source: mainline/uspace/srv/hid/display/clonegc.c@ 2ab8ab3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2ab8ab3 was 5271e4c, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Duplicate rendering to additional output devices using a cloning GC

This gives the display server a pretty good illusion of rendering to just
one output device, while supporting multiple. This makes RFB work properly.

  • Property mode set to 100644
File size: 12.8 KB
Line 
1/*
2 * Copyright (c) 2020 Jiri Svoboda
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
46static errno_t ds_clonegc_set_color(void *, gfx_color_t *);
47static errno_t ds_clonegc_fill_rect(void *, gfx_rect_t *);
48static errno_t ds_clonegc_bitmap_create(void *, gfx_bitmap_params_t *,
49 gfx_bitmap_alloc_t *, void **);
50static errno_t ds_clonegc_bitmap_destroy(void *);
51static errno_t ds_clonegc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
52static errno_t ds_clonegc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
53
54static ds_clonegc_output_t *ds_clonegc_first_output(ds_clonegc_t *);
55static ds_clonegc_output_t *ds_clonegc_next_output(ds_clonegc_output_t *);
56static ds_clonegc_bitmap_t *ds_clonegc_first_bitmap(ds_clonegc_t *);
57static ds_clonegc_bitmap_t *ds_clonegc_next_bitmap(ds_clonegc_bitmap_t *);
58static ds_clonegc_outbitmap_t *ds_clonegc_bitmap_first_obm(ds_clonegc_bitmap_t *);
59static ds_clonegc_outbitmap_t *ds_clonegc_bitmap_next_obm(ds_clonegc_outbitmap_t *);
60static errno_t ds_clonegc_outbitmap_create(ds_clonegc_output_t *,
61 ds_clonegc_bitmap_t *, gfx_bitmap_t *);
62static errno_t ds_clonegc_outbitmap_destroy(ds_clonegc_outbitmap_t *);
63static errno_t ds_clonegc_bitmap_add_output(ds_clonegc_bitmap_t *,
64 ds_clonegc_output_t *);
65
66gfx_context_ops_t ds_clonegc_ops = {
67 .set_color = ds_clonegc_set_color,
68 .fill_rect = ds_clonegc_fill_rect,
69 .bitmap_create = ds_clonegc_bitmap_create,
70 .bitmap_destroy = ds_clonegc_bitmap_destroy,
71 .bitmap_render = ds_clonegc_bitmap_render,
72 .bitmap_get_alloc = ds_clonegc_bitmap_get_alloc
73};
74
75/** Set color on clone GC.
76 *
77 * Set drawing color on memory GC.
78 *
79 * @param arg Clone GC
80 * @param color Color
81 *
82 * @return EOK on success or an error code
83 */
84static errno_t ds_clonegc_set_color(void *arg, gfx_color_t *color)
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_color(output->gc, color);
93 if (rc != EOK)
94 return rc;
95
96 output = ds_clonegc_next_output(output);
97 }
98
99 return EOK;
100}
101
102/** Fill rectangle on clone GC.
103 *
104 * @param arg Clone GC
105 * @param rect Rectangle
106 *
107 * @return EOK on success or an error code
108 */
109static errno_t ds_clonegc_fill_rect(void *arg, gfx_rect_t *rect)
110{
111 ds_clonegc_t *cgc = (ds_clonegc_t *)arg;
112 ds_clonegc_output_t *output;
113 errno_t rc;
114
115 output = ds_clonegc_first_output(cgc);
116 while (output != NULL) {
117 rc = gfx_fill_rect(output->gc, rect);
118 if (rc != EOK)
119 return rc;
120
121 output = ds_clonegc_next_output(output);
122 }
123
124 return EOK;
125}
126
127/** Create cloning GC.
128 *
129 * Create graphics context for copying rendering into several GCs.
130 *
131 * @param outgc Primary output GC
132 * @param rgc Place to store pointer to new clone GC
133 *
134 * @return EOK on success or an error code
135 */
136errno_t ds_clonegc_create(gfx_context_t *outgc, ds_clonegc_t **rgc)
137{
138 ds_clonegc_t *cgc = NULL;
139 gfx_context_t *gc = NULL;
140 errno_t rc;
141
142 cgc = calloc(1, sizeof(ds_clonegc_t));
143 if (cgc == NULL) {
144 rc = ENOMEM;
145 goto error;
146 }
147
148 rc = gfx_context_new(&ds_clonegc_ops, cgc, &gc);
149 if (rc != EOK)
150 goto error;
151
152 cgc->gc = gc;
153 list_initialize(&cgc->outputs);
154 list_initialize(&cgc->bitmaps);
155
156 if (outgc != NULL) {
157 rc = ds_clonegc_add_output(cgc, outgc);
158 if (rc != EOK)
159 goto error;
160 }
161
162 *rgc = cgc;
163 return EOK;
164error:
165 if (cgc != NULL)
166 free(cgc);
167 if (gc != NULL)
168 gfx_context_delete(gc);
169 return rc;
170}
171
172/** Delete cloning GC.
173 *
174 * @param cgc Cloning GC
175 */
176errno_t ds_clonegc_delete(ds_clonegc_t *cgc)
177{
178 errno_t rc;
179
180 rc = gfx_context_delete(cgc->gc);
181 if (rc != EOK)
182 return rc;
183
184 free(cgc);
185 return EOK;
186}
187
188/** Add new output to cloning GC.
189 *
190 * @param cgc Cloning GC
191 * @param outgc New output GC
192 * @return EOK on success, ENOMEM if out of memory
193 */
194errno_t ds_clonegc_add_output(ds_clonegc_t *cgc, gfx_context_t *outgc)
195{
196 ds_clonegc_output_t *output;
197 ds_clonegc_bitmap_t *cbm;
198 errno_t rc;
199
200 output = calloc(1, sizeof(ds_clonegc_output_t));
201 if (output == NULL)
202 return ENOMEM;
203
204 output->clonegc = cgc;
205 list_append(&output->loutputs, &cgc->outputs);
206 output->gc = outgc;
207 list_initialize(&output->obitmaps);
208
209 /* Extend each existing bitmap to the new output */
210 cbm = ds_clonegc_first_bitmap(cgc);
211 while (cbm != NULL) {
212 rc = ds_clonegc_bitmap_add_output(cbm, output);
213 if (rc != EOK)
214 goto error;
215
216 cbm = ds_clonegc_next_bitmap(cbm);
217 }
218
219 return EOK;
220error:
221 list_remove(&output->loutputs);
222 free(output);
223 return rc;
224}
225
226/** Get generic graphic context from clone GC.
227 *
228 * @param cgc Clone GC
229 * @return Graphic context
230 */
231gfx_context_t *ds_clonegc_get_ctx(ds_clonegc_t *cgc)
232{
233 return cgc->gc;
234}
235
236/** Create bitmap in clone GC.
237 *
238 * @param arg Clone GC
239 * @param params Bitmap params
240 * @param alloc Bitmap allocation info or @c NULL
241 * @param rbm Place to store pointer to new bitmap
242 * @return EOK on success or an error code
243 */
244errno_t ds_clonegc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
245 gfx_bitmap_alloc_t *alloc, void **rbm)
246{
247 ds_clonegc_t *cgc = (ds_clonegc_t *)arg;
248 ds_clonegc_bitmap_t *cbm = NULL;
249 ds_clonegc_output_t *output;
250 gfx_bitmap_t *bitmap;
251 errno_t rc;
252
253 cbm = calloc(1, sizeof(ds_clonegc_bitmap_t));
254 if (cbm == NULL)
255 return ENOMEM;
256
257 list_initialize(&cbm->obitmaps);
258 cbm->clonegc = cgc;
259 cbm->params = *params;
260
261 output = ds_clonegc_first_output(cgc);
262 assert(output != NULL);
263
264 /* Create the first output bitmap */
265
266 rc = gfx_bitmap_create(output->gc, params, alloc, &bitmap);
267 if (rc != EOK)
268 goto error;
269
270 rc = gfx_bitmap_get_alloc(bitmap, &cbm->alloc);
271 if (rc != EOK)
272 goto error;
273
274 rc = ds_clonegc_outbitmap_create(output, cbm, bitmap);
275 if (rc != EOK)
276 goto error;
277
278 bitmap = NULL;
279
280 /* Create all other output bitmaps as copies */
281 output = ds_clonegc_next_output(output);
282 while (output != NULL) {
283 rc = ds_clonegc_bitmap_add_output(cbm, output);
284 if (rc != EOK)
285 goto error;
286
287 output = ds_clonegc_next_output(output);
288 }
289
290 list_append(&cbm->lbitmaps, &cgc->bitmaps);
291 *rbm = (void *)cbm;
292 return EOK;
293error:
294 if (bitmap != NULL)
295 gfx_bitmap_destroy(bitmap);
296 if (cbm != NULL)
297 ds_clonegc_bitmap_destroy(cbm);
298 return rc;
299}
300
301/** Destroy bitmap in memory GC.
302 *
303 * @param bm Bitmap
304 * @return EOK on success or an error code
305 */
306static errno_t ds_clonegc_bitmap_destroy(void *bm)
307{
308 ds_clonegc_bitmap_t *cbm = (ds_clonegc_bitmap_t *)bm;
309 ds_clonegc_outbitmap_t *outbm;
310 errno_t rc;
311
312 outbm = ds_clonegc_bitmap_first_obm(cbm);
313 while (outbm != NULL) {
314 rc = ds_clonegc_outbitmap_destroy(outbm);
315 if (rc != EOK)
316 return rc;
317
318 outbm = ds_clonegc_bitmap_first_obm(cbm);
319 }
320
321 list_remove(&cbm->lbitmaps);
322 free(cbm);
323 return EOK;
324}
325
326/** Render bitmap in memory GC.
327 *
328 * @param bm Bitmap
329 * @param srect0 Source rectangle or @c NULL
330 * @param offs0 Offset or @c NULL
331 * @return EOK on success or an error code
332 */
333static errno_t ds_clonegc_bitmap_render(void *bm, gfx_rect_t *srect0,
334 gfx_coord2_t *offs0)
335{
336 ds_clonegc_bitmap_t *cbm = (ds_clonegc_bitmap_t *)bm;
337 ds_clonegc_outbitmap_t *outbm;
338 errno_t rc;
339
340 outbm = ds_clonegc_bitmap_first_obm(cbm);
341 while (outbm != NULL) {
342 rc = gfx_bitmap_render(outbm->obitmap, srect0, offs0);
343 if (rc != EOK)
344 return rc;
345
346 outbm = ds_clonegc_bitmap_next_obm(outbm);
347 }
348
349 return EOK;
350}
351
352/** Get allocation info for bitmap in memory GC.
353 *
354 * @param bm Bitmap
355 * @param alloc Place to store allocation info
356 * @return EOK on success or an error code
357 */
358static errno_t ds_clonegc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
359{
360 ds_clonegc_bitmap_t *cbm = (ds_clonegc_bitmap_t *)bm;
361
362 *alloc = cbm->alloc;
363 return EOK;
364}
365
366/** Get first clone GC output.
367 *
368 * @param cgc Clone GC
369 * @return First output or @c NULL if there are none
370 */
371static ds_clonegc_output_t *ds_clonegc_first_output(ds_clonegc_t *cgc)
372{
373 link_t *link;
374
375 link = list_first(&cgc->outputs);
376 if (link == NULL)
377 return NULL;
378
379 return list_get_instance(link, ds_clonegc_output_t, loutputs);
380}
381
382/** Get next clone GC output.
383 *
384 * @param cur Current output
385 * @return Next output or @c NULL if @a cur is the last
386 */
387static ds_clonegc_output_t *ds_clonegc_next_output(ds_clonegc_output_t *cur)
388{
389 link_t *link;
390
391 link = list_next(&cur->loutputs, &cur->clonegc->outputs);
392 if (link == NULL)
393 return NULL;
394
395 return list_get_instance(link, ds_clonegc_output_t, loutputs);
396}
397
398/** Get first clone GC bitmap.
399 *
400 * @param cgc Clone GC
401 * @return First bitmap or @c NULL if there are none
402 */
403static ds_clonegc_bitmap_t *ds_clonegc_first_bitmap(ds_clonegc_t *cgc)
404{
405 link_t *link;
406
407 link = list_first(&cgc->bitmaps);
408 if (link == NULL)
409 return NULL;
410
411 return list_get_instance(link, ds_clonegc_bitmap_t, lbitmaps);
412}
413
414/** Get next clone GC bitmap.
415 *
416 * @param cur Current bitmap
417 * @return Next bitmap or @c NULL if @a cur is the last
418 */
419static ds_clonegc_bitmap_t *ds_clonegc_next_bitmap(ds_clonegc_bitmap_t *cur)
420{
421 link_t *link;
422
423 link = list_next(&cur->lbitmaps, &cur->clonegc->bitmaps);
424 if (link == NULL)
425 return NULL;
426
427 return list_get_instance(link, ds_clonegc_bitmap_t, lbitmaps);
428}
429
430/** Get first output bitmap of a clone GC bitmap.
431 *
432 * @param cbm Clone GC bitmap
433 * @return First output bitmap or @c NULL if there are none
434 */
435static ds_clonegc_outbitmap_t *ds_clonegc_bitmap_first_obm(ds_clonegc_bitmap_t *cbm)
436{
437 link_t *link;
438
439 link = list_first(&cbm->obitmaps);
440 if (link == NULL)
441 return NULL;
442
443 return list_get_instance(link, ds_clonegc_outbitmap_t, lbbitmaps);
444}
445
446/** Get next output bitmap of a clone GC bitmap.
447 *
448 * @param cur Current output bitmap
449 * @return Next output bitmap or @c NULL if @a cur is the last
450 */
451static ds_clonegc_outbitmap_t *ds_clonegc_bitmap_next_obm(ds_clonegc_outbitmap_t *cur)
452{
453 link_t *link;
454
455 link = list_next(&cur->lbbitmaps, &cur->bitmap->obitmaps);
456 if (link == NULL)
457 return NULL;
458
459 return list_get_instance(link, ds_clonegc_outbitmap_t, lbbitmaps);
460}
461
462/** Create clone GC output bitmap.
463 *
464 * Create a new entry in the output x bitmap matrix.
465 *
466 * @param output Clone GC output
467 * @param cbm Clone GC bitmap
468 * @param obitmap Output bitmap
469 */
470static errno_t ds_clonegc_outbitmap_create(ds_clonegc_output_t *output,
471 ds_clonegc_bitmap_t *cbm, gfx_bitmap_t *obitmap)
472{
473 ds_clonegc_outbitmap_t *outbm;
474
475 outbm = calloc(1, sizeof(ds_clonegc_outbitmap_t));
476 if (outbm == NULL)
477 return ENOMEM;
478
479 outbm->output = output;
480 outbm->bitmap = cbm;
481 list_append(&outbm->lobitmaps, &output->obitmaps);
482 list_append(&outbm->lbbitmaps, &cbm->obitmaps);
483 outbm->obitmap = obitmap;
484
485 return EOK;
486}
487
488/** Destroy clone GC output bitmap.
489 *
490 * @param outbm Output bitmap
491 * @return EOK on success or an error code
492 */
493static errno_t ds_clonegc_outbitmap_destroy(ds_clonegc_outbitmap_t *outbm)
494{
495 errno_t rc;
496
497 rc = gfx_bitmap_destroy(outbm->obitmap);
498 if (rc != EOK)
499 return rc;
500
501 list_remove(&outbm->lobitmaps);
502 list_remove(&outbm->lbbitmaps);
503 free(outbm);
504 return EOK;
505}
506
507/** Extend clone GC bitmap to new output.
508 *
509 * @param cbm Clone GC bitmap
510 * @param output Clone GC output
511 */
512static errno_t ds_clonegc_bitmap_add_output(ds_clonegc_bitmap_t *cbm,
513 ds_clonegc_output_t *output)
514{
515 gfx_bitmap_t *obitmap = NULL;
516 errno_t rc;
517
518 rc = gfx_bitmap_create(output->gc, &cbm->params, &cbm->alloc, &obitmap);
519 if (rc != EOK)
520 goto error;
521
522 rc = ds_clonegc_outbitmap_create(output, cbm, obitmap);
523 if (rc != EOK)
524 goto error;
525
526 return EOK;
527error:
528 if (obitmap != NULL)
529 gfx_bitmap_destroy(obitmap);
530 return rc;
531}
532
533/** @}
534 */
Note: See TracBrowser for help on using the repository browser.