source: mainline/uspace/lib/memgfx/test/memgfx.c@ 5bfeeaa

Last change on this file since 5bfeeaa 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: 8.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#include <errno.h>
30#include <gfx/bitmap.h>
31#include <gfx/color.h>
32#include <gfx/coord.h>
33#include <gfx/context.h>
34#include <gfx/render.h>
35#include <io/pixelmap.h>
36#include <mem.h>
37#include <memgfx/memgc.h>
38#include <pcut/pcut.h>
39
40PCUT_INIT;
41
42PCUT_TEST_SUITE(memgfx);
43
44static void test_invalidate_rect(void *arg, gfx_rect_t *rect);
45static void test_update(void *arg);
46
47typedef struct {
48 /** True if invalidate was called */
49 bool invalidate_called;
50 /** Invalidate rectangle */
51 gfx_rect_t inv_rect;
52 /** True if update was called */
53 bool update_called;
54} test_resp_t;
55
56/** Test creating and deleting a memory GC */
57PCUT_TEST(create_delete)
58{
59 mem_gc_t *mgc;
60 gfx_rect_t rect;
61 gfx_bitmap_alloc_t alloc;
62 errno_t rc;
63
64 rect.p0.x = 0;
65 rect.p0.y = 0;
66 rect.p1.x = 10;
67 rect.p1.y = 10;
68
69 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
70 alloc.off0 = 0;
71 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
72 PCUT_ASSERT_NOT_NULL(alloc.pixels);
73
74 rc = mem_gc_create(&rect, &alloc, NULL, NULL, NULL, &mgc);
75 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
76
77 mem_gc_delete(mgc);
78 free(alloc.pixels);
79}
80
81/** Test filling a rectangle in memory GC */
82PCUT_TEST(fill_rect)
83{
84 mem_gc_t *mgc;
85 gfx_rect_t rect;
86 gfx_rect_t frect;
87 gfx_bitmap_alloc_t alloc;
88 gfx_context_t *gc;
89 gfx_color_t *color;
90 gfx_coord2_t pos;
91 pixelmap_t pixelmap;
92 pixel_t pixel;
93 pixel_t expected;
94 test_resp_t resp;
95 errno_t rc;
96
97 /* Bounding rectangle for memory GC */
98 rect.p0.x = 0;
99 rect.p0.y = 0;
100 rect.p1.x = 10;
101 rect.p1.y = 10;
102
103 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
104 alloc.off0 = 0;
105 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
106 PCUT_ASSERT_NOT_NULL(alloc.pixels);
107
108 rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
109 test_update, &resp, &mgc);
110 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
111
112 gc = mem_gc_get_ctx(mgc);
113 PCUT_ASSERT_NOT_NULL(gc);
114
115 /* Fill a rectangle */
116
117 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0, &color);
118 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
119
120 rc = gfx_set_color(gc, color);
121 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
122
123 frect.p0.x = 2;
124 frect.p0.y = 2;
125 frect.p1.x = 5;
126 frect.p1.y = 5;
127
128 memset(&resp, 0, sizeof(resp));
129
130 rc = gfx_fill_rect(gc, &frect);
131 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
132
133 pixelmap.width = rect.p1.x - rect.p0.x;
134 pixelmap.height = rect.p1.y - rect.p0.y;
135 pixelmap.data = alloc.pixels;
136
137 /* Check that the pixels of the rectangle are set and no others are */
138 for (pos.y = rect.p0.y; pos.y < rect.p1.y; pos.y++) {
139 for (pos.x = rect.p0.x; pos.x < rect.p1.x; pos.x++) {
140 pixel = pixelmap_get_pixel(&pixelmap, pos.x, pos.y);
141 expected = gfx_pix_inside_rect(&pos, &frect) ?
142 PIXEL(0, 255, 255, 0) : PIXEL(0, 0, 0, 0);
143 PCUT_ASSERT_INT_EQUALS(expected, pixel);
144 }
145 }
146
147 /* Check that the invalidate rect is equal to the filled rect */
148 PCUT_ASSERT_TRUE(resp.invalidate_called);
149 PCUT_ASSERT_INT_EQUALS(frect.p0.x, resp.inv_rect.p0.x);
150 PCUT_ASSERT_INT_EQUALS(frect.p0.y, resp.inv_rect.p0.y);
151 PCUT_ASSERT_INT_EQUALS(frect.p1.x, resp.inv_rect.p1.x);
152 PCUT_ASSERT_INT_EQUALS(frect.p1.y, resp.inv_rect.p1.y);
153
154 /* TODO: Check clipping once memgc can support pitch != width etc. */
155
156 mem_gc_delete(mgc);
157 free(alloc.pixels);
158}
159
160/** Test rendering a bitmap in memory GC */
161PCUT_TEST(bitmap_render)
162{
163 mem_gc_t *mgc;
164 gfx_rect_t rect;
165 gfx_bitmap_alloc_t alloc;
166 gfx_context_t *gc;
167 gfx_coord2_t pos;
168 gfx_bitmap_params_t params;
169 gfx_bitmap_alloc_t balloc;
170 gfx_bitmap_t *bitmap;
171 pixelmap_t bpmap;
172 pixelmap_t dpmap;
173 pixel_t pixel;
174 pixel_t expected;
175 test_resp_t resp;
176 errno_t rc;
177
178 /* Bounding rectangle for memory GC */
179 rect.p0.x = 0;
180 rect.p0.y = 0;
181 rect.p1.x = 10;
182 rect.p1.y = 10;
183
184 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
185 alloc.off0 = 0;
186 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
187 PCUT_ASSERT_NOT_NULL(alloc.pixels);
188
189 rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
190 test_update, &resp, &mgc);
191 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
192
193 gc = mem_gc_get_ctx(mgc);
194 PCUT_ASSERT_NOT_NULL(gc);
195
196 /* Create bitmap */
197
198 gfx_bitmap_params_init(&params);
199 params.rect.p0.x = 0;
200 params.rect.p0.y = 0;
201 params.rect.p1.x = 6;
202 params.rect.p1.y = 6;
203
204 /* TODO Test client allocation */
205 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
206 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
207
208 rc = gfx_bitmap_get_alloc(bitmap, &balloc);
209 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
210
211 bpmap.width = params.rect.p1.x - params.rect.p0.x;
212 bpmap.height = params.rect.p1.y - params.rect.p0.y;
213 bpmap.data = balloc.pixels;
214
215 /* Fill bitmap pixels with constant color */
216 for (pos.y = params.rect.p0.y; pos.y < params.rect.p1.y; pos.y++) {
217 for (pos.x = params.rect.p0.x; pos.x < params.rect.p1.x; pos.x++) {
218 pixelmap_put_pixel(&bpmap, pos.x, pos.y,
219 PIXEL(0, 255, 255, 0));
220 }
221 }
222
223 dpmap.width = rect.p1.x - rect.p0.x;
224 dpmap.height = rect.p1.y - rect.p0.y;
225 dpmap.data = alloc.pixels;
226
227 memset(&resp, 0, sizeof(resp));
228
229 /* Render the bitmap */
230 /* TODO Test rendering sub-rectangle */
231 /* TODO Test rendering with offset */
232 rc = gfx_bitmap_render(bitmap, NULL, NULL);
233 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
234
235 /* Check that the pixels of the rectangle are set and no others are */
236 for (pos.y = rect.p0.y; pos.y < rect.p1.y; pos.y++) {
237 for (pos.x = rect.p0.x; pos.x < rect.p1.x; pos.x++) {
238 pixel = pixelmap_get_pixel(&dpmap, pos.x, pos.y);
239 expected = gfx_pix_inside_rect(&pos, &params.rect) ?
240 PIXEL(0, 255, 255, 0) : PIXEL(0, 0, 0, 0);
241 PCUT_ASSERT_INT_EQUALS(expected, pixel);
242 }
243 }
244
245 /* Check that the invalidate rect is equal to the filled rect */
246 PCUT_ASSERT_TRUE(resp.invalidate_called);
247 PCUT_ASSERT_INT_EQUALS(params.rect.p0.x, resp.inv_rect.p0.x);
248 PCUT_ASSERT_INT_EQUALS(params.rect.p0.y, resp.inv_rect.p0.y);
249 PCUT_ASSERT_INT_EQUALS(params.rect.p1.x, resp.inv_rect.p1.x);
250 PCUT_ASSERT_INT_EQUALS(params.rect.p1.y, resp.inv_rect.p1.y);
251
252 /* TODO: Check clipping once memgc can support pitch != width etc. */
253
254 mem_gc_delete(mgc);
255 free(alloc.pixels);
256}
257
258/** Test gfx_update() on a memory GC */
259PCUT_TEST(gfx_update)
260{
261 mem_gc_t *mgc;
262 gfx_rect_t rect;
263 gfx_bitmap_alloc_t alloc;
264 gfx_context_t *gc;
265 test_resp_t resp;
266 errno_t rc;
267
268 /* Bounding rectangle for memory GC */
269 rect.p0.x = 0;
270 rect.p0.y = 0;
271 rect.p1.x = 10;
272 rect.p1.y = 10;
273
274 alloc.pitch = (rect.p1.x - rect.p0.x) * sizeof(uint32_t);
275 alloc.off0 = 0;
276 alloc.pixels = calloc(1, alloc.pitch * (rect.p1.y - rect.p0.y));
277 PCUT_ASSERT_NOT_NULL(alloc.pixels);
278
279 rc = mem_gc_create(&rect, &alloc, test_invalidate_rect,
280 test_update, &resp, &mgc);
281 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
282
283 gc = mem_gc_get_ctx(mgc);
284 PCUT_ASSERT_NOT_NULL(gc);
285
286 memset(&resp, 0, sizeof(resp));
287 PCUT_ASSERT_FALSE(resp.update_called);
288
289 gfx_update(gc);
290 PCUT_ASSERT_TRUE(resp.update_called);
291
292 mem_gc_delete(mgc);
293 free(alloc.pixels);
294}
295
296/** Called by memory GC when a rectangle is modified. */
297static void test_invalidate_rect(void *arg, gfx_rect_t *rect)
298{
299 test_resp_t *resp = (test_resp_t *)arg;
300
301 resp->invalidate_called = true;
302 resp->inv_rect = *rect;
303}
304
305/** Called by memory GC when update is called. */
306static void test_update(void *arg)
307{
308 test_resp_t *resp = (test_resp_t *)arg;
309
310 resp->update_called = true;
311}
312
313PCUT_EXPORT(memgfx);
Note: See TracBrowser for help on using the repository browser.