source: mainline/uspace/lib/ipcgfx/src/server.c

Last change on this file was cdd6fc9, checked in by Jiri Svoboda <jiri@…>, 2 years ago

Add missing replies in IPC error paths

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 2023 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(&call, EINVAL);
154 async_answer_0(icall, EINVAL);
155 return;
156 }
157
158 /* Check size */
159 if (size != PAGES2SIZE(SIZE2PAGES(dim.x * dim.y * sizeof(uint32_t)))) {
160 async_answer_0(&call, EINVAL);
161 async_answer_0(icall, EINVAL);
162 return;
163 }
164
165 rc = async_share_out_finalize(&call, &pixels);
166 if (rc != EOK || pixels == AS_MAP_FAILED) {
167 async_answer_0(&call, ENOMEM);
168 async_answer_0(icall, ENOMEM);
169 return;
170 }
171
172 alloc.pitch = dim.x * sizeof(uint32_t);
173 alloc.off0 = 0;
174 alloc.pixels = pixels;
175
176 srvbmp = calloc(1, sizeof(ipc_gc_srv_bitmap_t));
177 if (srvbmp == NULL) {
178 as_area_destroy(pixels);
179 async_answer_0(icall, ENOMEM);
180 return;
181 }
182
183 rc = gfx_bitmap_create(srvgc->gc, &params, &alloc, &bitmap);
184 if (rc != EOK) {
185 free(srvbmp);
186 as_area_destroy(pixels);
187 async_answer_0(icall, rc);
188 return;
189 }
190
191 srvbmp->srvgc = srvgc;
192 list_append(&srvbmp->lbitmaps, &srvgc->bitmaps);
193 srvbmp->bmp = bitmap;
194 srvbmp->bmp_id = srvgc->next_bmp_id++;
195
196 /* We created the memory area by sharing it in */
197 srvbmp->myalloc = true;
198 srvbmp->pixels = pixels;
199
200 async_answer_1(icall, EOK, srvbmp->bmp_id);
201}
202
203static void gc_bitmap_create_doutput_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
204{
205 gfx_bitmap_params_t params;
206 gfx_bitmap_alloc_t alloc;
207 gfx_bitmap_t *bitmap;
208 gfx_coord2_t dim;
209 ipc_gc_srv_bitmap_t *srvbmp = NULL;
210 ipc_call_t call;
211 size_t size;
212 errno_t rc;
213
214 if (!async_data_write_receive(&call, &size)) {
215 async_answer_0(&call, EREFUSED);
216 async_answer_0(icall, EREFUSED);
217 return;
218 }
219
220 if (size != sizeof(gfx_bitmap_params_t)) {
221 async_answer_0(&call, EINVAL);
222 async_answer_0(icall, EINVAL);
223 return;
224 }
225
226 rc = async_data_write_finalize(&call, &params, size);
227 if (rc != EOK) {
228 async_answer_0(&call, rc);
229 async_answer_0(icall, rc);
230 return;
231 }
232
233 /* Bitmap dimensions */
234 gfx_coord2_subtract(&params.rect.p1, &params.rect.p0, &dim);
235
236 if (!async_share_in_receive(&call, &size)) {
237 async_answer_0(icall, EINVAL);
238 return;
239 }
240
241 /* Check size */
242 if (size != PAGES2SIZE(SIZE2PAGES(dim.x * dim.y * sizeof(uint32_t)))) {
243 async_answer_0(&call, EINVAL);
244 async_answer_0(icall, EINVAL);
245 return;
246 }
247
248 rc = gfx_bitmap_create(srvgc->gc, &params, NULL, &bitmap);
249 if (rc != EOK) {
250 async_answer_0(&call, rc);
251 async_answer_0(icall, rc);
252 return;
253 }
254
255 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
256 if (rc != EOK) {
257 gfx_bitmap_destroy(bitmap);
258 async_answer_0(&call, rc);
259 async_answer_0(icall, rc);
260 return;
261 }
262
263 rc = async_share_in_finalize(&call, alloc.pixels, AS_AREA_READ |
264 AS_AREA_WRITE | AS_AREA_CACHEABLE);
265 if (rc != EOK) {
266 gfx_bitmap_destroy(bitmap);
267 async_answer_0(icall, EIO);
268 return;
269 }
270
271 srvbmp = calloc(1, sizeof(ipc_gc_srv_bitmap_t));
272 if (srvbmp == NULL) {
273 gfx_bitmap_destroy(bitmap);
274 async_answer_0(icall, ENOMEM);
275 return;
276 }
277
278 srvbmp->srvgc = srvgc;
279 list_append(&srvbmp->lbitmaps, &srvgc->bitmaps);
280 srvbmp->bmp = bitmap;
281 srvbmp->bmp_id = srvgc->next_bmp_id++;
282
283 /* Area allocated by backing GC, we just shared it out */
284 srvbmp->myalloc = false;
285 srvbmp->pixels = alloc.pixels; // Not really needed
286
287 async_answer_1(icall, EOK, srvbmp->bmp_id);
288}
289
290static void gc_bitmap_destroy_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
291{
292 sysarg_t bmp_id;
293 ipc_gc_srv_bitmap_t *bitmap;
294 errno_t rc;
295
296 bmp_id = ipc_get_arg1(call);
297
298 bitmap = gc_bitmap_lookup(srvgc, bmp_id);
299 if (bitmap == NULL) {
300 async_answer_0(call, ENOENT);
301 return;
302 }
303
304 rc = gfx_bitmap_destroy(bitmap->bmp);
305 if (rc != EOK) {
306 async_answer_0(call, rc);
307 return;
308 }
309
310 if (bitmap->myalloc)
311 as_area_destroy(bitmap->pixels);
312
313 list_remove(&bitmap->lbitmaps);
314 free(bitmap);
315
316 async_answer_0(call, rc);
317}
318
319static void gc_bitmap_render_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
320{
321 ipc_gc_srv_bitmap_t *bitmap;
322 sysarg_t bmp_id;
323 gfx_rect_t srect;
324 gfx_coord2_t offs;
325 ipc_call_t call;
326 size_t size;
327 errno_t rc;
328
329 if (!async_data_write_receive(&call, &size)) {
330 async_answer_0(&call, EREFUSED);
331 async_answer_0(icall, EREFUSED);
332 return;
333 }
334
335 if (size != sizeof(gfx_rect_t)) {
336 async_answer_0(&call, EINVAL);
337 async_answer_0(icall, EINVAL);
338 return;
339 }
340
341 rc = async_data_write_finalize(&call, &srect, size);
342 if (rc != EOK) {
343 async_answer_0(&call, rc);
344 async_answer_0(icall, rc);
345 return;
346 }
347
348 bmp_id = ipc_get_arg1(icall);
349 offs.x = ipc_get_arg2(icall);
350 offs.y = ipc_get_arg3(icall);
351
352 bitmap = gc_bitmap_lookup(srvgc, bmp_id);
353 if (bitmap == NULL) {
354 async_answer_0(icall, ENOENT);
355 return;
356 }
357
358 rc = gfx_bitmap_render(bitmap->bmp, &srect, &offs);
359 async_answer_0(icall, rc);
360}
361
362errno_t gc_conn(ipc_call_t *icall, gfx_context_t *gc)
363{
364 ipc_gc_srv_t srvgc;
365 ipc_gc_srv_bitmap_t *bitmap;
366 link_t *link;
367
368 /* Accept the connection */
369 async_accept_0(icall);
370
371 srvgc.gc = gc;
372 list_initialize(&srvgc.bitmaps);
373 srvgc.next_bmp_id = 1;
374
375 while (true) {
376 ipc_call_t call;
377 async_get_call(&call);
378 sysarg_t method = ipc_get_imethod(&call);
379
380 if (!method) {
381 /* The other side has hung up */
382 async_answer_0(&call, EOK);
383 break;
384 }
385
386 switch (method) {
387 case GC_SET_CLIP_RECT:
388 gc_set_clip_rect_srv(&srvgc, &call);
389 break;
390 case GC_SET_CLIP_RECT_NULL:
391 gc_set_clip_rect_null_srv(&srvgc, &call);
392 break;
393 case GC_SET_RGB_COLOR:
394 gc_set_rgb_color_srv(&srvgc, &call);
395 break;
396 case GC_FILL_RECT:
397 gc_fill_rect_srv(&srvgc, &call);
398 break;
399 case GC_UPDATE:
400 gc_update_srv(&srvgc, &call);
401 break;
402 case GC_BITMAP_CREATE:
403 gc_bitmap_create_srv(&srvgc, &call);
404 break;
405 case GC_BITMAP_CREATE_DOUTPUT:
406 gc_bitmap_create_doutput_srv(&srvgc, &call);
407 break;
408 case GC_BITMAP_DESTROY:
409 gc_bitmap_destroy_srv(&srvgc, &call);
410 break;
411 case GC_BITMAP_RENDER:
412 gc_bitmap_render_srv(&srvgc, &call);
413 break;
414 default:
415 async_answer_0(&call, EINVAL);
416 break;
417 }
418 }
419
420 /*
421 * Destroy all remaining bitmaps. A client should destroy all
422 * the bitmaps before closing connection. But it could happen
423 * that the client is misbehaving or was abruptly disconnected
424 * (e.g. crashed).
425 */
426 link = list_first(&srvgc.bitmaps);
427 while (link != NULL) {
428 bitmap = list_get_instance(link, ipc_gc_srv_bitmap_t,
429 lbitmaps);
430
431 (void) gfx_bitmap_destroy(bitmap->bmp);
432 if (bitmap->myalloc)
433 as_area_destroy(bitmap->pixels);
434 list_remove(&bitmap->lbitmaps);
435 free(bitmap);
436
437 link = list_first(&srvgc.bitmaps);
438 }
439
440 return EOK;
441}
442
443static ipc_gc_srv_bitmap_t *gc_bitmap_lookup(ipc_gc_srv_t *srvgc,
444 sysarg_t bmp_id)
445{
446 link_t *link;
447 ipc_gc_srv_bitmap_t *bmp;
448
449 link = list_first(&srvgc->bitmaps);
450 while (link != NULL) {
451 bmp = list_get_instance(link, ipc_gc_srv_bitmap_t, lbitmaps);
452 if (bmp->bmp_id == bmp_id)
453 return bmp;
454 link = list_next(link, &srvgc->bitmaps);
455 }
456
457 return NULL;
458}
459
460/** @}
461 */
Note: See TracBrowser for help on using the repository browser.