source: mainline/uspace/lib/memgfx/test/memgfx.c

Last change on this file was 1215db9, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Memory GC needs to be able to forward cursor control

  • Property mode set to 100644
File size: 13.1 KB
RevLine 
[d8e2485]1/*
[2ab8ab3]2 * Copyright (c) 2021 Jiri Svoboda
[d8e2485]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#include <errno.h>
30#include <gfx/bitmap.h>
31#include <gfx/color.h>
32#include <gfx/coord.h>
33#include <gfx/context.h>
[1215db9]34#include <gfx/cursor.h>
[d8e2485]35#include <gfx/render.h>
36#include <io/pixelmap.h>
[f8375f7]37#include <mem.h>
[d8e2485]38#include <memgfx/memgc.h>
39#include <pcut/pcut.h>
40
41PCUT_INIT;
42
43PCUT_TEST_SUITE(memgfx);
44
[2ab8ab3]45static void test_invalidate_rect(void *arg, gfx_rect_t *rect);
46static void test_update(void *arg);
[1215db9]47static errno_t test_cursor_get_pos(void *arg, gfx_coord2_t *);
48static errno_t test_cursor_set_pos(void *arg, gfx_coord2_t *);
49static errno_t test_cursor_set_visible(void *arg, bool);
50
51static mem_gc_cb_t test_mem_gc_cb = {
52 .invalidate = test_invalidate_rect,
53 .update = test_update,
54 .cursor_get_pos = test_cursor_get_pos,
55 .cursor_set_pos = test_cursor_set_pos,
56 .cursor_set_visible = test_cursor_set_visible
57};
[f8375f7]58
59typedef struct {
[1215db9]60 /** Return code to return */
61 errno_t rc;
[2ab8ab3]62 /** True if invalidate was called */
63 bool invalidate_called;
64 /** Invalidate rectangle */
65 gfx_rect_t inv_rect;
[f8375f7]66 /** True if update was called */
67 bool update_called;
[1215db9]68 /** True if cursor_get_pos was called */
69 bool cursor_get_pos_called;
70 /** Position to return from cursor_get_pos */
71 gfx_coord2_t get_pos_pos;
72 /** True if cursor_set_pos was called */
73 bool cursor_set_pos_called;
74 /** Position passed to cursor_set_pos */
75 gfx_coord2_t set_pos_pos;
76 /** True if cursor_set_visible was called */
77 bool cursor_set_visible_called;
78 /** Value passed to cursor_set_visible */
79 bool set_visible_vis;
[2ab8ab3]80} test_resp_t;
[f8375f7]81
[d8e2485]82/** Test creating and deleting a memory GC */
83PCUT_TEST(create_delete)
84{
85 mem_gc_t *mgc;
86 gfx_rect_t rect;
87 gfx_bitmap_alloc_t alloc;
88 errno_t rc;
89
90 rect.p0.x = 0;
91 rect.p0.y = 0;
92 rect.p1.x = 10;
93 rect.p1.y = 10;
94
95 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
96 alloc.off0 = 0;
97 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
98 PCUT_ASSERT_NOT_NULL(alloc.pixels);
99
[1215db9]100 rc = mem_gc_create(&rect, &alloc, NULL, NULL, &mgc);
[d8e2485]101 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
102
103 mem_gc_delete(mgc);
104 free(alloc.pixels);
105}
106
107/** Test filling a rectangle in memory GC */
108PCUT_TEST(fill_rect)
109{
110 mem_gc_t *mgc;
111 gfx_rect_t rect;
112 gfx_rect_t frect;
113 gfx_bitmap_alloc_t alloc;
114 gfx_context_t *gc;
115 gfx_color_t *color;
116 gfx_coord2_t pos;
117 pixelmap_t pixelmap;
118 pixel_t pixel;
119 pixel_t expected;
[2ab8ab3]120 test_resp_t resp;
[d8e2485]121 errno_t rc;
122
123 /* Bounding rectangle for memory GC */
124 rect.p0.x = 0;
125 rect.p0.y = 0;
126 rect.p1.x = 10;
127 rect.p1.y = 10;
128
129 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
130 alloc.off0 = 0;
131 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
132 PCUT_ASSERT_NOT_NULL(alloc.pixels);
133
[1215db9]134 rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
[d8e2485]135 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
136
137 gc = mem_gc_get_ctx(mgc);
138 PCUT_ASSERT_NOT_NULL(gc);
139
140 /* Fill a rectangle */
141
142 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0, &color);
143 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
144
145 rc = gfx_set_color(gc, color);
146 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
147
148 frect.p0.x = 2;
149 frect.p0.y = 2;
150 frect.p1.x = 5;
151 frect.p1.y = 5;
152
[2ab8ab3]153 memset(&resp, 0, sizeof(resp));
[f8375f7]154
[d8e2485]155 rc = gfx_fill_rect(gc, &frect);
156 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
157
158 pixelmap.width = rect.p1.x - rect.p0.x;
159 pixelmap.height = rect.p1.y - rect.p0.y;
160 pixelmap.data = alloc.pixels;
161
162 /* Check that the pixels of the rectangle are set and no others are */
163 for (pos.y = rect.p0.y; pos.y < rect.p1.y; pos.y++) {
164 for (pos.x = rect.p0.x; pos.x < rect.p1.x; pos.x++) {
165 pixel = pixelmap_get_pixel(&pixelmap, pos.x, pos.y);
166 expected = gfx_pix_inside_rect(&pos, &frect) ?
167 PIXEL(0, 255, 255, 0) : PIXEL(0, 0, 0, 0);
168 PCUT_ASSERT_INT_EQUALS(expected, pixel);
169 }
170 }
171
[2ab8ab3]172 /* Check that the invalidate rect is equal to the filled rect */
173 PCUT_ASSERT_TRUE(resp.invalidate_called);
174 PCUT_ASSERT_INT_EQUALS(frect.p0.x, resp.inv_rect.p0.x);
175 PCUT_ASSERT_INT_EQUALS(frect.p0.y, resp.inv_rect.p0.y);
176 PCUT_ASSERT_INT_EQUALS(frect.p1.x, resp.inv_rect.p1.x);
177 PCUT_ASSERT_INT_EQUALS(frect.p1.y, resp.inv_rect.p1.y);
[d8e2485]178
179 /* TODO: Check clipping once memgc can support pitch != width etc. */
180
181 mem_gc_delete(mgc);
182 free(alloc.pixels);
183}
184
185/** Test rendering a bitmap in memory GC */
186PCUT_TEST(bitmap_render)
187{
188 mem_gc_t *mgc;
189 gfx_rect_t rect;
190 gfx_bitmap_alloc_t alloc;
191 gfx_context_t *gc;
192 gfx_coord2_t pos;
193 gfx_bitmap_params_t params;
194 gfx_bitmap_alloc_t balloc;
195 gfx_bitmap_t *bitmap;
196 pixelmap_t bpmap;
197 pixelmap_t dpmap;
198 pixel_t pixel;
199 pixel_t expected;
[2ab8ab3]200 test_resp_t resp;
[d8e2485]201 errno_t rc;
202
203 /* Bounding rectangle for memory GC */
204 rect.p0.x = 0;
205 rect.p0.y = 0;
206 rect.p1.x = 10;
207 rect.p1.y = 10;
208
209 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
210 alloc.off0 = 0;
211 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
212 PCUT_ASSERT_NOT_NULL(alloc.pixels);
213
[1215db9]214 rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
[d8e2485]215 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
216
217 gc = mem_gc_get_ctx(mgc);
218 PCUT_ASSERT_NOT_NULL(gc);
219
220 /* Create bitmap */
221
[2ab8ab3]222 gfx_bitmap_params_init(&params);
[d8e2485]223 params.rect.p0.x = 0;
224 params.rect.p0.y = 0;
225 params.rect.p1.x = 6;
226 params.rect.p1.y = 6;
227
228 /* TODO Test client allocation */
229 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
230 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
231
232 rc = gfx_bitmap_get_alloc(bitmap, &balloc);
233 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
234
235 bpmap.width = params.rect.p1.x - params.rect.p0.x;
236 bpmap.height = params.rect.p1.y - params.rect.p0.y;
237 bpmap.data = balloc.pixels;
238
239 /* Fill bitmap pixels with constant color */
240 for (pos.y = params.rect.p0.y; pos.y < params.rect.p1.y; pos.y++) {
241 for (pos.x = params.rect.p0.x; pos.x < params.rect.p1.x; pos.x++) {
242 pixelmap_put_pixel(&bpmap, pos.x, pos.y,
243 PIXEL(0, 255, 255, 0));
244 }
245 }
246
247 dpmap.width = rect.p1.x - rect.p0.x;
248 dpmap.height = rect.p1.y - rect.p0.y;
249 dpmap.data = alloc.pixels;
250
[2ab8ab3]251 memset(&resp, 0, sizeof(resp));
[f8375f7]252
[d8e2485]253 /* Render the bitmap */
254 /* TODO Test rendering sub-rectangle */
255 /* TODO Test rendering with offset */
256 rc = gfx_bitmap_render(bitmap, NULL, NULL);
257 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
258
259 /* Check that the pixels of the rectangle are set and no others are */
260 for (pos.y = rect.p0.y; pos.y < rect.p1.y; pos.y++) {
261 for (pos.x = rect.p0.x; pos.x < rect.p1.x; pos.x++) {
262 pixel = pixelmap_get_pixel(&dpmap, pos.x, pos.y);
263 expected = gfx_pix_inside_rect(&pos, &params.rect) ?
264 PIXEL(0, 255, 255, 0) : PIXEL(0, 0, 0, 0);
265 PCUT_ASSERT_INT_EQUALS(expected, pixel);
266 }
267 }
268
[2ab8ab3]269 /* Check that the invalidate rect is equal to the filled rect */
270 PCUT_ASSERT_TRUE(resp.invalidate_called);
271 PCUT_ASSERT_INT_EQUALS(params.rect.p0.x, resp.inv_rect.p0.x);
272 PCUT_ASSERT_INT_EQUALS(params.rect.p0.y, resp.inv_rect.p0.y);
273 PCUT_ASSERT_INT_EQUALS(params.rect.p1.x, resp.inv_rect.p1.x);
274 PCUT_ASSERT_INT_EQUALS(params.rect.p1.y, resp.inv_rect.p1.y);
[d8e2485]275
276 /* TODO: Check clipping once memgc can support pitch != width etc. */
277
278 mem_gc_delete(mgc);
279 free(alloc.pixels);
280}
281
[2ab8ab3]282/** Test gfx_update() on a memory GC */
283PCUT_TEST(gfx_update)
284{
285 mem_gc_t *mgc;
286 gfx_rect_t rect;
287 gfx_bitmap_alloc_t alloc;
288 gfx_context_t *gc;
289 test_resp_t resp;
290 errno_t rc;
291
292 /* Bounding rectangle for memory GC */
293 rect.p0.x = 0;
294 rect.p0.y = 0;
295 rect.p1.x = 10;
296 rect.p1.y = 10;
297
298 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
299 alloc.off0 = 0;
300 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
301 PCUT_ASSERT_NOT_NULL(alloc.pixels);
302
[1215db9]303 rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
[2ab8ab3]304 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
305
306 gc = mem_gc_get_ctx(mgc);
307 PCUT_ASSERT_NOT_NULL(gc);
308
309 memset(&resp, 0, sizeof(resp));
310 PCUT_ASSERT_FALSE(resp.update_called);
311
312 gfx_update(gc);
313 PCUT_ASSERT_TRUE(resp.update_called);
314
315 mem_gc_delete(mgc);
316 free(alloc.pixels);
317}
318
[1215db9]319/** Test gfx_cursor_get_pos() on a memory GC */
320PCUT_TEST(gfx_cursor_get_pos)
321{
322 mem_gc_t *mgc;
323 gfx_rect_t rect;
324 gfx_bitmap_alloc_t alloc;
325 gfx_coord2_t pos;
326 gfx_context_t *gc;
327 test_resp_t resp;
328 errno_t rc;
329
330 /* Bounding rectangle for memory GC */
331 rect.p0.x = 0;
332 rect.p0.y = 0;
333 rect.p1.x = 10;
334 rect.p1.y = 10;
335
336 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
337 alloc.off0 = 0;
338 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
339 PCUT_ASSERT_NOT_NULL(alloc.pixels);
340
341 rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
342 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
343
344 gc = mem_gc_get_ctx(mgc);
345 PCUT_ASSERT_NOT_NULL(gc);
346
347 memset(&resp, 0, sizeof(resp));
348 resp.rc = EOK;
349 resp.get_pos_pos.x = 1;
350 resp.get_pos_pos.y = 2;
351 PCUT_ASSERT_FALSE(resp.cursor_get_pos_called);
352
353 rc = gfx_cursor_get_pos(gc, &pos);
354 PCUT_ASSERT_TRUE(resp.cursor_get_pos_called);
355 PCUT_ASSERT_INT_EQUALS(resp.get_pos_pos.x, pos.x);
356 PCUT_ASSERT_INT_EQUALS(resp.get_pos_pos.y, pos.y);
357
358 mem_gc_delete(mgc);
359 free(alloc.pixels);
360}
361
362/** Test gfx_cursor_set_pos() on a memory GC */
363PCUT_TEST(gfx_cursor_set_pos)
364{
365 mem_gc_t *mgc;
366 gfx_rect_t rect;
367 gfx_bitmap_alloc_t alloc;
368 gfx_coord2_t pos;
369 gfx_context_t *gc;
370 test_resp_t resp;
371 errno_t rc;
372
373 /* Bounding rectangle for memory GC */
374 rect.p0.x = 0;
375 rect.p0.y = 0;
376 rect.p1.x = 10;
377 rect.p1.y = 10;
378
379 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
380 alloc.off0 = 0;
381 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
382 PCUT_ASSERT_NOT_NULL(alloc.pixels);
383
384 rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
385 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
386
387 gc = mem_gc_get_ctx(mgc);
388 PCUT_ASSERT_NOT_NULL(gc);
389
390 memset(&resp, 0, sizeof(resp));
391 resp.rc = EOK;
392 pos.x = 1;
393 pos.y = 2;
394 PCUT_ASSERT_FALSE(resp.cursor_set_pos_called);
395
396 rc = gfx_cursor_set_pos(gc, &pos);
397 PCUT_ASSERT_TRUE(resp.cursor_set_pos_called);
398 PCUT_ASSERT_INT_EQUALS(pos.x, resp.set_pos_pos.x);
399 PCUT_ASSERT_INT_EQUALS(pos.y, resp.set_pos_pos.y);
400
401 mem_gc_delete(mgc);
402 free(alloc.pixels);
403}
404
405/** Test gfx_cursor_set_visible() on a memory GC */
406PCUT_TEST(gfx_cursor_set_visible)
407{
408 mem_gc_t *mgc;
409 gfx_rect_t rect;
410 gfx_bitmap_alloc_t alloc;
411 gfx_context_t *gc;
412 test_resp_t resp;
413 errno_t rc;
414
415 /* Bounding rectangle for memory GC */
416 rect.p0.x = 0;
417 rect.p0.y = 0;
418 rect.p1.x = 10;
419 rect.p1.y = 10;
420
421 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
422 alloc.off0 = 0;
423 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
424 PCUT_ASSERT_NOT_NULL(alloc.pixels);
425
426 rc = mem_gc_create(&rect, &alloc, &test_mem_gc_cb, &resp, &mgc);
427 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
428
429 gc = mem_gc_get_ctx(mgc);
430 PCUT_ASSERT_NOT_NULL(gc);
431
432 memset(&resp, 0, sizeof(resp));
433 resp.rc = EOK;
434 PCUT_ASSERT_FALSE(resp.cursor_set_visible_called);
435
436 rc = gfx_cursor_set_visible(gc, true);
437 PCUT_ASSERT_TRUE(resp.cursor_set_visible_called);
438 PCUT_ASSERT_TRUE(resp.set_visible_vis);
439
440 resp.cursor_set_visible_called = false;
441
442 rc = gfx_cursor_set_visible(gc, false);
443 PCUT_ASSERT_TRUE(resp.cursor_set_visible_called);
444 PCUT_ASSERT_FALSE(resp.set_visible_vis);
445
446 mem_gc_delete(mgc);
447 free(alloc.pixels);
448}
449
[2ab8ab3]450/** Called by memory GC when a rectangle is modified. */
451static void test_invalidate_rect(void *arg, gfx_rect_t *rect)
452{
453 test_resp_t *resp = (test_resp_t *)arg;
454
455 resp->invalidate_called = true;
456 resp->inv_rect = *rect;
457}
458
459/** Called by memory GC when update is called. */
460static void test_update(void *arg)
[f8375f7]461{
[2ab8ab3]462 test_resp_t *resp = (test_resp_t *)arg;
[f8375f7]463
[2ab8ab3]464 resp->update_called = true;
[f8375f7]465}
466
[1215db9]467/** Called by memory GC when cursor_get_pos is called. */
468static errno_t test_cursor_get_pos(void *arg, gfx_coord2_t *pos)
469{
470 test_resp_t *resp = (test_resp_t *)arg;
471
472 resp->cursor_get_pos_called = true;
473 *pos = resp->get_pos_pos;
474 return resp->rc;
475}
476
477/** Called by memory GC when cursor_set_pos is called. */
478static errno_t test_cursor_set_pos(void *arg, gfx_coord2_t *pos)
479{
480 test_resp_t *resp = (test_resp_t *)arg;
481
482 resp->cursor_set_pos_called = true;
483 resp->set_pos_pos = *pos;
484 return resp->rc;
485}
486
487/** Called by memory GC when cursor_set_visible is called. */
488static errno_t test_cursor_set_visible(void *arg, bool visible)
489{
490 test_resp_t *resp = (test_resp_t *)arg;
491
492 resp->cursor_set_visible_called = true;
493 resp->set_visible_vis = visible;
494 return resp->rc;
495}
496
[d8e2485]497PCUT_EXPORT(memgfx);
Note: See TracBrowser for help on using the repository browser.