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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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