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