source: mainline/uspace/srv/hid/rfb/main.c@ 46a47c0

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 46a47c0 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: 12.3 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * Copyright (c) 2013 Martin Sucha
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <ddev/info.h>
31#include <ddev_srv.h>
32#include <errno.h>
33#include <fibril_synch.h>
34#include <gfx/color.h>
35#include <gfx/context.h>
36#include <gfx/coord.h>
37#include <inttypes.h>
38#include <io/log.h>
39#include <io/pixelmap.h>
40#include <ipcgfx/server.h>
41#include <loc.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <task.h>
45
46#include "rfb.h"
47
48#define NAME "rfb"
49
50static errno_t rfb_ddev_get_gc(void *, sysarg_t *, sysarg_t *);
51static errno_t rfb_ddev_get_info(void *, ddev_info_t *);
52
53static errno_t rfb_gc_set_clip_rect(void *, gfx_rect_t *);
54static errno_t rfb_gc_set_color(void *, gfx_color_t *);
55static errno_t rfb_gc_fill_rect(void *, gfx_rect_t *);
56static errno_t rfb_gc_bitmap_create(void *, gfx_bitmap_params_t *,
57 gfx_bitmap_alloc_t *, void **);
58static errno_t rfb_gc_bitmap_destroy(void *);
59static errno_t rfb_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
60static errno_t rfb_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
61
62static ddev_ops_t rfb_ddev_ops = {
63 .get_gc = rfb_ddev_get_gc,
64 .get_info = rfb_ddev_get_info
65};
66
67typedef struct {
68 rfb_t rfb;
69 pixel_t color;
70 gfx_rect_t rect;
71 gfx_rect_t clip_rect;
72} rfb_gc_t;
73
74typedef struct {
75 rfb_gc_t *rfb;
76 gfx_bitmap_alloc_t alloc;
77 gfx_rect_t rect;
78 gfx_bitmap_flags_t flags;
79 pixel_t key_color;
80 bool myalloc;
81} rfb_bitmap_t;
82
83static gfx_context_ops_t rfb_gc_ops = {
84 .set_clip_rect = rfb_gc_set_clip_rect,
85 .set_color = rfb_gc_set_color,
86 .fill_rect = rfb_gc_fill_rect,
87 .bitmap_create = rfb_gc_bitmap_create,
88 .bitmap_destroy = rfb_gc_bitmap_destroy,
89 .bitmap_render = rfb_gc_bitmap_render,
90 .bitmap_get_alloc = rfb_gc_bitmap_get_alloc
91};
92
93static void rfb_gc_invalidate_rect(rfb_gc_t *rfbgc, gfx_rect_t *rect)
94{
95 rfb_t *rfb = &rfbgc->rfb;
96 gfx_rect_t old_rect;
97 gfx_rect_t new_rect;
98
99 if (gfx_rect_is_empty(rect))
100 return;
101
102 if (!rfb->damage_valid) {
103 old_rect.p0.x = old_rect.p0.y = 0;
104 old_rect.p1.x = old_rect.p1.y = 0;
105 } else {
106 old_rect.p0.x = rfb->damage_rect.x;
107 old_rect.p0.y = rfb->damage_rect.y;
108 old_rect.p1.x = rfb->damage_rect.x + rfb->damage_rect.width;
109 old_rect.p1.y = rfb->damage_rect.y + rfb->damage_rect.height;
110 }
111
112 gfx_rect_envelope(&old_rect, rect, &new_rect);
113
114 rfb->damage_rect.x = new_rect.p0.x;
115 rfb->damage_rect.y = new_rect.p0.y;
116 rfb->damage_rect.width = new_rect.p1.x - new_rect.p0.x;
117 rfb->damage_rect.height = new_rect.p1.y - new_rect.p0.y;
118}
119
120static errno_t rfb_ddev_get_gc(void *arg, sysarg_t *arg2, sysarg_t *arg3)
121{
122 *arg2 = 0;
123 *arg3 = 42;
124 return EOK;
125}
126
127static errno_t rfb_ddev_get_info(void *arg, ddev_info_t *info)
128{
129 rfb_t *rfb = (rfb_t *) arg;
130
131 ddev_info_init(info);
132
133 info->rect.p0.x = 0;
134 info->rect.p0.y = 0;
135 info->rect.p1.x = rfb->width;
136 info->rect.p1.y = rfb->height;
137
138 return EOK;
139}
140
141/** Create RFB GC.
142 *
143 * @param rrgb Place to store pointer to new RFB GC
144 * @return EOK on success, ENOMEM if out of memory
145 */
146static errno_t rgb_gc_create(rfb_gc_t **rrfb)
147{
148 rfb_gc_t *rfb;
149
150 rfb = calloc(1, sizeof(rfb_gc_t));
151 if (rfb == NULL)
152 return ENOMEM;
153
154 *rrfb = rfb;
155 return EOK;
156}
157
158/** Destroy RFB GC.
159 *
160 * @param rfb RFB GC
161 */
162static void rfb_gc_destroy(rfb_gc_t *rfb)
163{
164 free(rfb);
165}
166
167/** Set clipping rectangle on RFB.
168 *
169 * @param arg RFB
170 * @param rect Rectangle or @c NULL
171 *
172 * @return EOK on success or an error code
173 */
174static errno_t rfb_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
175{
176 rfb_gc_t *rfb = (rfb_gc_t *) arg;
177
178 if (rect != NULL)
179 gfx_rect_clip(rect, &rfb->rect, &rfb->clip_rect);
180 else
181 rfb->clip_rect = rfb->rect;
182
183 return EOK;
184}
185
186/** Set color on RFB.
187 *
188 * Set drawing color on RFB GC.
189 *
190 * @param arg RFB
191 * @param color Color
192 *
193 * @return EOK on success or an error code
194 */
195static errno_t rfb_gc_set_color(void *arg, gfx_color_t *color)
196{
197 rfb_gc_t *rfb = (rfb_gc_t *) arg;
198 uint16_t r, g, b;
199
200 gfx_color_get_rgb_i16(color, &r, &g, &b);
201 rfb->color = PIXEL(0, r >> 8, g >> 8, b >> 8);
202 return EOK;
203}
204
205/** Fill rectangle on RFB.
206 *
207 * @param arg RFB
208 * @param rect Rectangle
209 *
210 * @return EOK on success or an error code
211 */
212static errno_t rfb_gc_fill_rect(void *arg, gfx_rect_t *rect)
213{
214 rfb_gc_t *rfb = (rfb_gc_t *) arg;
215 gfx_rect_t crect;
216 gfx_coord_t x, y;
217
218 gfx_rect_clip(rect, &rfb->clip_rect, &crect);
219
220 for (y = crect.p0.y; y < crect.p1.y; y++) {
221 for (x = crect.p0.x; x < crect.p1.x; x++) {
222 pixelmap_put_pixel(&rfb->rfb.framebuffer, x, y,
223 rfb->color);
224 }
225 }
226
227 rfb_gc_invalidate_rect(rfb, &crect);
228
229 return EOK;
230}
231
232/** Create bitmap in RFB GC.
233 *
234 * @param arg RFB
235 * @param params Bitmap params
236 * @param alloc Bitmap allocation info or @c NULL
237 * @param rbm Place to store pointer to new bitmap
238 * @return EOK on success or an error code
239 */
240errno_t rfb_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
241 gfx_bitmap_alloc_t *alloc, void **rbm)
242{
243 rfb_gc_t *rfb = (rfb_gc_t *) arg;
244 rfb_bitmap_t *rfbbm = NULL;
245 gfx_coord2_t dim;
246 errno_t rc;
247
248 /* Check that we support all required flags */
249 if ((params->flags & ~(bmpf_color_key | bmpf_colorize)) != 0)
250 return ENOTSUP;
251
252 rfbbm = calloc(1, sizeof(rfb_bitmap_t));
253 if (rfbbm == NULL)
254 return ENOMEM;
255
256 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
257 rfbbm->rect = params->rect;
258 rfbbm->flags = params->flags;
259 rfbbm->key_color = params->key_color;
260
261 if (alloc == NULL) {
262 rfbbm->alloc.pitch = dim.x * sizeof(uint32_t);
263 rfbbm->alloc.off0 = 0;
264 rfbbm->alloc.pixels = malloc(rfbbm->alloc.pitch * dim.y);
265 rfbbm->myalloc = true;
266
267 if (rfbbm->alloc.pixels == NULL) {
268 rc = ENOMEM;
269 goto error;
270 }
271 } else {
272 rfbbm->alloc = *alloc;
273 }
274
275 rfbbm->rfb = rfb;
276 *rbm = (void *)rfbbm;
277 return EOK;
278error:
279 if (rbm != NULL)
280 free(rfbbm);
281 return rc;
282}
283
284/** Destroy bitmap in RFB GC.
285 *
286 * @param bm Bitmap
287 * @return EOK on success or an error code
288 */
289static errno_t rfb_gc_bitmap_destroy(void *bm)
290{
291 rfb_bitmap_t *rfbbm = (rfb_bitmap_t *)bm;
292 if (rfbbm->myalloc)
293 free(rfbbm->alloc.pixels);
294 free(rfbbm);
295 return EOK;
296}
297
298/** Render bitmap in RFB GC.
299 *
300 * @param bm Bitmap
301 * @param srect0 Source rectangle or @c NULL
302 * @param offs0 Offset or @c NULL
303 * @return EOK on success or an error code
304 */
305static errno_t rfb_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
306 gfx_coord2_t *offs0)
307{
308 rfb_bitmap_t *rfbbm = (rfb_bitmap_t *)bm;
309 gfx_rect_t srect;
310 gfx_rect_t drect;
311 gfx_rect_t crect;
312 gfx_coord2_t offs;
313 gfx_coord2_t bmdim;
314 gfx_coord2_t dim;
315 gfx_coord_t x, y;
316 pixelmap_t pbm;
317 pixel_t color;
318
319 if (srect0 != NULL)
320 srect = *srect0;
321 else
322 srect = rfbbm->rect;
323
324 if (offs0 != NULL) {
325 offs = *offs0;
326 } else {
327 offs.x = 0;
328 offs.y = 0;
329 }
330
331 /* Destination rectangle */
332 gfx_rect_translate(&offs, &srect, &drect);
333 gfx_rect_clip(&drect, &rfbbm->rfb->clip_rect, &crect);
334 gfx_coord2_subtract(&crect.p1, &crect.p0, &dim);
335 gfx_coord2_subtract(&rfbbm->rect.p1, &rfbbm->rect.p0, &bmdim);
336
337 pbm.width = bmdim.x;
338 pbm.height = bmdim.y;
339 pbm.data = rfbbm->alloc.pixels;
340
341 if ((rfbbm->flags & bmpf_color_key) == 0) {
342 /* Simple copy */
343 for (y = srect.p0.y; y < srect.p1.y; y++) {
344 for (x = srect.p0.x; x < srect.p1.x; x++) {
345 color = pixelmap_get_pixel(&pbm, x, y);
346 pixelmap_put_pixel(&rfbbm->rfb->rfb.framebuffer,
347 x + offs.x, y + offs.y, color);
348 }
349 }
350 } else if ((rfbbm->flags & bmpf_colorize) == 0) {
351 /* Color key */
352 for (y = srect.p0.y; y < srect.p1.y; y++) {
353 for (x = srect.p0.x; x < srect.p1.x; x++) {
354 color = pixelmap_get_pixel(&pbm, x, y);
355 if (color != rfbbm->key_color) {
356 pixelmap_put_pixel(&rfbbm->rfb->rfb.framebuffer,
357 x + offs.x, y + offs.y, color);
358 }
359 }
360 }
361 } else {
362 /* Color key & colorization */
363 for (y = srect.p0.y; y < srect.p1.y; y++) {
364 for (x = srect.p0.x; x < srect.p1.x; x++) {
365 color = pixelmap_get_pixel(&pbm, x, y);
366 if (color != rfbbm->key_color) {
367 pixelmap_put_pixel(&rfbbm->rfb->rfb.framebuffer,
368 x + offs.x, y + offs.y,
369 rfbbm->rfb->color);
370 }
371 }
372 }
373 }
374
375 rfb_gc_invalidate_rect(rfbbm->rfb, &crect);
376
377 return EOK;
378}
379
380/** Get allocation info for bitmap in RFB GC.
381 *
382 * @param bm Bitmap
383 * @param alloc Place to store allocation info
384 * @return EOK on success or an error code
385 */
386static errno_t rfb_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
387{
388 rfb_bitmap_t *rfbbm = (rfb_bitmap_t *)bm;
389 *alloc = rfbbm->alloc;
390 return EOK;
391}
392
393static void syntax_print(void)
394{
395 fprintf(stderr, "Usage: %s <name> <width> <height> [port]\n", NAME);
396}
397
398static void client_connection(ipc_call_t *icall, void *arg)
399{
400 rfb_t *rfb = (rfb_t *) arg;
401 rfb_gc_t *rfbgc;
402 ddev_srv_t srv;
403 sysarg_t svc_id;
404 gfx_context_t *gc;
405 errno_t rc;
406
407 svc_id = ipc_get_arg2(icall);
408
409 if (svc_id != 0) {
410 /* Set up protocol structure */
411 ddev_srv_initialize(&srv);
412 srv.ops = &rfb_ddev_ops;
413 srv.arg = (void *) rfb;
414
415 /* Handle connection */
416 ddev_conn(icall, &srv);
417 } else {
418 rc = rgb_gc_create(&rfbgc);
419 if (rc != EOK) {
420 async_answer_0(icall, ENOMEM);
421 return;
422 }
423
424 rfbgc->rect.p0.x = 0;
425 rfbgc->rect.p0.y = 0;
426 rfbgc->rect.p1.x = rfb->width;
427 rfbgc->rect.p1.y = rfb->height;
428 rfbgc->clip_rect = rfbgc->rect;
429
430 rc = gfx_context_new(&rfb_gc_ops, (void *) rfbgc, &gc);
431 if (rc != EOK) {
432 rfb_gc_destroy(rfbgc);
433 async_answer_0(icall, ENOMEM);
434 return;
435 }
436
437 /* GC connection */
438 gc_conn(icall, gc);
439 }
440}
441
442int main(int argc, char **argv)
443{
444 rfb_t rfb;
445
446 log_init(NAME);
447
448 if (argc <= 3) {
449 syntax_print();
450 return 1;
451 }
452
453 const char *rfb_name = argv[1];
454
455 char *endptr;
456 unsigned long width = strtoul(argv[2], &endptr, 0);
457 if (*endptr != 0) {
458 fprintf(stderr, "Invalid width\n");
459 syntax_print();
460 return 1;
461 }
462
463 unsigned long height = strtoul(argv[3], &endptr, 0);
464 if (*endptr != 0) {
465 fprintf(stderr, "Invalid height\n");
466 syntax_print();
467 return 1;
468 }
469
470 unsigned long port = 5900;
471 if (argc > 4) {
472 port = strtoul(argv[4], &endptr, 0);
473 if (*endptr != 0) {
474 fprintf(stderr, "Invalid port number\n");
475 syntax_print();
476 return 1;
477 }
478 }
479
480 rfb_init(&rfb, width, height, rfb_name);
481
482 async_set_fallback_port_handler(client_connection, &rfb);
483
484 errno_t rc = loc_server_register(NAME);
485 if (rc != EOK) {
486 printf("%s: Unable to register server.\n", NAME);
487 return rc;
488 }
489
490 char *service_name;
491 rc = asprintf(&service_name, "rfb/%s", rfb_name);
492 if (rc < 0) {
493 printf(NAME ": Unable to create service name\n");
494 return rc;
495 }
496
497 service_id_t service_id;
498
499 rc = loc_service_register(service_name, &service_id);
500 if (rc != EOK) {
501 printf(NAME ": Unable to register service %s.\n", service_name);
502 return rc;
503 }
504
505 free(service_name);
506
507 category_id_t ddev_cid;
508 rc = loc_category_get_id("display-device", &ddev_cid, IPC_FLAG_BLOCKING);
509 if (rc != EOK) {
510 fprintf(stderr, NAME ": Unable to get display device category id.\n");
511 return 1;
512 }
513
514 rc = loc_service_add_to_cat(service_id, ddev_cid);
515 if (rc != EOK) {
516 fprintf(stderr, NAME ": Unable to add service to display device category.\n");
517 return 1;
518 }
519
520 rc = rfb_listen(&rfb, port);
521 if (rc != EOK) {
522 fprintf(stderr, NAME ": Unable to listen at rfb port\n");
523 return 2;
524 }
525
526 printf("%s: Accepting connections\n", NAME);
527 task_retval(0);
528 async_manager();
529
530 /* Not reached */
531 return 0;
532}
Note: See TracBrowser for help on using the repository browser.