1 /*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23 #include <gtest/gtest.h>
24 #include <signal.h>
25 #include <setjmp.h>
26
27 #include "glxclient.h"
28 #include "glx_error.h"
29
30 extern bool GetGLXScreenConfigs_called;
31 extern struct glx_screen *psc;
32
33 struct attribute_test_vector {
34 const char *string;
35 int value;
36 };
37
38 #define E(x) { # x, x }
39
40
41
42 static bool got_sigsegv;
43 static jmp_buf jmp;
44
45 static void
sigsegv_handler(int sig)46 sigsegv_handler(int sig)
47 {
48 (void) sig;
49 got_sigsegv = true;
50 longjmp(jmp, 1);
51 }
52
53 static bool query_renderer_string_called = false;
54 static bool query_renderer_integer_called = false;
55
56 static int
fake_query_renderer_integer(struct glx_screen * psc,int attribute,unsigned int * value)57 fake_query_renderer_integer(struct glx_screen *psc, int attribute,
58 unsigned int *value)
59 {
60 (void) psc;
61 (void) attribute;
62 (void) value;
63
64 query_renderer_integer_called = true;
65
66 return -1;
67 }
68
69 static int
fake_query_renderer_string(struct glx_screen * psc,int attribute,const char ** value)70 fake_query_renderer_string(struct glx_screen *psc, int attribute,
71 const char **value)
72 {
73 (void) psc;
74 (void) attribute;
75 (void) value;
76
77 query_renderer_string_called = true;
78
79 return -1;
80 }
81
82 struct glx_screen_vtable fake_vtable = {
83 NULL,
84 NULL,
85 fake_query_renderer_integer,
86 fake_query_renderer_string
87 };
88
89 class query_renderer_string_test : public ::testing::Test {
90 public:
91 virtual void SetUp();
92 virtual void TearDown();
93
94 struct glx_screen scr;
95 struct sigaction sa;
96 struct sigaction old_sa;
97 Display dpy;
98 };
99
100 class query_renderer_integer_test : public query_renderer_string_test {
101 };
102
SetUp()103 void query_renderer_string_test::SetUp()
104 {
105 memset(&scr, 0, sizeof(scr));
106 scr.vtable = &fake_vtable;
107 psc = &scr;
108
109 got_sigsegv = false;
110
111 sa.sa_handler = sigsegv_handler;
112 sigemptyset(&sa.sa_mask);
113 sa.sa_flags = 0;
114 sigaction(SIGSEGV, &sa, &old_sa);
115 }
116
TearDown()117 void query_renderer_string_test::TearDown()
118 {
119 sigaction(SIGSEGV, &old_sa, NULL);
120 }
121
122 /**
123 * glXQueryRendererStringMESA will return \c NULL if the query_render_string
124 * vtable entry is \c NULL. It will also not segfault.
125 */
TEST_F(query_renderer_string_test,null_query_render_string)126 TEST_F(query_renderer_string_test, null_query_render_string)
127 {
128 struct glx_screen_vtable vtable = {
129 NULL,
130 NULL,
131 NULL,
132 NULL
133 };
134
135 scr.vtable = &vtable;
136
137 if (setjmp(jmp) == 0) {
138 const char *str =
139 glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
140 EXPECT_EQ((char *)0, str);
141 } else {
142 EXPECT_FALSE(got_sigsegv);
143 }
144 }
145
146 /**
147 * glXQueryRendererStringMESA will not call the screen query_render_string
148 * function with an invalid GLX enum value, and it will return NULL.
149 */
TEST_F(query_renderer_string_test,invalid_attribute)150 TEST_F(query_renderer_string_test, invalid_attribute)
151 {
152 static const attribute_test_vector invalid_attributes[] = {
153 /* These values are just plain invalid for use with this extension.
154 */
155 E(0),
156 E(GLX_VENDOR),
157 E(GLX_VERSION),
158 E(GLX_EXTENSIONS),
159 E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
160 E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
161
162 /* These enums are part of the extension, but they are not allowed for
163 * the string query.
164 */
165 E(GLX_RENDERER_VERSION_MESA),
166 E(GLX_RENDERER_ACCELERATED_MESA),
167 E(GLX_RENDERER_VIDEO_MEMORY_MESA),
168 E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA),
169 E(GLX_RENDERER_PREFERRED_PROFILE_MESA),
170 E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA),
171 E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA),
172 E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA),
173 E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA),
174 E(GLX_RENDERER_ID_MESA),
175 };
176
177 for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
178 query_renderer_integer_called = false;
179 query_renderer_string_called = false;
180
181 const char *str =
182 glXQueryRendererStringMESA(&dpy, 0, 0, invalid_attributes[i].value);
183 EXPECT_EQ((char *)0, str) << invalid_attributes[i].string;
184 EXPECT_FALSE(query_renderer_integer_called)
185 << invalid_attributes[i].string;
186 EXPECT_FALSE(query_renderer_string_called)
187 << invalid_attributes[i].string;
188 }
189 }
190
191 /**
192 * glXQueryRendererStringMESA will not call GetGLXScreenConfigs if the display
193 * pointer is \c NULL. It will also not segfault.
194 */
TEST_F(query_renderer_string_test,null_display_pointer)195 TEST_F(query_renderer_string_test, null_display_pointer)
196 {
197 if (setjmp(jmp) == 0) {
198 GetGLXScreenConfigs_called = false;
199
200 const char *str =
201 glXQueryRendererStringMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
202 EXPECT_EQ((char *)0, str);
203 EXPECT_FALSE(GetGLXScreenConfigs_called);
204 } else {
205 EXPECT_FALSE(got_sigsegv);
206 }
207 }
208
209 /**
210 * glXQueryRendererStringMESA will return error if GetGLXScreenConfigs returns
211 * NULL. It will also not segfault.
212 */
TEST_F(query_renderer_string_test,null_screen_pointer)213 TEST_F(query_renderer_string_test, null_screen_pointer)
214 {
215 psc = NULL;
216
217 if (setjmp(jmp) == 0) {
218 GetGLXScreenConfigs_called = false;
219
220 const char *str =
221 glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
222 EXPECT_EQ((char *)0, str);
223 EXPECT_TRUE(GetGLXScreenConfigs_called);
224 } else {
225 EXPECT_FALSE(got_sigsegv);
226 }
227 }
228
229 /**
230 * glXQueryRendererStringMESA will not call the screen query_render_string
231 * function if the renderer is invalid, and it will return NULL.
232 */
TEST_F(query_renderer_string_test,invalid_renderer_index)233 TEST_F(query_renderer_string_test, invalid_renderer_index)
234 {
235 static const int invalid_renderer_indices[] = {
236 -1,
237 1,
238 999,
239 };
240
241 if (setjmp(jmp) == 0) {
242 for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
243 const char *str =
244 glXQueryRendererStringMESA(&dpy, 0,
245 invalid_renderer_indices[i],
246 GLX_RENDERER_VENDOR_ID_MESA);
247 EXPECT_EQ((char *)0, str) << invalid_renderer_indices[i];
248 EXPECT_FALSE(query_renderer_integer_called)
249 << invalid_renderer_indices[i];
250 EXPECT_FALSE(query_renderer_string_called)
251 << invalid_renderer_indices[i];
252 }
253 } else {
254 EXPECT_FALSE(got_sigsegv);
255 }
256 }
257
258 /**
259 * glXQueryCurrentRendererStringMESA will return error if there is no context
260 * current. It will also not segfault.
261 */
TEST_F(query_renderer_string_test,no_current_context)262 TEST_F(query_renderer_string_test, no_current_context)
263 {
264 if (setjmp(jmp) == 0) {
265 const char *str =
266 glXQueryCurrentRendererStringMESA(GLX_RENDERER_VENDOR_ID_MESA);
267 EXPECT_EQ((char *)0, str);
268 } else {
269 EXPECT_FALSE(got_sigsegv);
270 }
271 }
272
273 /**
274 * glXQueryCurrentRendererIntegerMESA will return \c NULL if the
275 * query_render_string vtable entry is \c NULL. It will also not segfault.
276 */
TEST_F(query_renderer_integer_test,null_query_render_string)277 TEST_F(query_renderer_integer_test, null_query_render_string)
278 {
279 struct glx_screen_vtable vtable = {
280 NULL,
281 NULL,
282 NULL,
283 NULL
284 };
285
286 scr.vtable = &vtable;
287
288 if (setjmp(jmp) == 0) {
289 unsigned value = 0xDEADBEEF;
290 Bool success = glXQueryRendererIntegerMESA(&dpy, 0, 0,
291 GLX_RENDERER_VENDOR_ID_MESA,
292 &value);
293 EXPECT_FALSE(success);
294 EXPECT_EQ(0xDEADBEEF, value);
295 } else {
296 EXPECT_FALSE(got_sigsegv);
297 }
298 }
299
300 /**
301 * glXQueryCurrentRendererIntegerMESA will not call the screen
302 * query_render_string function with an invalid GLX enum value, and it will
303 * return NULL.
304 */
TEST_F(query_renderer_integer_test,invalid_attribute)305 TEST_F(query_renderer_integer_test, invalid_attribute)
306 {
307 static const attribute_test_vector invalid_attributes[] = {
308 /* These values are just plain invalid for use with this extension.
309 */
310 E(0),
311 E(GLX_VENDOR),
312 E(GLX_VERSION),
313 E(GLX_EXTENSIONS),
314 E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
315 E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
316 E(GLX_RENDERER_VERSION_MESA + 0x10000),
317 E(GLX_RENDERER_ACCELERATED_MESA + 0x10000),
318 E(GLX_RENDERER_VIDEO_MEMORY_MESA + 0x10000),
319 E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA + 0x10000),
320 E(GLX_RENDERER_PREFERRED_PROFILE_MESA + 0x10000),
321 E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA + 0x10000),
322 E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA + 0x10000),
323 E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA + 0x10000),
324 E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA + 0x10000),
325 E(GLX_RENDERER_ID_MESA + 0x10000),
326 };
327
328 for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
329 query_renderer_integer_called = false;
330 query_renderer_string_called = false;
331
332 unsigned value = 0xDEADBEEF;
333 Bool success =
334 glXQueryRendererIntegerMESA(&dpy, 0, 0,
335 invalid_attributes[i].value,
336 &value);
337 EXPECT_FALSE(success) << invalid_attributes[i].string;
338 EXPECT_EQ(0xDEADBEEF, value) << invalid_attributes[i].string;
339 EXPECT_FALSE(query_renderer_integer_called)
340 << invalid_attributes[i].string;
341 EXPECT_FALSE(query_renderer_string_called)
342 << invalid_attributes[i].string;
343 }
344 }
345
346 /**
347 * glXQueryCurrentRendererIntegerMESA will not call GetGLXScreenConfigs if the
348 * display pointer is \c NULL. It will also not segfault.
349 */
TEST_F(query_renderer_integer_test,null_display_pointer)350 TEST_F(query_renderer_integer_test, null_display_pointer)
351 {
352 if (setjmp(jmp) == 0) {
353 GetGLXScreenConfigs_called = false;
354
355 unsigned value = 0xDEADBEEF;
356 Bool success =
357 glXQueryRendererIntegerMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
358 &value);
359 EXPECT_FALSE(success);
360 EXPECT_EQ(0xDEADBEEF, value);
361 EXPECT_FALSE(GetGLXScreenConfigs_called);
362 } else {
363 EXPECT_FALSE(got_sigsegv);
364 }
365 }
366
367 /**
368 * glXQueryCurrentRendererIntegerMESA will return error if GetGLXScreenConfigs
369 * returns NULL. It will also not segfault.
370 */
TEST_F(query_renderer_integer_test,null_screen_pointer)371 TEST_F(query_renderer_integer_test, null_screen_pointer)
372 {
373 psc = NULL;
374
375 if (setjmp(jmp) == 0) {
376 GetGLXScreenConfigs_called = false;
377
378 unsigned value = 0xDEADBEEF;
379 Bool success =
380 glXQueryRendererIntegerMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
381 &value);
382 EXPECT_FALSE(success);
383 EXPECT_EQ(0xDEADBEEF, value);
384 EXPECT_TRUE(GetGLXScreenConfigs_called);
385 } else {
386 EXPECT_FALSE(got_sigsegv);
387 }
388 }
389
390 /**
391 * glXQueryRendererIntegerMESA will not call the screen query_render_integer
392 * function if the renderer is invalid, and it will return NULL.
393 */
TEST_F(query_renderer_integer_test,invalid_renderer_index)394 TEST_F(query_renderer_integer_test, invalid_renderer_index)
395 {
396 static const int invalid_renderer_indices[] = {
397 -1,
398 1,
399 999,
400 };
401
402 if (setjmp(jmp) == 0) {
403 for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
404 unsigned value = 0xDEADBEEF;
405 Bool success =
406 glXQueryRendererIntegerMESA(&dpy, 0,
407 invalid_renderer_indices[i],
408 GLX_RENDERER_VENDOR_ID_MESA,
409 &value);
410 EXPECT_FALSE(success) << invalid_renderer_indices[i];
411 EXPECT_EQ(0xDEADBEEF, value) << invalid_renderer_indices[i];
412 EXPECT_FALSE(query_renderer_integer_called)
413 << invalid_renderer_indices[i];
414 EXPECT_FALSE(query_renderer_string_called)
415 << invalid_renderer_indices[i];
416 }
417 } else {
418 EXPECT_FALSE(got_sigsegv);
419 }
420 }
421
422 /**
423 * glXQueryCurrentRendererIntegerMESA will return error if there is no context
424 * current. It will also not segfault.
425 */
TEST_F(query_renderer_integer_test,no_current_context)426 TEST_F(query_renderer_integer_test, no_current_context)
427 {
428 if (setjmp(jmp) == 0) {
429 unsigned value = 0xDEADBEEF;
430 Bool success =
431 glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA,
432 &value);
433 EXPECT_FALSE(success);
434 EXPECT_EQ(0xDEADBEEF, value);
435 } else {
436 EXPECT_FALSE(got_sigsegv);
437 }
438 }
439