source: mainline/uspace/lib/ipcgfx/src/client.c@ 62223ec

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

Client-side UI rendering

It is possible to turn on and off and if turned on, one can also
enable or disable window double buffering (currently both options
are build-time).

  • Property mode set to 100644
File size: 11.3 KB
Line 
1/*
2 * Copyright (c) 2021 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 libipcgfx
30 * @{
31 */
32/**
33 * @file GFX IPC backend
34 *
35 * This implements a graphics context via HelenOS IPC.
36 */
37
38#include <as.h>
39#include <ipcgfx/client.h>
40#include <ipcgfx/ipc/gc.h>
41#include <gfx/color.h>
42#include <gfx/coord.h>
43#include <gfx/context.h>
44#include <stdlib.h>
45#include "../private/client.h"
46
47static errno_t ipc_gc_set_color(void *, gfx_color_t *);
48static errno_t ipc_gc_fill_rect(void *, gfx_rect_t *);
49static errno_t ipc_gc_update(void *);
50static errno_t ipc_gc_bitmap_create(void *, gfx_bitmap_params_t *,
51 gfx_bitmap_alloc_t *, void **);
52static errno_t ipc_gc_bitmap_destroy(void *);
53static errno_t ipc_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
54static errno_t ipc_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
55
56gfx_context_ops_t ipc_gc_ops = {
57 .set_color = ipc_gc_set_color,
58 .fill_rect = ipc_gc_fill_rect,
59 .update = ipc_gc_update,
60 .bitmap_create = ipc_gc_bitmap_create,
61 .bitmap_destroy = ipc_gc_bitmap_destroy,
62 .bitmap_render = ipc_gc_bitmap_render,
63 .bitmap_get_alloc = ipc_gc_bitmap_get_alloc
64};
65
66/** Set color on IPC GC.
67 *
68 * Set drawing color on IPC GC.
69 *
70 * @param arg IPC GC
71 * @param color Color
72 *
73 * @return EOK on success or an error code
74 */
75static errno_t ipc_gc_set_color(void *arg, gfx_color_t *color)
76{
77 ipc_gc_t *ipcgc = (ipc_gc_t *) arg;
78 async_exch_t *exch;
79 uint16_t r, g, b;
80 errno_t rc;
81
82 gfx_color_get_rgb_i16(color, &r, &g, &b);
83
84 exch = async_exchange_begin(ipcgc->sess);
85 rc = async_req_3_0(exch, GC_SET_RGB_COLOR, r, g, b);
86 async_exchange_end(exch);
87
88 return rc;
89}
90
91/** Fill rectangle on IPC GC.
92 *
93 * @param arg IPC GC
94 * @param rect Rectangle
95 *
96 * @return EOK on success or an error code
97 */
98static errno_t ipc_gc_fill_rect(void *arg, gfx_rect_t *rect)
99{
100 ipc_gc_t *ipcgc = (ipc_gc_t *) arg;
101 async_exch_t *exch;
102 errno_t rc;
103
104 exch = async_exchange_begin(ipcgc->sess);
105 rc = async_req_4_0(exch, GC_FILL_RECT, rect->p0.x, rect->p0.y,
106 rect->p1.x, rect->p1.y);
107 async_exchange_end(exch);
108
109 return rc;
110}
111
112/** Update display on IPC GC.
113 *
114 * @param arg IPC GC
115 *
116 * @return EOK on success or an error code
117 */
118static errno_t ipc_gc_update(void *arg)
119{
120 ipc_gc_t *ipcgc = (ipc_gc_t *) arg;
121 async_exch_t *exch;
122 errno_t rc;
123
124 exch = async_exchange_begin(ipcgc->sess);
125 rc = async_req_0_0(exch, GC_UPDATE);
126 async_exchange_end(exch);
127
128 return rc;
129}
130
131/** Create normal bitmap in IPC GC.
132 *
133 * @param arg IPC GC
134 * @param params Bitmap params
135 * @param alloc Bitmap allocation info or @c NULL
136 * @param rbm Place to store pointer to new bitmap
137 * @return EOK on success or an error code
138 */
139static errno_t ipc_gc_bitmap_create_normal(void *arg,
140 gfx_bitmap_params_t *params,
141 gfx_bitmap_alloc_t *alloc, void **rbm)
142{
143 ipc_gc_t *ipcgc = (ipc_gc_t *) arg;
144 ipc_gc_bitmap_t *ipcbm = NULL;
145 gfx_coord2_t dim;
146 async_exch_t *exch = NULL;
147 as_area_info_t info;
148 ipc_call_t answer;
149 size_t asize;
150 aid_t req;
151 errno_t rc;
152
153 ipcbm = calloc(1, sizeof(ipc_gc_bitmap_t));
154 if (ipcbm == NULL)
155 return ENOMEM;
156
157 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
158 ipcbm->rect = params->rect;
159
160 if (alloc == NULL) {
161 ipcbm->alloc.pitch = dim.x * sizeof(uint32_t);
162 ipcbm->alloc.off0 = 0;
163 ipcbm->alloc.pixels = as_area_create(AS_AREA_ANY,
164 dim.x * dim.y * sizeof(uint32_t), AS_AREA_READ |
165 AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
166 if (ipcbm->alloc.pixels == AS_MAP_FAILED) {
167 rc = ENOMEM;
168 goto error;
169 }
170
171 ipcbm->myalloc = true;
172 } else {
173 /*
174 * Accept user allocation if it points to a an acceptable
175 * memory area.
176 */
177 rc = as_area_get_info(alloc->pixels, &info);
178 if (rc != EOK)
179 goto error;
180
181 /* Pixels should start at the beginning of the area */
182 if (info.start_addr != (uintptr_t) alloc->pixels) {
183 rc = EINVAL;
184 goto error;
185 }
186
187 /* Size of area should be size of bitmap rounded up to page size */
188 asize = PAGES2SIZE(SIZE2PAGES(alloc->pitch * dim.y));
189 if (info.size != asize) {
190 rc = EINVAL;
191 goto error;
192 }
193
194 ipcbm->alloc = *alloc;
195 }
196
197 exch = async_exchange_begin(ipcgc->sess);
198 req = async_send_0(exch, GC_BITMAP_CREATE, &answer);
199 rc = async_data_write_start(exch, params, sizeof (gfx_bitmap_params_t));
200 if (rc != EOK) {
201 async_forget(req);
202 goto error;
203 }
204
205 rc = async_share_out_start(exch, ipcbm->alloc.pixels,
206 AS_AREA_READ | AS_AREA_CACHEABLE);
207 if (rc != EOK) {
208 async_forget(req);
209 goto error;
210 }
211 async_exchange_end(exch);
212 exch = NULL;
213
214 async_wait_for(req, &rc);
215 if (rc != EOK)
216 goto error;
217
218 ipcbm->ipcgc = ipcgc;
219 ipcbm->bmp_id = ipc_get_arg1(&answer);
220 *rbm = (void *)ipcbm;
221 return EOK;
222error:
223 if (exch != NULL)
224 async_exchange_end(exch);
225 if (ipcbm != NULL) {
226 if (ipcbm->alloc.pixels != NULL)
227 as_area_destroy(ipcbm->alloc.pixels);
228 free(ipcbm);
229 }
230 return rc;
231}
232
233/** Create direct output bitmap in IPC GC.
234 *
235 * @param arg IPC GC
236 * @param params Bitmap params
237 * @param alloc Bitmap allocation info or @c NULL
238 * @param rbm Place to store pointer to new bitmap
239 * @return EOK on success or an error code
240 */
241static errno_t ipc_gc_bitmap_create_direct_output(void *arg,
242 gfx_bitmap_params_t *params,
243 gfx_bitmap_alloc_t *alloc, void **rbm)
244{
245 ipc_gc_t *ipcgc = (ipc_gc_t *) arg;
246 ipc_gc_bitmap_t *ipcbm = NULL;
247 gfx_coord2_t dim;
248 async_exch_t *exch = NULL;
249 void *pixels;
250 ipc_call_t answer;
251 size_t asize;
252 aid_t req;
253 errno_t rc;
254
255 /* Cannot specify allocation for direct output bitmap */
256 if (alloc != NULL)
257 return EINVAL;
258
259 ipcbm = calloc(1, sizeof(ipc_gc_bitmap_t));
260 if (ipcbm == NULL)
261 return ENOMEM;
262
263 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
264 ipcbm->rect = params->rect;
265
266 ipcbm->alloc.pitch = dim.x * sizeof(uint32_t);
267 ipcbm->alloc.off0 = 0;
268 ipcbm->myalloc = true;
269
270 asize = PAGES2SIZE(SIZE2PAGES(ipcbm->alloc.pitch * dim.y));
271
272 exch = async_exchange_begin(ipcgc->sess);
273 req = async_send_0(exch, GC_BITMAP_CREATE_DOUTPUT, &answer);
274 rc = async_data_write_start(exch, params, sizeof (gfx_bitmap_params_t));
275 if (rc != EOK) {
276 async_forget(req);
277 goto error;
278 }
279
280 rc = async_share_in_start_0_0(exch, asize, &pixels);
281 if (rc != EOK) {
282 async_forget(req);
283 goto error;
284 }
285 async_exchange_end(exch);
286 exch = NULL;
287
288 async_wait_for(req, &rc);
289 if (rc != EOK)
290 goto error;
291
292 ipcbm->ipcgc = ipcgc;
293 ipcbm->bmp_id = ipc_get_arg1(&answer);
294 ipcbm->alloc.pixels = pixels;
295 *rbm = (void *)ipcbm;
296 return EOK;
297error:
298 if (exch != NULL)
299 async_exchange_end(exch);
300 if (ipcbm != NULL) {
301 if (ipcbm->alloc.pixels != NULL)
302 as_area_destroy(ipcbm->alloc.pixels);
303 free(ipcbm);
304 }
305 return rc;
306}
307
308/** Create bitmap in IPC GC.
309 *
310 * @param arg IPC GC
311 * @param params Bitmap params
312 * @param alloc Bitmap allocation info or @c NULL
313 * @param rbm Place to store pointer to new bitmap
314 * @return EOK on success or an error code
315 */
316errno_t ipc_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
317 gfx_bitmap_alloc_t *alloc, void **rbm)
318{
319 if ((params->flags & bmpf_direct_output) != 0) {
320 return ipc_gc_bitmap_create_direct_output(arg, params, alloc,
321 rbm);
322 } else {
323 return ipc_gc_bitmap_create_normal(arg, params, alloc, rbm);
324 }
325}
326
327/** Destroy bitmap in IPC GC.
328 *
329 * @param bm Bitmap
330 * @return EOK on success or an error code
331 */
332static errno_t ipc_gc_bitmap_destroy(void *bm)
333{
334 ipc_gc_bitmap_t *ipcbm = (ipc_gc_bitmap_t *)bm;
335 async_exch_t *exch;
336 errno_t rc;
337
338 exch = async_exchange_begin(ipcbm->ipcgc->sess);
339 rc = async_req_1_0(exch, GC_BITMAP_DESTROY, ipcbm->bmp_id);
340 async_exchange_end(exch);
341
342 if (rc != EOK)
343 return rc;
344
345 if (ipcbm->myalloc)
346 as_area_destroy(ipcbm->alloc.pixels);
347 free(ipcbm);
348 return EOK;
349}
350
351/** Render bitmap in IPC GC.
352 *
353 * @param bm Bitmap
354 * @param srect0 Source rectangle or @c NULL
355 * @param offs0 Offset or @c NULL
356 * @return EOK on success or an error code
357 */
358static errno_t ipc_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
359 gfx_coord2_t *offs0)
360{
361 ipc_gc_bitmap_t *ipcbm = (ipc_gc_bitmap_t *)bm;
362 gfx_rect_t srect;
363 gfx_rect_t drect;
364 gfx_coord2_t offs;
365 async_exch_t *exch = NULL;
366 ipc_call_t answer;
367 aid_t req;
368 errno_t rc;
369
370 if (srect0 != NULL)
371 srect = *srect0;
372 else
373 srect = ipcbm->rect;
374
375 if (offs0 != NULL) {
376 offs = *offs0;
377 } else {
378 offs.x = 0;
379 offs.y = 0;
380 }
381
382 /* Destination rectangle */
383 gfx_rect_translate(&offs, &srect, &drect);
384
385 exch = async_exchange_begin(ipcbm->ipcgc->sess);
386 req = async_send_3(exch, GC_BITMAP_RENDER, ipcbm->bmp_id, offs.x,
387 offs.y, &answer);
388
389 rc = async_data_write_start(exch, &srect, sizeof (gfx_rect_t));
390 if (rc != EOK) {
391 async_forget(req);
392 goto error;
393 }
394
395 async_exchange_end(exch);
396 exch = NULL;
397
398 async_wait_for(req, &rc);
399 if (rc != EOK)
400 goto error;
401
402 return EOK;
403error:
404 if (exch != NULL)
405 async_exchange_end(exch);
406 return rc;
407}
408
409/** Get allocation info for bitmap in IPC GC.
410 *
411 * @param bm Bitmap
412 * @param alloc Place to store allocation info
413 * @return EOK on success or an error code
414 */
415static errno_t ipc_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
416{
417 ipc_gc_bitmap_t *ipcbm = (ipc_gc_bitmap_t *)bm;
418 *alloc = ipcbm->alloc;
419 return EOK;
420}
421
422/** Create IPC GC.
423 *
424 * Create graphics context for rendering via IPC.
425 *
426 * @param sess Async session
427 * @param rgc Place to store pointer to new GC.
428 *
429 * @return EOK on success or an error code
430 */
431errno_t ipc_gc_create(async_sess_t *sess, ipc_gc_t **rgc)
432{
433 ipc_gc_t *ipcgc = NULL;
434 gfx_context_t *gc = NULL;
435 errno_t rc;
436
437 ipcgc = calloc(1, sizeof(ipc_gc_t));
438 if (ipcgc == NULL) {
439 rc = ENOMEM;
440 goto error;
441 }
442
443 rc = gfx_context_new(&ipc_gc_ops, ipcgc, &gc);
444 if (rc != EOK)
445 goto error;
446
447 ipcgc->gc = gc;
448 ipcgc->sess = sess;
449 *rgc = ipcgc;
450 return EOK;
451error:
452 if (ipcgc != NULL)
453 free(ipcgc);
454 gfx_context_delete(gc);
455 return rc;
456}
457
458/** Delete IPC GC.
459 *
460 * @param ipcgc IPC GC
461 */
462errno_t ipc_gc_delete(ipc_gc_t *ipcgc)
463{
464 errno_t rc;
465
466 rc = gfx_context_delete(ipcgc->gc);
467 if (rc != EOK)
468 return rc;
469
470 free(ipcgc);
471 return EOK;
472}
473
474/** Get generic graphic context from IPC GC.
475 *
476 * @param ipcgc IPC GC
477 * @return Graphic context
478 */
479gfx_context_t *ipc_gc_get_ctx(ipc_gc_t *ipcgc)
480{
481 return ipcgc->gc;
482}
483
484/** @}
485 */
Note: See TracBrowser for help on using the repository browser.