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