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 30extern bool GetGLXScreenConfigs_called; 31extern struct glx_screen *psc; 32 33struct attribute_test_vector { 34 const char *string; 35 int value; 36}; 37 38#define E(x) { # x, x } 39 40 41 42static bool got_sigsegv; 43static jmp_buf jmp; 44 45static void 46sigsegv_handler(int sig) 47{ 48 (void) sig; 49 got_sigsegv = true; 50 longjmp(jmp, 1); 51} 52 53static bool query_renderer_string_called = false; 54static bool query_renderer_integer_called = false; 55 56static int 57fake_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 69static int 70fake_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 82struct glx_screen_vtable fake_vtable = { 83 NULL, 84 NULL, 85 fake_query_renderer_integer, 86 fake_query_renderer_string 87}; 88 89class query_renderer_string_test : public ::testing::Test { 90public: 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 100class query_renderer_integer_test : public query_renderer_string_test { 101}; 102 103void 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 117void 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 */ 126TEST_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 */ 150TEST_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 }; 175 176 for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) { 177 query_renderer_integer_called = false; 178 query_renderer_string_called = false; 179 180 const char *str = 181 glXQueryRendererStringMESA(&dpy, 0, 0, invalid_attributes[i].value); 182 EXPECT_EQ((char *)0, str) << invalid_attributes[i].string; 183 EXPECT_FALSE(query_renderer_integer_called) 184 << invalid_attributes[i].string; 185 EXPECT_FALSE(query_renderer_string_called) 186 << invalid_attributes[i].string; 187 } 188} 189 190/** 191 * glXQueryRendererStringMESA will not call GetGLXScreenConfigs if the display 192 * pointer is \c NULL. It will also not segfault. 193 */ 194TEST_F(query_renderer_string_test, null_display_pointer) 195{ 196 if (setjmp(jmp) == 0) { 197 GetGLXScreenConfigs_called = false; 198 199 const char *str = 200 glXQueryRendererStringMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA); 201 EXPECT_EQ((char *)0, str); 202 EXPECT_FALSE(GetGLXScreenConfigs_called); 203 } else { 204 EXPECT_FALSE(got_sigsegv); 205 } 206} 207 208/** 209 * glXQueryRendererStringMESA will return error if GetGLXScreenConfigs returns 210 * NULL. It will also not segfault. 211 */ 212TEST_F(query_renderer_string_test, null_screen_pointer) 213{ 214 psc = NULL; 215 216 if (setjmp(jmp) == 0) { 217 GetGLXScreenConfigs_called = false; 218 219 const char *str = 220 glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA); 221 EXPECT_EQ((char *)0, str); 222 EXPECT_TRUE(GetGLXScreenConfigs_called); 223 } else { 224 EXPECT_FALSE(got_sigsegv); 225 } 226} 227 228/** 229 * glXQueryRendererStringMESA will not call the screen query_render_string 230 * function if the renderer is invalid, and it will return NULL. 231 */ 232TEST_F(query_renderer_string_test, invalid_renderer_index) 233{ 234 static const int invalid_renderer_indices[] = { 235 -1, 236 1, 237 999, 238 }; 239 240 if (setjmp(jmp) == 0) { 241 for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) { 242 const char *str = 243 glXQueryRendererStringMESA(&dpy, 0, 244 invalid_renderer_indices[i], 245 GLX_RENDERER_VENDOR_ID_MESA); 246 EXPECT_EQ((char *)0, str) << invalid_renderer_indices[i]; 247 EXPECT_FALSE(query_renderer_integer_called) 248 << invalid_renderer_indices[i]; 249 EXPECT_FALSE(query_renderer_string_called) 250 << invalid_renderer_indices[i]; 251 } 252 } else { 253 EXPECT_FALSE(got_sigsegv); 254 } 255} 256 257/** 258 * glXQueryCurrentRendererStringMESA will return error if there is no context 259 * current. It will also not segfault. 260 */ 261TEST_F(query_renderer_string_test, no_current_context) 262{ 263 if (setjmp(jmp) == 0) { 264 const char *str = 265 glXQueryCurrentRendererStringMESA(GLX_RENDERER_VENDOR_ID_MESA); 266 EXPECT_EQ((char *)0, str); 267 } else { 268 EXPECT_FALSE(got_sigsegv); 269 } 270} 271 272/** 273 * glXQueryCurrentRendererIntegerMESA will return \c NULL if the 274 * query_render_string vtable entry is \c NULL. It will also not segfault. 275 */ 276TEST_F(query_renderer_integer_test, null_query_render_string) 277{ 278 struct glx_screen_vtable vtable = { 279 NULL, 280 NULL, 281 NULL, 282 NULL 283 }; 284 285 scr.vtable = &vtable; 286 287 if (setjmp(jmp) == 0) { 288 unsigned value = 0xDEADBEEF; 289 Bool success = glXQueryRendererIntegerMESA(&dpy, 0, 0, 290 GLX_RENDERER_VENDOR_ID_MESA, 291 &value); 292 EXPECT_FALSE(success); 293 EXPECT_EQ(0xDEADBEEF, value); 294 } else { 295 EXPECT_FALSE(got_sigsegv); 296 } 297} 298 299/** 300 * glXQueryCurrentRendererIntegerMESA will not call the screen 301 * query_render_string function with an invalid GLX enum value, and it will 302 * return NULL. 303 */ 304TEST_F(query_renderer_integer_test, invalid_attribute) 305{ 306 static const attribute_test_vector invalid_attributes[] = { 307 /* These values are just plain invalid for use with this extension. 308 */ 309 E(0), 310 E(GLX_VENDOR), 311 E(GLX_VERSION), 312 E(GLX_EXTENSIONS), 313 E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000), 314 E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000), 315 E(GLX_RENDERER_VERSION_MESA + 0x10000), 316 E(GLX_RENDERER_ACCELERATED_MESA + 0x10000), 317 E(GLX_RENDERER_VIDEO_MEMORY_MESA + 0x10000), 318 E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA + 0x10000), 319 E(GLX_RENDERER_PREFERRED_PROFILE_MESA + 0x10000), 320 E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA + 0x10000), 321 E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA + 0x10000), 322 E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA + 0x10000), 323 E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA + 0x10000), 324 }; 325 326 for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) { 327 query_renderer_integer_called = false; 328 query_renderer_string_called = false; 329 330 unsigned value = 0xDEADBEEF; 331 Bool success = 332 glXQueryRendererIntegerMESA(&dpy, 0, 0, 333 invalid_attributes[i].value, 334 &value); 335 EXPECT_FALSE(success) << invalid_attributes[i].string; 336 EXPECT_EQ(0xDEADBEEF, value) << invalid_attributes[i].string; 337 EXPECT_FALSE(query_renderer_integer_called) 338 << invalid_attributes[i].string; 339 EXPECT_FALSE(query_renderer_string_called) 340 << invalid_attributes[i].string; 341 } 342} 343 344/** 345 * glXQueryCurrentRendererIntegerMESA will not call GetGLXScreenConfigs if the 346 * display pointer is \c NULL. It will also not segfault. 347 */ 348TEST_F(query_renderer_integer_test, null_display_pointer) 349{ 350 if (setjmp(jmp) == 0) { 351 GetGLXScreenConfigs_called = false; 352 353 unsigned value = 0xDEADBEEF; 354 Bool success = 355 glXQueryRendererIntegerMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA, 356 &value); 357 EXPECT_FALSE(success); 358 EXPECT_EQ(0xDEADBEEF, value); 359 EXPECT_FALSE(GetGLXScreenConfigs_called); 360 } else { 361 EXPECT_FALSE(got_sigsegv); 362 } 363} 364 365/** 366 * glXQueryCurrentRendererIntegerMESA will return error if GetGLXScreenConfigs 367 * returns NULL. It will also not segfault. 368 */ 369TEST_F(query_renderer_integer_test, null_screen_pointer) 370{ 371 psc = NULL; 372 373 if (setjmp(jmp) == 0) { 374 GetGLXScreenConfigs_called = false; 375 376 unsigned value = 0xDEADBEEF; 377 Bool success = 378 glXQueryRendererIntegerMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA, 379 &value); 380 EXPECT_FALSE(success); 381 EXPECT_EQ(0xDEADBEEF, value); 382 EXPECT_TRUE(GetGLXScreenConfigs_called); 383 } else { 384 EXPECT_FALSE(got_sigsegv); 385 } 386} 387 388/** 389 * glXQueryRendererIntegerMESA will not call the screen query_render_integer 390 * function if the renderer is invalid, and it will return NULL. 391 */ 392TEST_F(query_renderer_integer_test, invalid_renderer_index) 393{ 394 static const int invalid_renderer_indices[] = { 395 -1, 396 1, 397 999, 398 }; 399 400 if (setjmp(jmp) == 0) { 401 for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) { 402 unsigned value = 0xDEADBEEF; 403 Bool success = 404 glXQueryRendererIntegerMESA(&dpy, 0, 405 invalid_renderer_indices[i], 406 GLX_RENDERER_VENDOR_ID_MESA, 407 &value); 408 EXPECT_FALSE(success) << invalid_renderer_indices[i]; 409 EXPECT_EQ(0xDEADBEEF, value) << invalid_renderer_indices[i]; 410 EXPECT_FALSE(query_renderer_integer_called) 411 << invalid_renderer_indices[i]; 412 EXPECT_FALSE(query_renderer_string_called) 413 << invalid_renderer_indices[i]; 414 } 415 } else { 416 EXPECT_FALSE(got_sigsegv); 417 } 418} 419 420/** 421 * glXQueryCurrentRendererIntegerMESA will return error if there is no context 422 * current. It will also not segfault. 423 */ 424TEST_F(query_renderer_integer_test, no_current_context) 425{ 426 if (setjmp(jmp) == 0) { 427 unsigned value = 0xDEADBEEF; 428 Bool success = 429 glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA, 430 &value); 431 EXPECT_FALSE(success); 432 EXPECT_EQ(0xDEADBEEF, value); 433 } else { 434 EXPECT_FALSE(got_sigsegv); 435 } 436} 437