source: mainline/uspace/drv/fb/kfb/port.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: 14.3 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * Copyright (c) 2006 Jakub Vana
4 * Copyright (c) 2006 Ondrej Palkovsky
5 * Copyright (c) 2008 Martin Decky
6 * Copyright (c) 2011 Petr Koupy
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * - The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/** @addtogroup kfb
34 * @{
35 */
36/**
37 * @file
38 */
39
40#include <abi/fb/visuals.h>
41#include <adt/list.h>
42#include <align.h>
43#include <as.h>
44#include <ddev_srv.h>
45#include <ddev/info.h>
46#include <ddi.h>
47#include <ddf/log.h>
48#include <errno.h>
49#include <gfx/bitmap.h>
50#include <gfx/color.h>
51#include <gfx/coord.h>
52#include <io/pixelmap.h>
53#include <ipcgfx/server.h>
54#include <mem.h>
55#include <pixconv.h>
56#include <stddef.h>
57#include <stdint.h>
58#include <stdlib.h>
59#include <sysinfo.h>
60
61#include "kfb.h"
62#include "port.h"
63
64#define FB_POS(fb, x, y) ((y) * (fb)->scanline + (x) * (fb)->pixel_bytes)
65
66typedef struct {
67 ddf_fun_t *fun;
68
69 sysarg_t paddr;
70 gfx_rect_t rect;
71 gfx_rect_t clip_rect;
72 size_t offset;
73 size_t scanline;
74 visual_t visual;
75
76 pixel2visual_t pixel2visual;
77 visual2pixel_t visual2pixel;
78 visual_mask_t visual_mask;
79 size_t pixel_bytes;
80
81 size_t size;
82 uint8_t *addr;
83
84 /** Current drawing color */
85 pixel_t color;
86} kfb_t;
87
88typedef struct {
89 kfb_t *kfb;
90 gfx_bitmap_alloc_t alloc;
91 gfx_rect_t rect;
92 gfx_bitmap_flags_t flags;
93 pixel_t key_color;
94 bool myalloc;
95} kfb_bitmap_t;
96
97static errno_t kfb_ddev_get_gc(void *, sysarg_t *, sysarg_t *);
98static errno_t kfb_ddev_get_info(void *, ddev_info_t *);
99
100static errno_t kfb_gc_set_clip_rect(void *, gfx_rect_t *);
101static errno_t kfb_gc_set_color(void *, gfx_color_t *);
102static errno_t kfb_gc_fill_rect(void *, gfx_rect_t *);
103static errno_t kfb_gc_bitmap_create(void *, gfx_bitmap_params_t *,
104 gfx_bitmap_alloc_t *, void **);
105static errno_t kfb_gc_bitmap_destroy(void *);
106static errno_t kfb_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
107static errno_t kfb_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
108
109static ddev_ops_t kfb_ddev_ops = {
110 .get_gc = kfb_ddev_get_gc,
111 .get_info = kfb_ddev_get_info
112};
113
114static gfx_context_ops_t kfb_gc_ops = {
115 .set_clip_rect = kfb_gc_set_clip_rect,
116 .set_color = kfb_gc_set_color,
117 .fill_rect = kfb_gc_fill_rect,
118 .bitmap_create = kfb_gc_bitmap_create,
119 .bitmap_destroy = kfb_gc_bitmap_destroy,
120 .bitmap_render = kfb_gc_bitmap_render,
121 .bitmap_get_alloc = kfb_gc_bitmap_get_alloc
122};
123
124static errno_t kfb_ddev_get_gc(void *arg, sysarg_t *arg2, sysarg_t *arg3)
125{
126 kfb_t *kfb = (kfb_t *) arg;
127
128 *arg2 = ddf_fun_get_handle(kfb->fun);
129 *arg3 = 42;
130 return EOK;
131}
132
133static errno_t kfb_ddev_get_info(void *arg, ddev_info_t *info)
134{
135 kfb_t *kfb = (kfb_t *) arg;
136
137 ddev_info_init(info);
138 info->rect = kfb->rect;
139 return EOK;
140}
141
142/** Set clipping rectangle on KFB.
143 *
144 * @param arg KFB
145 * @param rect Rectangle or @c NULL
146 *
147 * @return EOK on success or an error code
148 */
149static errno_t kfb_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
150{
151 kfb_t *kfb = (kfb_t *) arg;
152
153 if (rect != NULL)
154 gfx_rect_clip(rect, &kfb->rect, &kfb->clip_rect);
155 else
156 kfb->clip_rect = kfb->rect;
157
158 return EOK;
159}
160
161/** Set color on KFB.
162 *
163 * Set drawing color on KFB GC.
164 *
165 * @param arg KFB
166 * @param color Color
167 *
168 * @return EOK on success or an error code
169 */
170static errno_t kfb_gc_set_color(void *arg, gfx_color_t *color)
171{
172 kfb_t *kfb = (kfb_t *) arg;
173 uint16_t r, g, b;
174
175 gfx_color_get_rgb_i16(color, &r, &g, &b);
176 kfb->color = PIXEL(0, r >> 8, g >> 8, b >> 8);
177 return EOK;
178}
179
180/** Fill rectangle on KFB.
181 *
182 * @param arg KFB
183 * @param rect Rectangle
184 *
185 * @return EOK on success or an error code
186 */
187static errno_t kfb_gc_fill_rect(void *arg, gfx_rect_t *rect)
188{
189 kfb_t *kfb = (kfb_t *) arg;
190 gfx_rect_t crect;
191 gfx_coord_t x, y;
192
193 /* Make sure we have a sorted, clipped rectangle */
194 gfx_rect_clip(rect, &kfb->rect, &crect);
195
196 for (y = crect.p0.y; y < crect.p1.y; y++) {
197 for (x = crect.p0.x; x < crect.p1.x; x++) {
198 kfb->pixel2visual(kfb->addr + FB_POS(kfb, x, y),
199 kfb->color);
200 }
201 }
202
203 return EOK;
204}
205
206/** Create bitmap in KFB GC.
207 *
208 * @param arg KFB
209 * @param params Bitmap params
210 * @param alloc Bitmap allocation info or @c NULL
211 * @param rbm Place to store pointer to new bitmap
212 * @return EOK on success or an error code
213 */
214errno_t kfb_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
215 gfx_bitmap_alloc_t *alloc, void **rbm)
216{
217 kfb_t *kfb = (kfb_t *) arg;
218 kfb_bitmap_t *kfbbm = NULL;
219 gfx_coord2_t dim;
220 errno_t rc;
221
222 /* Check that we support all required flags */
223 if ((params->flags & ~(bmpf_color_key | bmpf_colorize)) != 0)
224 return ENOTSUP;
225
226 kfbbm = calloc(1, sizeof(kfb_bitmap_t));
227 if (kfbbm == NULL)
228 return ENOMEM;
229
230 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
231 kfbbm->rect = params->rect;
232 kfbbm->flags = params->flags;
233 kfbbm->key_color = params->key_color;
234
235 if (alloc == NULL) {
236 kfbbm->alloc.pitch = dim.x * sizeof(uint32_t);
237 kfbbm->alloc.off0 = 0;
238 kfbbm->alloc.pixels = malloc(kfbbm->alloc.pitch * dim.y);
239 kfbbm->myalloc = true;
240
241 if (kfbbm->alloc.pixels == NULL) {
242 rc = ENOMEM;
243 goto error;
244 }
245 } else {
246 kfbbm->alloc = *alloc;
247 }
248
249 kfbbm->kfb = kfb;
250 *rbm = (void *)kfbbm;
251 return EOK;
252error:
253 if (rbm != NULL)
254 free(kfbbm);
255 return rc;
256}
257
258/** Destroy bitmap in KFB GC.
259 *
260 * @param bm Bitmap
261 * @return EOK on success or an error code
262 */
263static errno_t kfb_gc_bitmap_destroy(void *bm)
264{
265 kfb_bitmap_t *kfbbm = (kfb_bitmap_t *)bm;
266 if (kfbbm->myalloc)
267 free(kfbbm->alloc.pixels);
268 free(kfbbm);
269 return EOK;
270}
271
272/** Render bitmap in KFB GC.
273 *
274 * @param bm Bitmap
275 * @param srect0 Source rectangle or @c NULL
276 * @param offs0 Offset or @c NULL
277 * @return EOK on success or an error code
278 */
279static errno_t kfb_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
280 gfx_coord2_t *offs0)
281{
282 kfb_bitmap_t *kfbbm = (kfb_bitmap_t *)bm;
283 kfb_t *kfb = kfbbm->kfb;
284 gfx_rect_t srect;
285 gfx_rect_t drect;
286 gfx_rect_t skfbrect;
287 gfx_rect_t crect;
288 gfx_coord2_t offs;
289 gfx_coord2_t bmdim;
290 gfx_coord2_t dim;
291 gfx_coord2_t sp;
292 gfx_coord2_t dp;
293 gfx_coord2_t pos;
294 pixelmap_t pbm;
295 pixel_t color;
296
297 /* Clip source rectangle to bitmap bounds */
298
299 if (srect0 != NULL)
300 gfx_rect_clip(srect0, &kfbbm->rect, &srect);
301 else
302 srect = kfbbm->rect;
303
304 if (offs0 != NULL) {
305 offs = *offs0;
306 } else {
307 offs.x = 0;
308 offs.y = 0;
309 }
310
311 /* Destination rectangle */
312 gfx_rect_translate(&offs, &srect, &drect);
313 gfx_coord2_subtract(&drect.p1, &drect.p0, &dim);
314 gfx_coord2_subtract(&kfbbm->rect.p1, &kfbbm->rect.p0, &bmdim);
315
316 pbm.width = bmdim.x;
317 pbm.height = bmdim.y;
318 pbm.data = kfbbm->alloc.pixels;
319
320 /* Transform KFB bounding rectangle back to bitmap coordinate system */
321 gfx_rect_rtranslate(&offs, &kfb->rect, &skfbrect);
322
323 /*
324 * Make sure we have a sorted source rectangle, clipped so that
325 * destination lies within KFB bounding rectangle
326 */
327 gfx_rect_clip(&srect, &skfbrect, &crect);
328
329 if ((kfbbm->flags & bmpf_color_key) != 0) {
330 /* Simple copy */
331 for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
332 for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
333 gfx_coord2_subtract(&pos, &kfbbm->rect.p0, &sp);
334 gfx_coord2_add(&pos, &offs, &dp);
335
336 color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
337 if (color != kfbbm->key_color) {
338 kfb->pixel2visual(kfb->addr +
339 FB_POS(kfb, dp.x, dp.y), color);
340 }
341 }
342 }
343 } else if ((kfbbm->flags & bmpf_colorize) != 0) {
344 /* Color key */
345 for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
346 for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
347 gfx_coord2_subtract(&pos, &kfbbm->rect.p0, &sp);
348 gfx_coord2_add(&pos, &offs, &dp);
349
350 color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
351 kfb->pixel2visual(kfb->addr +
352 FB_POS(kfb, dp.x, dp.y), color);
353 }
354 }
355 } else {
356 /* Color key & colorize */
357 for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
358 for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
359 gfx_coord2_subtract(&pos, &kfbbm->rect.p0, &sp);
360 gfx_coord2_add(&pos, &offs, &dp);
361
362 color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
363 kfb->pixel2visual(kfb->addr +
364 FB_POS(kfb, dp.x, dp.y), color);
365 }
366 }
367 }
368
369 return EOK;
370}
371
372/** Get allocation info for bitmap in KFB GC.
373 *
374 * @param bm Bitmap
375 * @param alloc Place to store allocation info
376 * @return EOK on success or an error code
377 */
378static errno_t kfb_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
379{
380 kfb_bitmap_t *kfbbm = (kfb_bitmap_t *)bm;
381 *alloc = kfbbm->alloc;
382 return EOK;
383}
384
385static void kfb_client_conn(ipc_call_t *icall, void *arg)
386{
387 kfb_t *kfb;
388 ddev_srv_t srv;
389 sysarg_t gc_id;
390 gfx_context_t *gc;
391 errno_t rc;
392
393 kfb = (kfb_t *) ddf_fun_data_get((ddf_fun_t *) arg);
394
395 gc_id = ipc_get_arg3(icall);
396
397 if (gc_id == 0) {
398 /* Set up protocol structure */
399 ddev_srv_initialize(&srv);
400 srv.ops = &kfb_ddev_ops;
401 srv.arg = kfb;
402
403 /* Handle connection */
404 ddev_conn(icall, &srv);
405 } else {
406 assert(gc_id == 42);
407
408 if (kfb->addr != AS_AREA_ANY) {
409 /* This means there already is a GC connection */
410 async_answer_0(icall, EBUSY);
411 return;
412 }
413
414 rc = physmem_map(kfb->paddr + kfb->offset,
415 ALIGN_UP(kfb->size, PAGE_SIZE) >> PAGE_WIDTH,
416 AS_AREA_READ | AS_AREA_WRITE, (void *) &kfb->addr);
417 if (rc != EOK)
418 goto error;
419
420 rc = gfx_context_new(&kfb_gc_ops, kfb, &gc);
421 if (rc != EOK)
422 goto error;
423
424 /* GC connection */
425 gc_conn(icall, gc);
426
427 rc = physmem_unmap(kfb->addr);
428 if (rc == EOK)
429 kfb->addr = AS_AREA_ANY;
430 }
431
432 return;
433error:
434 if (kfb->addr != AS_AREA_ANY) {
435 if (physmem_unmap(kfb->addr) == EOK)
436 kfb->addr = AS_AREA_ANY;
437 }
438
439 async_answer_0(icall, rc);
440}
441
442errno_t port_init(ddf_dev_t *dev)
443{
444 ddf_fun_t *fun = NULL;
445 kfb_t *kfb = NULL;
446 errno_t rc;
447
448 fun = ddf_fun_create(dev, fun_exposed, "kfb");
449 if (fun == NULL) {
450 rc = ENOMEM;
451 goto error;
452 }
453
454 ddf_fun_set_conn_handler(fun, &kfb_client_conn);
455
456 kfb = ddf_fun_data_alloc(fun, sizeof(kfb_t));
457 if (kfb == NULL) {
458 rc = ENOMEM;
459 goto error;
460 }
461
462 sysarg_t present;
463 rc = sysinfo_get_value("fb", &present);
464 if (rc != EOK)
465 present = false;
466
467 if (!present) {
468 rc = ENOENT;
469 goto error;
470 }
471
472 sysarg_t kind;
473 rc = sysinfo_get_value("fb.kind", &kind);
474 if (rc != EOK)
475 kind = (sysarg_t) -1;
476
477 if (kind != 1) {
478 rc = EINVAL;
479 goto error;
480 }
481
482 sysarg_t paddr;
483 rc = sysinfo_get_value("fb.address.physical", &paddr);
484 if (rc != EOK)
485 goto error;
486
487 sysarg_t offset;
488 rc = sysinfo_get_value("fb.offset", &offset);
489 if (rc != EOK)
490 offset = 0;
491
492 sysarg_t width;
493 rc = sysinfo_get_value("fb.width", &width);
494 if (rc != EOK)
495 goto error;
496
497 sysarg_t height;
498 rc = sysinfo_get_value("fb.height", &height);
499 if (rc != EOK)
500 goto error;
501
502 sysarg_t scanline;
503 rc = sysinfo_get_value("fb.scanline", &scanline);
504 if (rc != EOK)
505 goto error;
506
507 sysarg_t visual;
508 rc = sysinfo_get_value("fb.visual", &visual);
509 if (rc != EOK)
510 goto error;
511
512 kfb->fun = fun;
513
514 kfb->rect.p0.x = 0;
515 kfb->rect.p0.y = 0;
516 kfb->rect.p1.x = width;
517 kfb->rect.p1.y = height;
518
519 kfb->clip_rect = kfb->rect;
520
521 kfb->paddr = paddr;
522 kfb->offset = offset;
523 kfb->scanline = scanline;
524 kfb->visual = visual;
525
526 switch (visual) {
527 case VISUAL_INDIRECT_8:
528 kfb->pixel2visual = pixel2bgr_323;
529 kfb->visual2pixel = bgr_323_2pixel;
530 kfb->visual_mask = visual_mask_323;
531 kfb->pixel_bytes = 1;
532 break;
533 case VISUAL_RGB_5_5_5_LE:
534 kfb->pixel2visual = pixel2rgb_555_le;
535 kfb->visual2pixel = rgb_555_le_2pixel;
536 kfb->visual_mask = visual_mask_555;
537 kfb->pixel_bytes = 2;
538 break;
539 case VISUAL_RGB_5_5_5_BE:
540 kfb->pixel2visual = pixel2rgb_555_be;
541 kfb->visual2pixel = rgb_555_be_2pixel;
542 kfb->visual_mask = visual_mask_555;
543 kfb->pixel_bytes = 2;
544 break;
545 case VISUAL_RGB_5_6_5_LE:
546 kfb->pixel2visual = pixel2rgb_565_le;
547 kfb->visual2pixel = rgb_565_le_2pixel;
548 kfb->visual_mask = visual_mask_565;
549 kfb->pixel_bytes = 2;
550 break;
551 case VISUAL_RGB_5_6_5_BE:
552 kfb->pixel2visual = pixel2rgb_565_be;
553 kfb->visual2pixel = rgb_565_be_2pixel;
554 kfb->visual_mask = visual_mask_565;
555 kfb->pixel_bytes = 2;
556 break;
557 case VISUAL_RGB_8_8_8:
558 kfb->pixel2visual = pixel2rgb_888;
559 kfb->visual2pixel = rgb_888_2pixel;
560 kfb->visual_mask = visual_mask_888;
561 kfb->pixel_bytes = 3;
562 break;
563 case VISUAL_BGR_8_8_8:
564 kfb->pixel2visual = pixel2bgr_888;
565 kfb->visual2pixel = bgr_888_2pixel;
566 kfb->visual_mask = visual_mask_888;
567 kfb->pixel_bytes = 3;
568 break;
569 case VISUAL_RGB_8_8_8_0:
570 kfb->pixel2visual = pixel2rgb_8880;
571 kfb->visual2pixel = rgb_8880_2pixel;
572 kfb->visual_mask = visual_mask_8880;
573 kfb->pixel_bytes = 4;
574 break;
575 case VISUAL_RGB_0_8_8_8:
576 kfb->pixel2visual = pixel2rgb_0888;
577 kfb->visual2pixel = rgb_0888_2pixel;
578 kfb->visual_mask = visual_mask_0888;
579 kfb->pixel_bytes = 4;
580 break;
581 case VISUAL_BGR_0_8_8_8:
582 kfb->pixel2visual = pixel2bgr_0888;
583 kfb->visual2pixel = bgr_0888_2pixel;
584 kfb->visual_mask = visual_mask_0888;
585 kfb->pixel_bytes = 4;
586 break;
587 case VISUAL_BGR_8_8_8_0:
588 kfb->pixel2visual = pixel2bgr_8880;
589 kfb->visual2pixel = bgr_8880_2pixel;
590 kfb->visual_mask = visual_mask_8880;
591 kfb->pixel_bytes = 4;
592 break;
593 default:
594 return EINVAL;
595 }
596
597 kfb->size = scanline * height;
598 kfb->addr = AS_AREA_ANY;
599
600 rc = ddf_fun_bind(fun);
601 if (rc != EOK)
602 goto error;
603
604 rc = ddf_fun_add_to_category(fun, "display-device");
605 if (rc != EOK) {
606 ddf_fun_unbind(fun);
607 goto error;
608 }
609
610 return EOK;
611error:
612 if (fun != NULL)
613 ddf_fun_destroy(fun);
614 return rc;
615}
616
617/** @}
618 */
Note: See TracBrowser for help on using the repository browser.