source: mainline/uspace/srv/hid/display/test/cursor.c@ 0da03df

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0da03df was 62018a0, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Properly clip cursor when repainting a part of the display

Not doing so was causing excessively large update rectangles, increasing
CPU usage and display artifacts.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * Copyright (c) 2020 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/context.h>
31#include <stdbool.h>
32#include <pcut/pcut.h>
33
34#include "../cursor.h"
35#include "../cursimg.h"
36#include "../ddev.h"
37#include "../display.h"
38#include "../display.h"
39
40PCUT_INIT;
41
42PCUT_TEST_SUITE(cursor);
43
44static errno_t dummy_bitmap_create(void *, gfx_bitmap_params_t *,
45 gfx_bitmap_alloc_t *, void **);
46static errno_t dummy_bitmap_destroy(void *);
47static errno_t dummy_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
48static errno_t dummy_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
49
50static gfx_context_ops_t dummy_ops = {
51 .bitmap_create = dummy_bitmap_create,
52 .bitmap_destroy = dummy_bitmap_destroy,
53 .bitmap_render = dummy_bitmap_render,
54 .bitmap_get_alloc = dummy_bitmap_get_alloc
55};
56
57typedef struct {
58 bool render_called;
59} test_response_t;
60
61typedef struct {
62 test_response_t *resp;
63 gfx_bitmap_alloc_t alloc;
64} dummy_bitmap_t;
65
66/** Test ds_cursor_create(), ds_cursor_destroy(). */
67PCUT_TEST(cursor_create_destroy)
68{
69 ds_display_t *disp;
70 ds_cursor_t *cursor;
71 errno_t rc;
72
73 rc = ds_display_create(NULL, df_none, &disp);
74 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
75
76 rc = ds_cursor_create(disp, &ds_cursimg[dcurs_arrow].rect,
77 ds_cursimg[dcurs_arrow].image, &cursor);
78 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
79
80 ds_cursor_destroy(cursor);
81 ds_display_destroy(disp);
82}
83
84/** Test ds_cursor_paint() renders the cursor. */
85PCUT_TEST(cursor_paint_render)
86{
87 gfx_context_t *gc;
88 ds_display_t *disp;
89 ds_cursor_t *cursor;
90 ds_ddev_t *ddev;
91 ddev_info_t ddinfo;
92 gfx_coord2_t pos;
93 test_response_t resp;
94 errno_t rc;
95
96 rc = gfx_context_new(&dummy_ops, &resp, &gc);
97 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
98
99 rc = ds_display_create(gc, df_none, &disp);
100 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
101
102 ddev_info_init(&ddinfo);
103
104 rc = ds_ddev_create(disp, NULL, &ddinfo, NULL, 0, gc, &ddev);
105 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
106
107 rc = ds_cursor_create(disp, &ds_cursimg[dcurs_arrow].rect,
108 ds_cursimg[dcurs_arrow].image, &cursor);
109 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
110
111 resp.render_called = false;
112
113 pos.x = 0;
114 pos.y = 0;
115 ds_cursor_paint(cursor, &pos, NULL);
116
117 PCUT_ASSERT_TRUE(resp.render_called);
118
119 ds_cursor_destroy(cursor);
120 ds_display_destroy(disp);
121}
122
123/** Test ds_cursor_paint() optimizes out rendering using clipping rectangle. */
124PCUT_TEST(cursor_paint_norender)
125{
126 gfx_context_t *gc;
127 ds_display_t *disp;
128 ds_cursor_t *cursor;
129 ds_ddev_t *ddev;
130 ddev_info_t ddinfo;
131 gfx_coord2_t pos;
132 gfx_rect_t clip;
133 test_response_t resp;
134 errno_t rc;
135
136 rc = gfx_context_new(&dummy_ops, &resp, &gc);
137 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
138
139 rc = ds_display_create(gc, df_none, &disp);
140 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
141
142 ddev_info_init(&ddinfo);
143
144 rc = ds_ddev_create(disp, NULL, &ddinfo, NULL, 0, gc, &ddev);
145 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
146
147 rc = ds_cursor_create(disp, &ds_cursimg[dcurs_arrow].rect,
148 ds_cursimg[dcurs_arrow].image, &cursor);
149 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
150
151 resp.render_called = false;
152
153 /*
154 * Clipping rectangle not intersecting the area where cursor is to
155 * be rendered
156 */
157 clip.p0.x = 100;
158 clip.p0.y = 100;
159 clip.p1.x = 150;
160 clip.p1.y = 150;
161
162 pos.x = 0;
163 pos.y = 0;
164 ds_cursor_paint(cursor, &pos, &clip);
165
166 /* Rendering should have been optimized out */
167 PCUT_ASSERT_FALSE(resp.render_called);
168
169 ds_cursor_destroy(cursor);
170 ds_display_destroy(disp);
171}
172
173/** Test ds_cursor_get_rect() */
174PCUT_TEST(cursor_get_rect)
175{
176 ds_display_t *disp;
177 ds_cursor_t *cursor;
178 gfx_coord2_t pos1, pos2;
179 gfx_rect_t rect1, rect2;
180 errno_t rc;
181
182 rc = ds_display_create(NULL, df_none, &disp);
183 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
184
185 rc = ds_cursor_create(disp, &ds_cursimg[dcurs_arrow].rect,
186 ds_cursimg[dcurs_arrow].image, &cursor);
187 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
188
189 pos1.x = 10;
190 pos1.y = 11;
191
192 pos2.x = 22;
193 pos2.y = 23;
194
195 ds_cursor_get_rect(cursor, &pos1, &rect1);
196 ds_cursor_get_rect(cursor, &pos2, &rect2);
197
198 PCUT_ASSERT_FALSE(gfx_rect_is_empty(&rect1));
199 PCUT_ASSERT_FALSE(gfx_rect_is_empty(&rect2));
200
201 PCUT_ASSERT_INT_EQUALS(pos2.x - pos1.x, rect2.p0.x - rect1.p0.x);
202 PCUT_ASSERT_INT_EQUALS(pos2.y - pos1.y, rect2.p0.y - rect1.p0.y);
203 PCUT_ASSERT_INT_EQUALS(pos2.x - pos1.x, rect2.p1.x - rect1.p1.x);
204 PCUT_ASSERT_INT_EQUALS(pos2.y - pos1.y, rect2.p1.y - rect1.p1.y);
205
206 ds_cursor_destroy(cursor);
207 ds_display_destroy(disp);
208}
209
210static errno_t dummy_bitmap_create(void *arg, gfx_bitmap_params_t *params,
211 gfx_bitmap_alloc_t *alloc, void **rbm)
212{
213 test_response_t *resp = (test_response_t *) arg;
214 dummy_bitmap_t *bm;
215 gfx_coord2_t dims;
216
217 gfx_rect_dims(&params->rect, &dims);
218 bm = calloc(1, sizeof(dummy_bitmap_t));
219 if (bm == NULL)
220 return ENOMEM;
221
222 bm->resp = resp;
223 bm->alloc.pitch = dims.x * sizeof(uint32_t);
224 bm->alloc.off0 = 0;
225
226 bm->alloc.pixels = malloc(bm->alloc.pitch * dims.y * sizeof(uint32_t));
227 if (bm->alloc.pixels == NULL) {
228 free(bm);
229 return ENOMEM;
230 }
231
232 *rbm = (void *) bm;
233 return EOK;
234}
235
236static errno_t dummy_bitmap_destroy(void *arg)
237{
238 dummy_bitmap_t *bm = (dummy_bitmap_t *) arg;
239
240 free(bm);
241 return EOK;
242}
243
244static errno_t dummy_bitmap_render(void *arg, gfx_rect_t *rect,
245 gfx_coord2_t *dpos)
246{
247 dummy_bitmap_t *bm = (dummy_bitmap_t *) arg;
248
249 bm->resp->render_called = true;
250 return EOK;
251}
252
253static errno_t dummy_bitmap_get_alloc(void *arg, gfx_bitmap_alloc_t *alloc)
254{
255 dummy_bitmap_t *bm = (dummy_bitmap_t *) arg;
256
257 *alloc = bm->alloc;
258 return EOK;
259}
260
261PCUT_EXPORT(cursor);
Note: See TracBrowser for help on using the repository browser.