source: mainline/uspace/lib/ipcgfx/src/server.c@ 901b302

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 901b302 was 5fc8244, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Move device-related stuff out of libc to libdevice

Unfortunately, we need to keep clock_dev, which pulls in hw_res
and pio_window. clock_dev is used by time.c

  • Property mode set to 100644
File size: 10.4 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 server
34 *
35 * Serve a graphics context via HelenOS IPC.
36 */
37
38#include <as.h>
39#include <errno.h>
40#include <gfx/bitmap.h>
41#include <gfx/color.h>
42#include <gfx/render.h>
43#include <ipcgfx/ipc/gc.h>
44#include <ipcgfx/server.h>
45#include <stdint.h>
46#include <stdlib.h>
47#include <stdio.h>
48
49#include "../private/server.h"
50
51static ipc_gc_srv_bitmap_t *gc_bitmap_lookup(ipc_gc_srv_t *, sysarg_t);
52
53static void gc_set_clip_rect_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
54{
55 gfx_rect_t rect;
56 errno_t rc;
57
58 rect.p0.x = ipc_get_arg1(call);
59 rect.p0.y = ipc_get_arg2(call);
60 rect.p1.x = ipc_get_arg3(call);
61 rect.p1.y = ipc_get_arg4(call);
62
63 rc = gfx_set_clip_rect(srvgc->gc, &rect);
64 async_answer_0(call, rc);
65}
66
67static void gc_set_clip_rect_null_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
68{
69 errno_t rc;
70
71 rc = gfx_set_clip_rect(srvgc->gc, NULL);
72 async_answer_0(call, rc);
73}
74
75static void gc_set_rgb_color_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
76{
77 uint16_t r, g, b;
78 gfx_color_t *color;
79 errno_t rc;
80
81 r = ipc_get_arg1(call);
82 g = ipc_get_arg2(call);
83 b = ipc_get_arg3(call);
84
85 rc = gfx_color_new_rgb_i16(r, g, b, &color);
86 if (rc != EOK) {
87 async_answer_0(call, ENOMEM);
88 return;
89 }
90
91 rc = gfx_set_color(srvgc->gc, color);
92 async_answer_0(call, rc);
93}
94
95static void gc_fill_rect_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
96{
97 gfx_rect_t rect;
98 errno_t rc;
99
100 rect.p0.x = ipc_get_arg1(call);
101 rect.p0.y = ipc_get_arg2(call);
102 rect.p1.x = ipc_get_arg3(call);
103 rect.p1.y = ipc_get_arg4(call);
104
105 rc = gfx_fill_rect(srvgc->gc, &rect);
106 async_answer_0(call, rc);
107}
108
109static void gc_update_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
110{
111 errno_t rc;
112
113 rc = gfx_update(srvgc->gc);
114 async_answer_0(call, rc);
115}
116
117static void gc_bitmap_create_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
118{
119 gfx_bitmap_params_t params;
120 gfx_bitmap_alloc_t alloc;
121 gfx_bitmap_t *bitmap;
122 gfx_coord2_t dim;
123 ipc_gc_srv_bitmap_t *srvbmp = NULL;
124 ipc_call_t call;
125 size_t size;
126 unsigned int flags;
127 void *pixels;
128 errno_t rc;
129
130 if (!async_data_write_receive(&call, &size)) {
131 async_answer_0(&call, EREFUSED);
132 async_answer_0(icall, EREFUSED);
133 return;
134 }
135
136 if (size != sizeof(gfx_bitmap_params_t)) {
137 async_answer_0(&call, EINVAL);
138 async_answer_0(icall, EINVAL);
139 return;
140 }
141
142 rc = async_data_write_finalize(&call, &params, size);
143 if (rc != EOK) {
144 async_answer_0(&call, rc);
145 async_answer_0(icall, rc);
146 return;
147 }
148
149 /* Bitmap dimensions */
150 gfx_coord2_subtract(&params.rect.p1, &params.rect.p0, &dim);
151
152 if (!async_share_out_receive(&call, &size, &flags)) {
153 async_answer_0(icall, EINVAL);
154 return;
155 }
156
157 /* Check size */
158 if (size != PAGES2SIZE(SIZE2PAGES(dim.x * dim.y * sizeof(uint32_t)))) {
159 async_answer_0(icall, EINVAL);
160 return;
161 }
162
163 rc = async_share_out_finalize(&call, &pixels);
164 if (rc != EOK || pixels == AS_MAP_FAILED) {
165 async_answer_0(icall, ENOMEM);
166 return;
167 }
168
169 alloc.pitch = dim.x * sizeof(uint32_t);
170 alloc.off0 = 0;
171 alloc.pixels = pixels;
172
173 srvbmp = calloc(1, sizeof(ipc_gc_srv_bitmap_t));
174 if (srvbmp == NULL) {
175 as_area_destroy(pixels);
176 async_answer_0(icall, ENOMEM);
177 return;
178 }
179
180 rc = gfx_bitmap_create(srvgc->gc, &params, &alloc, &bitmap);
181 if (rc != EOK) {
182 free(srvbmp);
183 as_area_destroy(pixels);
184 async_answer_0(icall, rc);
185 return;
186 }
187
188 srvbmp->srvgc = srvgc;
189 list_append(&srvbmp->lbitmaps, &srvgc->bitmaps);
190 srvbmp->bmp = bitmap;
191 srvbmp->bmp_id = srvgc->next_bmp_id++;
192
193 /* We created the memory area by sharing it in */
194 srvbmp->myalloc = true;
195 srvbmp->pixels = pixels;
196
197 async_answer_1(icall, EOK, srvbmp->bmp_id);
198}
199
200static void gc_bitmap_create_doutput_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
201{
202 gfx_bitmap_params_t params;
203 gfx_bitmap_alloc_t alloc;
204 gfx_bitmap_t *bitmap;
205 gfx_coord2_t dim;
206 ipc_gc_srv_bitmap_t *srvbmp = NULL;
207 ipc_call_t call;
208 size_t size;
209 errno_t rc;
210
211 if (!async_data_write_receive(&call, &size)) {
212 async_answer_0(&call, EREFUSED);
213 async_answer_0(icall, EREFUSED);
214 return;
215 }
216
217 if (size != sizeof(gfx_bitmap_params_t)) {
218 async_answer_0(&call, EINVAL);
219 async_answer_0(icall, EINVAL);
220 return;
221 }
222
223 rc = async_data_write_finalize(&call, &params, size);
224 if (rc != EOK) {
225 async_answer_0(&call, rc);
226 async_answer_0(icall, rc);
227 return;
228 }
229
230 /* Bitmap dimensions */
231 gfx_coord2_subtract(&params.rect.p1, &params.rect.p0, &dim);
232
233 if (!async_share_in_receive(&call, &size)) {
234 async_answer_0(icall, EINVAL);
235 return;
236 }
237
238 /* Check size */
239 if (size != PAGES2SIZE(SIZE2PAGES(dim.x * dim.y * sizeof(uint32_t)))) {
240 async_answer_0(&call, EINVAL);
241 async_answer_0(icall, EINVAL);
242 return;
243 }
244
245 rc = gfx_bitmap_create(srvgc->gc, &params, NULL, &bitmap);
246 if (rc != EOK) {
247 async_answer_0(&call, rc);
248 async_answer_0(icall, rc);
249 return;
250 }
251
252 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
253 if (rc != EOK) {
254 gfx_bitmap_destroy(bitmap);
255 async_answer_0(&call, rc);
256 async_answer_0(icall, rc);
257 return;
258 }
259
260 rc = async_share_in_finalize(&call, alloc.pixels, AS_AREA_READ |
261 AS_AREA_WRITE | AS_AREA_CACHEABLE);
262 if (rc != EOK) {
263 gfx_bitmap_destroy(bitmap);
264 async_answer_0(icall, EIO);
265 return;
266 }
267
268 srvbmp = calloc(1, sizeof(ipc_gc_srv_bitmap_t));
269 if (srvbmp == NULL) {
270 gfx_bitmap_destroy(bitmap);
271 async_answer_0(icall, ENOMEM);
272 return;
273 }
274
275 srvbmp->srvgc = srvgc;
276 list_append(&srvbmp->lbitmaps, &srvgc->bitmaps);
277 srvbmp->bmp = bitmap;
278 srvbmp->bmp_id = srvgc->next_bmp_id++;
279
280 /* Area allocated by backing GC, we just shared it out */
281 srvbmp->myalloc = false;
282 srvbmp->pixels = alloc.pixels; // Not really needed
283
284 async_answer_1(icall, EOK, srvbmp->bmp_id);
285}
286
287static void gc_bitmap_destroy_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
288{
289 sysarg_t bmp_id;
290 ipc_gc_srv_bitmap_t *bitmap;
291 errno_t rc;
292
293 bmp_id = ipc_get_arg1(call);
294
295 bitmap = gc_bitmap_lookup(srvgc, bmp_id);
296 if (bitmap == NULL) {
297 async_answer_0(call, ENOENT);
298 return;
299 }
300
301 rc = gfx_bitmap_destroy(bitmap->bmp);
302 if (rc != EOK) {
303 async_answer_0(call, rc);
304 return;
305 }
306
307 if (bitmap->myalloc)
308 as_area_destroy(bitmap->pixels);
309
310 list_remove(&bitmap->lbitmaps);
311 free(bitmap);
312
313 async_answer_0(call, rc);
314}
315
316static void gc_bitmap_render_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
317{
318 ipc_gc_srv_bitmap_t *bitmap;
319 sysarg_t bmp_id;
320 gfx_rect_t srect;
321 gfx_coord2_t offs;
322 ipc_call_t call;
323 size_t size;
324 errno_t rc;
325
326 if (!async_data_write_receive(&call, &size)) {
327 async_answer_0(&call, EREFUSED);
328 async_answer_0(icall, EREFUSED);
329 return;
330 }
331
332 if (size != sizeof(gfx_rect_t)) {
333 async_answer_0(&call, EINVAL);
334 async_answer_0(icall, EINVAL);
335 return;
336 }
337
338 rc = async_data_write_finalize(&call, &srect, size);
339 if (rc != EOK) {
340 async_answer_0(&call, rc);
341 async_answer_0(icall, rc);
342 return;
343 }
344
345 bmp_id = ipc_get_arg1(icall);
346 offs.x = ipc_get_arg2(icall);
347 offs.y = ipc_get_arg3(icall);
348
349 bitmap = gc_bitmap_lookup(srvgc, bmp_id);
350 if (bitmap == NULL) {
351 async_answer_0(icall, ENOENT);
352 return;
353 }
354
355 rc = gfx_bitmap_render(bitmap->bmp, &srect, &offs);
356 async_answer_0(icall, rc);
357}
358
359errno_t gc_conn(ipc_call_t *icall, gfx_context_t *gc)
360{
361 ipc_gc_srv_t srvgc;
362 ipc_gc_srv_bitmap_t *bitmap;
363 link_t *link;
364
365 /* Accept the connection */
366 async_accept_0(icall);
367
368 srvgc.gc = gc;
369 list_initialize(&srvgc.bitmaps);
370 srvgc.next_bmp_id = 1;
371
372 while (true) {
373 ipc_call_t call;
374 async_get_call(&call);
375 sysarg_t method = ipc_get_imethod(&call);
376
377 if (!method) {
378 /* The other side has hung up */
379 async_answer_0(&call, EOK);
380 break;
381 }
382
383 switch (method) {
384 case GC_SET_CLIP_RECT:
385 gc_set_clip_rect_srv(&srvgc, &call);
386 break;
387 case GC_SET_CLIP_RECT_NULL:
388 gc_set_clip_rect_null_srv(&srvgc, &call);
389 break;
390 case GC_SET_RGB_COLOR:
391 gc_set_rgb_color_srv(&srvgc, &call);
392 break;
393 case GC_FILL_RECT:
394 gc_fill_rect_srv(&srvgc, &call);
395 break;
396 case GC_UPDATE:
397 gc_update_srv(&srvgc, &call);
398 break;
399 case GC_BITMAP_CREATE:
400 gc_bitmap_create_srv(&srvgc, &call);
401 break;
402 case GC_BITMAP_CREATE_DOUTPUT:
403 gc_bitmap_create_doutput_srv(&srvgc, &call);
404 break;
405 case GC_BITMAP_DESTROY:
406 gc_bitmap_destroy_srv(&srvgc, &call);
407 break;
408 case GC_BITMAP_RENDER:
409 gc_bitmap_render_srv(&srvgc, &call);
410 break;
411 default:
412 async_answer_0(&call, EINVAL);
413 break;
414 }
415 }
416
417 /*
418 * Destroy all remaining bitmaps. A client should destroy all
419 * the bitmaps before closing connection. But it could happen
420 * that the client is misbehaving or was abruptly disconnected
421 * (e.g. crashed).
422 */
423 link = list_first(&srvgc.bitmaps);
424 while (link != NULL) {
425 bitmap = list_get_instance(link, ipc_gc_srv_bitmap_t,
426 lbitmaps);
427
428 (void) gfx_bitmap_destroy(bitmap->bmp);
429 if (bitmap->myalloc)
430 as_area_destroy(bitmap->pixels);
431 list_remove(&bitmap->lbitmaps);
432 free(bitmap);
433
434 link = list_first(&srvgc.bitmaps);
435 }
436
437 return EOK;
438}
439
440static ipc_gc_srv_bitmap_t *gc_bitmap_lookup(ipc_gc_srv_t *srvgc,
441 sysarg_t bmp_id)
442{
443 link_t *link;
444 ipc_gc_srv_bitmap_t *bmp;
445
446 link = list_first(&srvgc->bitmaps);
447 while (link != NULL) {
448 bmp = list_get_instance(link, ipc_gc_srv_bitmap_t, lbitmaps);
449 if (bmp->bmp_id == bmp_id)
450 return bmp;
451 link = list_next(link, &srvgc->bitmaps);
452 }
453
454 return NULL;
455}
456
457/** @}
458 */
Note: See TracBrowser for help on using the repository browser.