source: mainline/uspace/srv/hid/display/clonegc.c

Last change on this file was 7470d97, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Add GC operation to set clipping rectangle

The number of changed files is due to the proliferation of GC
implementations, mostly these are just dummies in unit tests.
Definitely need to tame those in the future.

  • Property mode set to 100644
File size: 13.3 KB
RevLine 
[5271e4c]1/*
[7470d97]2 * Copyright (c) 2021 Jiri Svoboda
[5271e4c]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup display
30 * @{
31 */
32/**
33 * @file Cloning graphics context
34 *
35 * This implements a graphics context that duplicates rendering to a number
36 * of GCs.
37 */
38
39#include <assert.h>
40#include <gfx/color.h>
41#include <gfx/context.h>
42#include <gfx/render.h>
43#include <stdlib.h>
44#include "clonegc.h"
45
[7470d97]46static errno_t ds_clonegc_set_clip_rect(void *, gfx_rect_t *);
[5271e4c]47static errno_t ds_clonegc_set_color(void *, gfx_color_t *);
48static errno_t ds_clonegc_fill_rect(void *, gfx_rect_t *);
49static errno_t ds_clonegc_bitmap_create(void *, gfx_bitmap_params_t *,
50 gfx_bitmap_alloc_t *, void **);
51static errno_t ds_clonegc_bitmap_destroy(void *);
52static errno_t ds_clonegc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
53static errno_t ds_clonegc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
54
55static ds_clonegc_output_t *ds_clonegc_first_output(ds_clonegc_t *);
56static ds_clonegc_output_t *ds_clonegc_next_output(ds_clonegc_output_t *);
57static ds_clonegc_bitmap_t *ds_clonegc_first_bitmap(ds_clonegc_t *);
58static ds_clonegc_bitmap_t *ds_clonegc_next_bitmap(ds_clonegc_bitmap_t *);
59static ds_clonegc_outbitmap_t *ds_clonegc_bitmap_first_obm(ds_clonegc_bitmap_t *);
60static ds_clonegc_outbitmap_t *ds_clonegc_bitmap_next_obm(ds_clonegc_outbitmap_t *);
61static errno_t ds_clonegc_outbitmap_create(ds_clonegc_output_t *,
62 ds_clonegc_bitmap_t *, gfx_bitmap_t *);
63static errno_t ds_clonegc_outbitmap_destroy(ds_clonegc_outbitmap_t *);
64static errno_t ds_clonegc_bitmap_add_output(ds_clonegc_bitmap_t *,
65 ds_clonegc_output_t *);
66
67gfx_context_ops_t ds_clonegc_ops = {
[7470d97]68 .set_clip_rect = ds_clonegc_set_clip_rect,
[5271e4c]69 .set_color = ds_clonegc_set_color,
70 .fill_rect = ds_clonegc_fill_rect,
71 .bitmap_create = ds_clonegc_bitmap_create,
72 .bitmap_destroy = ds_clonegc_bitmap_destroy,
73 .bitmap_render = ds_clonegc_bitmap_render,
74 .bitmap_get_alloc = ds_clonegc_bitmap_get_alloc
75};
76
[7470d97]77/** Set clipping rectangle on clone GC.
78 *
79 * @param arg Clone GC
80 * @param rect Rectangle
81 *
82 * @return EOK on success or an error code
83 */
84static errno_t ds_clonegc_set_clip_rect(void *arg, gfx_rect_t *rect)
85{
86 ds_clonegc_t *cgc = (ds_clonegc_t *)arg;
87 ds_clonegc_output_t *output;
88 errno_t rc;
89
90 output = ds_clonegc_first_output(cgc);
91 while (output != NULL) {
92 rc = gfx_set_clip_rect(output->gc, rect);
93 if (rc != EOK)
94 return rc;
95
96 output = ds_clonegc_next_output(output);
97 }
98
99 return EOK;
100}
101
[5271e4c]102/** Set color on clone GC.
103 *
104 * Set drawing color on memory GC.
105 *
106 * @param arg Clone GC
107 * @param color Color
108 *
109 * @return EOK on success or an error code
110 */
111static errno_t ds_clonegc_set_color(void *arg, gfx_color_t *color)
112{
113 ds_clonegc_t *cgc = (ds_clonegc_t *)arg;
114 ds_clonegc_output_t *output;
115 errno_t rc;
116
117 output = ds_clonegc_first_output(cgc);
118 while (output != NULL) {
119 rc = gfx_set_color(output->gc, color);
120 if (rc != EOK)
121 return rc;
122
123 output = ds_clonegc_next_output(output);
124 }
125
126 return EOK;
127}
128
129/** Fill rectangle on clone GC.
130 *
131 * @param arg Clone GC
132 * @param rect Rectangle
133 *
134 * @return EOK on success or an error code
135 */
136static errno_t ds_clonegc_fill_rect(void *arg, gfx_rect_t *rect)
137{
138 ds_clonegc_t *cgc = (ds_clonegc_t *)arg;
139 ds_clonegc_output_t *output;
140 errno_t rc;
141
142 output = ds_clonegc_first_output(cgc);
143 while (output != NULL) {
144 rc = gfx_fill_rect(output->gc, rect);
145 if (rc != EOK)
146 return rc;
147
148 output = ds_clonegc_next_output(output);
149 }
150
151 return EOK;
152}
153
154/** Create cloning GC.
155 *
156 * Create graphics context for copying rendering into several GCs.
157 *
158 * @param outgc Primary output GC
159 * @param rgc Place to store pointer to new clone GC
160 *
161 * @return EOK on success or an error code
162 */
163errno_t ds_clonegc_create(gfx_context_t *outgc, ds_clonegc_t **rgc)
164{
165 ds_clonegc_t *cgc = NULL;
166 gfx_context_t *gc = NULL;
167 errno_t rc;
168
169 cgc = calloc(1, sizeof(ds_clonegc_t));
170 if (cgc == NULL) {
171 rc = ENOMEM;
172 goto error;
173 }
174
175 rc = gfx_context_new(&ds_clonegc_ops, cgc, &gc);
176 if (rc != EOK)
177 goto error;
178
179 cgc->gc = gc;
180 list_initialize(&cgc->outputs);
181 list_initialize(&cgc->bitmaps);
182
183 if (outgc != NULL) {
184 rc = ds_clonegc_add_output(cgc, outgc);
185 if (rc != EOK)
186 goto error;
187 }
188
189 *rgc = cgc;
190 return EOK;
191error:
192 if (cgc != NULL)
193 free(cgc);
194 if (gc != NULL)
195 gfx_context_delete(gc);
196 return rc;
197}
198
199/** Delete cloning GC.
200 *
201 * @param cgc Cloning GC
202 */
203errno_t ds_clonegc_delete(ds_clonegc_t *cgc)
204{
205 errno_t rc;
206
207 rc = gfx_context_delete(cgc->gc);
208 if (rc != EOK)
209 return rc;
210
211 free(cgc);
212 return EOK;
213}
214
215/** Add new output to cloning GC.
216 *
217 * @param cgc Cloning GC
218 * @param outgc New output GC
219 * @return EOK on success, ENOMEM if out of memory
220 */
221errno_t ds_clonegc_add_output(ds_clonegc_t *cgc, gfx_context_t *outgc)
222{
223 ds_clonegc_output_t *output;
224 ds_clonegc_bitmap_t *cbm;
225 errno_t rc;
226
227 output = calloc(1, sizeof(ds_clonegc_output_t));
228 if (output == NULL)
229 return ENOMEM;
230
231 output->clonegc = cgc;
232 list_append(&output->loutputs, &cgc->outputs);
233 output->gc = outgc;
234 list_initialize(&output->obitmaps);
235
236 /* Extend each existing bitmap to the new output */
237 cbm = ds_clonegc_first_bitmap(cgc);
238 while (cbm != NULL) {
239 rc = ds_clonegc_bitmap_add_output(cbm, output);
240 if (rc != EOK)
241 goto error;
242
243 cbm = ds_clonegc_next_bitmap(cbm);
244 }
245
246 return EOK;
247error:
248 list_remove(&output->loutputs);
249 free(output);
250 return rc;
251}
252
253/** Get generic graphic context from clone GC.
254 *
255 * @param cgc Clone GC
256 * @return Graphic context
257 */
258gfx_context_t *ds_clonegc_get_ctx(ds_clonegc_t *cgc)
259{
260 return cgc->gc;
261}
262
263/** Create bitmap in clone GC.
264 *
265 * @param arg Clone GC
266 * @param params Bitmap params
267 * @param alloc Bitmap allocation info or @c NULL
268 * @param rbm Place to store pointer to new bitmap
269 * @return EOK on success or an error code
270 */
271errno_t ds_clonegc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
272 gfx_bitmap_alloc_t *alloc, void **rbm)
273{
274 ds_clonegc_t *cgc = (ds_clonegc_t *)arg;
275 ds_clonegc_bitmap_t *cbm = NULL;
276 ds_clonegc_output_t *output;
277 gfx_bitmap_t *bitmap;
278 errno_t rc;
279
280 cbm = calloc(1, sizeof(ds_clonegc_bitmap_t));
281 if (cbm == NULL)
282 return ENOMEM;
283
284 list_initialize(&cbm->obitmaps);
285 cbm->clonegc = cgc;
286 cbm->params = *params;
287
288 output = ds_clonegc_first_output(cgc);
289 assert(output != NULL);
290
291 /* Create the first output bitmap */
292
293 rc = gfx_bitmap_create(output->gc, params, alloc, &bitmap);
294 if (rc != EOK)
295 goto error;
296
297 rc = gfx_bitmap_get_alloc(bitmap, &cbm->alloc);
298 if (rc != EOK)
299 goto error;
300
301 rc = ds_clonegc_outbitmap_create(output, cbm, bitmap);
302 if (rc != EOK)
303 goto error;
304
305 bitmap = NULL;
306
307 /* Create all other output bitmaps as copies */
308 output = ds_clonegc_next_output(output);
309 while (output != NULL) {
310 rc = ds_clonegc_bitmap_add_output(cbm, output);
311 if (rc != EOK)
312 goto error;
313
314 output = ds_clonegc_next_output(output);
315 }
316
317 list_append(&cbm->lbitmaps, &cgc->bitmaps);
318 *rbm = (void *)cbm;
319 return EOK;
320error:
321 if (bitmap != NULL)
322 gfx_bitmap_destroy(bitmap);
323 if (cbm != NULL)
324 ds_clonegc_bitmap_destroy(cbm);
325 return rc;
326}
327
328/** Destroy bitmap in memory GC.
329 *
330 * @param bm Bitmap
331 * @return EOK on success or an error code
332 */
333static errno_t ds_clonegc_bitmap_destroy(void *bm)
334{
335 ds_clonegc_bitmap_t *cbm = (ds_clonegc_bitmap_t *)bm;
336 ds_clonegc_outbitmap_t *outbm;
337 errno_t rc;
338
339 outbm = ds_clonegc_bitmap_first_obm(cbm);
340 while (outbm != NULL) {
341 rc = ds_clonegc_outbitmap_destroy(outbm);
342 if (rc != EOK)
343 return rc;
344
345 outbm = ds_clonegc_bitmap_first_obm(cbm);
346 }
347
348 list_remove(&cbm->lbitmaps);
349 free(cbm);
350 return EOK;
351}
352
353/** Render bitmap in memory GC.
354 *
355 * @param bm Bitmap
356 * @param srect0 Source rectangle or @c NULL
357 * @param offs0 Offset or @c NULL
358 * @return EOK on success or an error code
359 */
360static errno_t ds_clonegc_bitmap_render(void *bm, gfx_rect_t *srect0,
361 gfx_coord2_t *offs0)
362{
363 ds_clonegc_bitmap_t *cbm = (ds_clonegc_bitmap_t *)bm;
364 ds_clonegc_outbitmap_t *outbm;
365 errno_t rc;
366
367 outbm = ds_clonegc_bitmap_first_obm(cbm);
368 while (outbm != NULL) {
369 rc = gfx_bitmap_render(outbm->obitmap, srect0, offs0);
370 if (rc != EOK)
371 return rc;
372
373 outbm = ds_clonegc_bitmap_next_obm(outbm);
374 }
375
376 return EOK;
377}
378
379/** Get allocation info for bitmap in memory GC.
380 *
381 * @param bm Bitmap
382 * @param alloc Place to store allocation info
383 * @return EOK on success or an error code
384 */
385static errno_t ds_clonegc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
386{
387 ds_clonegc_bitmap_t *cbm = (ds_clonegc_bitmap_t *)bm;
388
389 *alloc = cbm->alloc;
390 return EOK;
391}
392
393/** Get first clone GC output.
394 *
395 * @param cgc Clone GC
396 * @return First output or @c NULL if there are none
397 */
398static ds_clonegc_output_t *ds_clonegc_first_output(ds_clonegc_t *cgc)
399{
400 link_t *link;
401
402 link = list_first(&cgc->outputs);
403 if (link == NULL)
404 return NULL;
405
406 return list_get_instance(link, ds_clonegc_output_t, loutputs);
407}
408
409/** Get next clone GC output.
410 *
411 * @param cur Current output
412 * @return Next output or @c NULL if @a cur is the last
413 */
414static ds_clonegc_output_t *ds_clonegc_next_output(ds_clonegc_output_t *cur)
415{
416 link_t *link;
417
418 link = list_next(&cur->loutputs, &cur->clonegc->outputs);
419 if (link == NULL)
420 return NULL;
421
422 return list_get_instance(link, ds_clonegc_output_t, loutputs);
423}
424
425/** Get first clone GC bitmap.
426 *
427 * @param cgc Clone GC
428 * @return First bitmap or @c NULL if there are none
429 */
430static ds_clonegc_bitmap_t *ds_clonegc_first_bitmap(ds_clonegc_t *cgc)
431{
432 link_t *link;
433
434 link = list_first(&cgc->bitmaps);
435 if (link == NULL)
436 return NULL;
437
438 return list_get_instance(link, ds_clonegc_bitmap_t, lbitmaps);
439}
440
441/** Get next clone GC bitmap.
442 *
443 * @param cur Current bitmap
444 * @return Next bitmap or @c NULL if @a cur is the last
445 */
446static ds_clonegc_bitmap_t *ds_clonegc_next_bitmap(ds_clonegc_bitmap_t *cur)
447{
448 link_t *link;
449
450 link = list_next(&cur->lbitmaps, &cur->clonegc->bitmaps);
451 if (link == NULL)
452 return NULL;
453
454 return list_get_instance(link, ds_clonegc_bitmap_t, lbitmaps);
455}
456
457/** Get first output bitmap of a clone GC bitmap.
458 *
459 * @param cbm Clone GC bitmap
460 * @return First output bitmap or @c NULL if there are none
461 */
462static ds_clonegc_outbitmap_t *ds_clonegc_bitmap_first_obm(ds_clonegc_bitmap_t *cbm)
463{
464 link_t *link;
465
466 link = list_first(&cbm->obitmaps);
467 if (link == NULL)
468 return NULL;
469
470 return list_get_instance(link, ds_clonegc_outbitmap_t, lbbitmaps);
471}
472
473/** Get next output bitmap of a clone GC bitmap.
474 *
475 * @param cur Current output bitmap
476 * @return Next output bitmap or @c NULL if @a cur is the last
477 */
478static ds_clonegc_outbitmap_t *ds_clonegc_bitmap_next_obm(ds_clonegc_outbitmap_t *cur)
479{
480 link_t *link;
481
482 link = list_next(&cur->lbbitmaps, &cur->bitmap->obitmaps);
483 if (link == NULL)
484 return NULL;
485
486 return list_get_instance(link, ds_clonegc_outbitmap_t, lbbitmaps);
487}
488
489/** Create clone GC output bitmap.
490 *
491 * Create a new entry in the output x bitmap matrix.
492 *
493 * @param output Clone GC output
494 * @param cbm Clone GC bitmap
495 * @param obitmap Output bitmap
496 */
497static errno_t ds_clonegc_outbitmap_create(ds_clonegc_output_t *output,
498 ds_clonegc_bitmap_t *cbm, gfx_bitmap_t *obitmap)
499{
500 ds_clonegc_outbitmap_t *outbm;
501
502 outbm = calloc(1, sizeof(ds_clonegc_outbitmap_t));
503 if (outbm == NULL)
504 return ENOMEM;
505
506 outbm->output = output;
507 outbm->bitmap = cbm;
508 list_append(&outbm->lobitmaps, &output->obitmaps);
509 list_append(&outbm->lbbitmaps, &cbm->obitmaps);
510 outbm->obitmap = obitmap;
511
512 return EOK;
513}
514
515/** Destroy clone GC output bitmap.
516 *
517 * @param outbm Output bitmap
518 * @return EOK on success or an error code
519 */
520static errno_t ds_clonegc_outbitmap_destroy(ds_clonegc_outbitmap_t *outbm)
521{
522 errno_t rc;
523
524 rc = gfx_bitmap_destroy(outbm->obitmap);
525 if (rc != EOK)
526 return rc;
527
528 list_remove(&outbm->lobitmaps);
529 list_remove(&outbm->lbbitmaps);
530 free(outbm);
531 return EOK;
532}
533
534/** Extend clone GC bitmap to new output.
535 *
536 * @param cbm Clone GC bitmap
537 * @param output Clone GC output
538 */
539static errno_t ds_clonegc_bitmap_add_output(ds_clonegc_bitmap_t *cbm,
540 ds_clonegc_output_t *output)
541{
542 gfx_bitmap_t *obitmap = NULL;
543 errno_t rc;
544
545 rc = gfx_bitmap_create(output->gc, &cbm->params, &cbm->alloc, &obitmap);
546 if (rc != EOK)
547 goto error;
548
549 rc = ds_clonegc_outbitmap_create(output, cbm, obitmap);
550 if (rc != EOK)
551 goto error;
552
553 return EOK;
554error:
555 if (obitmap != NULL)
556 gfx_bitmap_destroy(obitmap);
557 return rc;
558}
559
560/** @}
561 */
Note: See TracBrowser for help on using the repository browser.