source: mainline/uspace/drv/fb/kfb/port.c@ bea947f

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bea947f was bea947f, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Implement bitmap color key to allow transparent cursor background

This seems to be the simplest solution of them all. It will work
on any bit depth except 1 bit per pixel (monochrome), where we would
need to extend the bitmap with a bit mask instead.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1/*
2 * Copyright (c) 2019 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/mode.h>
53#include <io/pixelmap.h>
54#include <ipcgfx/server.h>
55#include <mem.h>
56#include <pixconv.h>
57#include <stddef.h>
58#include <stdint.h>
59#include <stdlib.h>
60#include <sysinfo.h>
61
62#include "kfb.h"
63#include "port.h"
64
65#define FB_POS(fb, x, y) ((y) * (fb)->scanline + (x) * (fb)->pixel_bytes)
66
67typedef struct {
68 ddf_fun_t *fun;
69
70 sysarg_t paddr;
71 gfx_rect_t 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_color(void *, gfx_color_t *);
101static errno_t kfb_gc_fill_rect(void *, gfx_rect_t *);
102static errno_t kfb_gc_bitmap_create(void *, gfx_bitmap_params_t *,
103 gfx_bitmap_alloc_t *, void **);
104static errno_t kfb_gc_bitmap_destroy(void *);
105static errno_t kfb_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
106static errno_t kfb_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
107
108static ddev_ops_t kfb_ddev_ops = {
109 .get_gc = kfb_ddev_get_gc,
110 .get_info = kfb_ddev_get_info
111};
112
113static gfx_context_ops_t kfb_gc_ops = {
114 .set_color = kfb_gc_set_color,
115 .fill_rect = kfb_gc_fill_rect,
116 .bitmap_create = kfb_gc_bitmap_create,
117 .bitmap_destroy = kfb_gc_bitmap_destroy,
118 .bitmap_render = kfb_gc_bitmap_render,
119 .bitmap_get_alloc = kfb_gc_bitmap_get_alloc
120};
121
122static errno_t kfb_ddev_get_gc(void *arg, sysarg_t *arg2, sysarg_t *arg3)
123{
124 kfb_t *kfb = (kfb_t *) arg;
125
126 *arg2 = ddf_fun_get_handle(kfb->fun);
127 *arg3 = 42;
128 return EOK;
129}
130
131static errno_t kfb_ddev_get_info(void *arg, ddev_info_t *info)
132{
133 kfb_t *kfb = (kfb_t *) arg;
134
135 ddev_info_init(info);
136 info->rect = kfb->rect;
137 return EOK;
138}
139
140/** Set color on KFB.
141 *
142 * Set drawing color on KFB GC.
143 *
144 * @param arg KFB
145 * @param color Color
146 *
147 * @return EOK on success or an error code
148 */
149static errno_t kfb_gc_set_color(void *arg, gfx_color_t *color)
150{
151 kfb_t *kfb = (kfb_t *) arg;
152 uint16_t r, g, b;
153
154 gfx_color_get_rgb_i16(color, &r, &g, &b);
155 kfb->color = PIXEL(0, r >> 8, g >> 8, b >> 8);
156 return EOK;
157}
158
159/** Fill rectangle on KFB.
160 *
161 * @param arg KFB
162 * @param rect Rectangle
163 *
164 * @return EOK on success or an error code
165 */
166static errno_t kfb_gc_fill_rect(void *arg, gfx_rect_t *rect)
167{
168 kfb_t *kfb = (kfb_t *) arg;
169 gfx_rect_t crect;
170 gfx_coord_t x, y;
171
172 /* Make sure we have a sorted, clipped rectangle */
173 gfx_rect_clip(rect, &kfb->rect, &crect);
174
175 for (y = crect.p0.y; y < crect.p1.y; y++) {
176 for (x = crect.p0.x; x < crect.p1.x; x++) {
177 kfb->pixel2visual(kfb->addr + FB_POS(kfb, x, y),
178 kfb->color);
179 }
180 }
181
182 return EOK;
183}
184
185/** Create bitmap in KFB GC.
186 *
187 * @param arg KFB
188 * @param params Bitmap params
189 * @param alloc Bitmap allocation info or @c NULL
190 * @param rbm Place to store pointer to new bitmap
191 * @return EOK on success or an error code
192 */
193errno_t kfb_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
194 gfx_bitmap_alloc_t *alloc, void **rbm)
195{
196 kfb_t *kfb = (kfb_t *) arg;
197 kfb_bitmap_t *kfbbm = NULL;
198 gfx_coord2_t dim;
199 errno_t rc;
200
201 kfbbm = calloc(1, sizeof(kfb_bitmap_t));
202 if (kfbbm == NULL)
203 return ENOMEM;
204
205 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
206 kfbbm->rect = params->rect;
207 kfbbm->flags = params->flags;
208 kfbbm->key_color = params->key_color;
209
210 if (alloc == NULL) {
211 kfbbm->alloc.pitch = dim.x * sizeof(uint32_t);
212 kfbbm->alloc.off0 = 0;
213 kfbbm->alloc.pixels = malloc(kfbbm->alloc.pitch * dim.y);
214 kfbbm->myalloc = true;
215
216 if (kfbbm->alloc.pixels == NULL) {
217 rc = ENOMEM;
218 goto error;
219 }
220 } else {
221 kfbbm->alloc = *alloc;
222 }
223
224 kfbbm->kfb = kfb;
225 *rbm = (void *)kfbbm;
226 return EOK;
227error:
228 if (rbm != NULL)
229 free(kfbbm);
230 return rc;
231}
232
233/** Destroy bitmap in KFB GC.
234 *
235 * @param bm Bitmap
236 * @return EOK on success or an error code
237 */
238static errno_t kfb_gc_bitmap_destroy(void *bm)
239{
240 kfb_bitmap_t *kfbbm = (kfb_bitmap_t *)bm;
241 if (kfbbm->myalloc)
242 free(kfbbm->alloc.pixels);
243 free(kfbbm);
244 return EOK;
245}
246
247/** Render bitmap in KFB GC.
248 *
249 * @param bm Bitmap
250 * @param srect0 Source rectangle or @c NULL
251 * @param offs0 Offset or @c NULL
252 * @return EOK on success or an error code
253 */
254static errno_t kfb_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
255 gfx_coord2_t *offs0)
256{
257 kfb_bitmap_t *kfbbm = (kfb_bitmap_t *)bm;
258 kfb_t *kfb = kfbbm->kfb;
259 gfx_rect_t srect;
260 gfx_rect_t drect;
261 gfx_rect_t skfbrect;
262 gfx_rect_t crect;
263 gfx_coord2_t offs;
264 gfx_coord2_t bmdim;
265 gfx_coord2_t dim;
266 gfx_coord2_t sp;
267 gfx_coord2_t dp;
268 gfx_coord2_t pos;
269 pixelmap_t pbm;
270 pixel_t color;
271
272 /* Clip source rectangle to bitmap bounds */
273
274 if (srect0 != NULL)
275 gfx_rect_clip(srect0, &kfbbm->rect, &srect);
276 else
277 srect = kfbbm->rect;
278
279 if (offs0 != NULL) {
280 offs = *offs0;
281 } else {
282 offs.x = 0;
283 offs.y = 0;
284 }
285
286 /* Destination rectangle */
287 gfx_rect_translate(&offs, &srect, &drect);
288 gfx_coord2_subtract(&drect.p1, &drect.p0, &dim);
289 gfx_coord2_subtract(&kfbbm->rect.p1, &kfbbm->rect.p0, &bmdim);
290
291 pbm.width = bmdim.x;
292 pbm.height = bmdim.y;
293 pbm.data = kfbbm->alloc.pixels;
294
295 /* Transform KFB bounding rectangle back to bitmap coordinate system */
296 gfx_rect_rtranslate(&offs, &kfb->rect, &skfbrect);
297
298 /*
299 * Make sure we have a sorted source rectangle, clipped so that
300 * destination lies within KFB bounding rectangle
301 */
302 gfx_rect_clip(&srect, &skfbrect, &crect);
303
304 if ((kfbbm->flags & bmpf_color_key) != 0) {
305 for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
306 for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
307 gfx_coord2_subtract(&pos, &kfbbm->rect.p0, &sp);
308 gfx_coord2_add(&pos, &offs, &dp);
309
310 color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
311 if (color != kfbbm->key_color) {
312 kfb->pixel2visual(kfb->addr +
313 FB_POS(kfb, dp.x, dp.y), color);
314 }
315 }
316 }
317 } else {
318 for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
319 for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
320 gfx_coord2_subtract(&pos, &kfbbm->rect.p0, &sp);
321 gfx_coord2_add(&pos, &offs, &dp);
322
323 color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
324 kfb->pixel2visual(kfb->addr +
325 FB_POS(kfb, dp.x, dp.y), color);
326 }
327 }
328 }
329
330 return EOK;
331}
332
333/** Get allocation info for bitmap in KFB GC.
334 *
335 * @param bm Bitmap
336 * @param alloc Place to store allocation info
337 * @return EOK on success or an error code
338 */
339static errno_t kfb_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
340{
341 kfb_bitmap_t *kfbbm = (kfb_bitmap_t *)bm;
342 *alloc = kfbbm->alloc;
343 return EOK;
344}
345
346#include <stdio.h>
347static void kfb_client_conn(ipc_call_t *icall, void *arg)
348{
349 kfb_t *kfb;
350 ddev_srv_t srv;
351 sysarg_t gc_id;
352 gfx_context_t *gc;
353 errno_t rc;
354
355 kfb = (kfb_t *) ddf_fun_data_get((ddf_fun_t *) arg);
356
357 printf("kfb_client_conn arg2=%lu arg3=%lu arg4=%lu\n",
358 (unsigned long) ipc_get_arg2(icall),
359 (unsigned long) ipc_get_arg3(icall),
360 (unsigned long) ipc_get_arg4(icall));
361
362 gc_id = ipc_get_arg3(icall);
363
364 if (gc_id == 0) {
365 /* Set up protocol structure */
366 ddev_srv_initialize(&srv);
367 srv.ops = &kfb_ddev_ops;
368 srv.arg = kfb;
369
370 /* Handle connection */
371 ddev_conn(icall, &srv);
372 } else {
373 assert(gc_id == 42);
374
375 rc = physmem_map(kfb->paddr + kfb->offset,
376 ALIGN_UP(kfb->size, PAGE_SIZE) >> PAGE_WIDTH,
377 AS_AREA_READ | AS_AREA_WRITE, (void *) &kfb->addr);
378 if (rc != EOK)
379 goto error;
380
381 rc = gfx_context_new(&kfb_gc_ops, kfb, &gc);
382 if (rc != EOK)
383 goto error;
384
385 /* GC connection */
386 gc_conn(icall, gc);
387
388 rc = physmem_unmap(kfb->addr);
389 if (rc == EOK)
390 kfb->addr = NULL;
391 }
392
393 return;
394error:
395 if (kfb->addr != NULL) {
396 if (physmem_unmap(kfb->addr) == EOK)
397 kfb->addr = NULL;
398 }
399
400 async_answer_0(icall, rc);
401}
402
403errno_t port_init(ddf_dev_t *dev)
404{
405 ddf_fun_t *fun = NULL;
406 kfb_t *kfb = NULL;
407 errno_t rc;
408
409 fun = ddf_fun_create(dev, fun_exposed, "kfb");
410 if (fun == NULL) {
411 rc = ENOMEM;
412 goto error;
413 }
414
415 ddf_fun_set_conn_handler(fun, &kfb_client_conn);
416
417 kfb = ddf_fun_data_alloc(fun, sizeof(kfb_t));
418 if (kfb == NULL) {
419 rc = ENOMEM;
420 goto error;
421 }
422
423 sysarg_t present;
424 rc = sysinfo_get_value("fb", &present);
425 if (rc != EOK)
426 present = false;
427
428 if (!present) {
429 ddf_fun_destroy(fun);
430 rc = ENOENT;
431 goto error;
432 }
433
434 sysarg_t kind;
435 rc = sysinfo_get_value("fb.kind", &kind);
436 if (rc != EOK)
437 kind = (sysarg_t) -1;
438
439 if (kind != 1) {
440 rc = EINVAL;
441 goto error;
442 }
443
444 sysarg_t paddr;
445 rc = sysinfo_get_value("fb.address.physical", &paddr);
446 if (rc != EOK)
447 goto error;
448
449 sysarg_t offset;
450 rc = sysinfo_get_value("fb.offset", &offset);
451 if (rc != EOK)
452 offset = 0;
453
454 sysarg_t width;
455 rc = sysinfo_get_value("fb.width", &width);
456 if (rc != EOK)
457 goto error;
458
459 sysarg_t height;
460 rc = sysinfo_get_value("fb.height", &height);
461 if (rc != EOK)
462 goto error;
463
464 sysarg_t scanline;
465 rc = sysinfo_get_value("fb.scanline", &scanline);
466 if (rc != EOK)
467 goto error;
468
469 sysarg_t visual;
470 rc = sysinfo_get_value("fb.visual", &visual);
471 if (rc != EOK)
472 goto error;
473
474 kfb->fun = fun;
475
476 kfb->rect.p0.x = 0;
477 kfb->rect.p0.y = 0;
478 kfb->rect.p1.x = width;
479 kfb->rect.p1.y = height;
480
481 kfb->paddr = paddr;
482 kfb->offset = offset;
483 kfb->scanline = scanline;
484 kfb->visual = visual;
485
486 switch (visual) {
487 case VISUAL_INDIRECT_8:
488 kfb->pixel2visual = pixel2bgr_323;
489 kfb->visual2pixel = bgr_323_2pixel;
490 kfb->visual_mask = visual_mask_323;
491 kfb->pixel_bytes = 1;
492 break;
493 case VISUAL_RGB_5_5_5_LE:
494 kfb->pixel2visual = pixel2rgb_555_le;
495 kfb->visual2pixel = rgb_555_le_2pixel;
496 kfb->visual_mask = visual_mask_555;
497 kfb->pixel_bytes = 2;
498 break;
499 case VISUAL_RGB_5_5_5_BE:
500 kfb->pixel2visual = pixel2rgb_555_be;
501 kfb->visual2pixel = rgb_555_be_2pixel;
502 kfb->visual_mask = visual_mask_555;
503 kfb->pixel_bytes = 2;
504 break;
505 case VISUAL_RGB_5_6_5_LE:
506 kfb->pixel2visual = pixel2rgb_565_le;
507 kfb->visual2pixel = rgb_565_le_2pixel;
508 kfb->visual_mask = visual_mask_565;
509 kfb->pixel_bytes = 2;
510 break;
511 case VISUAL_RGB_5_6_5_BE:
512 kfb->pixel2visual = pixel2rgb_565_be;
513 kfb->visual2pixel = rgb_565_be_2pixel;
514 kfb->visual_mask = visual_mask_565;
515 kfb->pixel_bytes = 2;
516 break;
517 case VISUAL_RGB_8_8_8:
518 kfb->pixel2visual = pixel2rgb_888;
519 kfb->visual2pixel = rgb_888_2pixel;
520 kfb->visual_mask = visual_mask_888;
521 kfb->pixel_bytes = 3;
522 break;
523 case VISUAL_BGR_8_8_8:
524 kfb->pixel2visual = pixel2bgr_888;
525 kfb->visual2pixel = bgr_888_2pixel;
526 kfb->visual_mask = visual_mask_888;
527 kfb->pixel_bytes = 3;
528 break;
529 case VISUAL_RGB_8_8_8_0:
530 kfb->pixel2visual = pixel2rgb_8880;
531 kfb->visual2pixel = rgb_8880_2pixel;
532 kfb->visual_mask = visual_mask_8880;
533 kfb->pixel_bytes = 4;
534 break;
535 case VISUAL_RGB_0_8_8_8:
536 kfb->pixel2visual = pixel2rgb_0888;
537 kfb->visual2pixel = rgb_0888_2pixel;
538 kfb->visual_mask = visual_mask_0888;
539 kfb->pixel_bytes = 4;
540 break;
541 case VISUAL_BGR_0_8_8_8:
542 kfb->pixel2visual = pixel2bgr_0888;
543 kfb->visual2pixel = bgr_0888_2pixel;
544 kfb->visual_mask = visual_mask_0888;
545 kfb->pixel_bytes = 4;
546 break;
547 case VISUAL_BGR_8_8_8_0:
548 kfb->pixel2visual = pixel2bgr_8880;
549 kfb->visual2pixel = bgr_8880_2pixel;
550 kfb->visual_mask = visual_mask_8880;
551 kfb->pixel_bytes = 4;
552 break;
553 default:
554 return EINVAL;
555 }
556
557 kfb->size = scanline * height;
558 kfb->addr = AS_AREA_ANY;
559
560 rc = ddf_fun_bind(fun);
561 if (rc != EOK)
562 goto error;
563
564 rc = ddf_fun_add_to_category(fun, "display-device");
565 if (rc != EOK) {
566 ddf_fun_unbind(fun);
567 goto error;
568 }
569
570 return EOK;
571error:
572 if (fun != NULL)
573 ddf_fun_destroy(fun);
574 return rc;
575}
576
577/** @}
578 */
Note: See TracBrowser for help on using the repository browser.