source: mainline/uspace/lib/ipcgfx/src/client.c@ 8bf9058

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

Allow GUI direct access to window buffer

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