query_renderer_unittest.cpp revision af69d88d
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
27extern "C" {
28#include "glxclient.h"
29#include "glx_error.h"
30}
31
32extern bool GetGLXScreenConfigs_called;
33extern struct glx_screen *psc;
34
35struct attribute_test_vector {
36   const char *string;
37   int value;
38};
39
40#define E(x) { # x, x }
41
42
43
44static bool got_sigsegv;
45static jmp_buf jmp;
46
47static void
48sigsegv_handler(int sig)
49{
50   (void) sig;
51   got_sigsegv = true;
52   longjmp(jmp, 1);
53}
54
55static bool query_renderer_string_called = false;
56static bool query_renderer_integer_called = false;
57
58static int
59fake_query_renderer_integer(struct glx_screen *psc, int attribute,
60                            unsigned int *value)
61{
62   (void) psc;
63   (void) attribute;
64   (void) value;
65
66   query_renderer_integer_called = true;
67
68   return -1;
69}
70
71static int
72fake_query_renderer_string(struct glx_screen *psc, int attribute,
73                           const char **value)
74{
75   (void) psc;
76   (void) attribute;
77   (void) value;
78
79   query_renderer_string_called = true;
80
81   return -1;
82}
83
84struct glx_screen_vtable fake_vtable = {
85   NULL,
86   NULL,
87   fake_query_renderer_integer,
88   fake_query_renderer_string
89};
90
91class query_renderer_string_test : public ::testing::Test {
92public:
93   virtual void SetUp();
94   virtual void TearDown();
95
96   struct glx_screen scr;
97   struct sigaction sa;
98   struct sigaction old_sa;
99   Display dpy;
100};
101
102class query_renderer_integer_test : public query_renderer_string_test {
103};
104
105void query_renderer_string_test::SetUp()
106{
107   memset(&scr, 0, sizeof(scr));
108   scr.vtable = &fake_vtable;
109   psc = &scr;
110
111   got_sigsegv = false;
112
113   sa.sa_handler = sigsegv_handler;
114   sigemptyset(&sa.sa_mask);
115   sa.sa_flags = 0;
116   sigaction(SIGSEGV, &sa, &old_sa);
117}
118
119void query_renderer_string_test::TearDown()
120{
121   sigaction(SIGSEGV, &old_sa, NULL);
122}
123
124/**
125 * glXQueryRendererStringMESA will return \c NULL if the query_render_string
126 * vtable entry is \c NULL.  It will also not segfault.
127 */
128TEST_F(query_renderer_string_test, null_query_render_string)
129{
130   struct glx_screen_vtable vtable = {
131      NULL,
132      NULL,
133      NULL,
134      NULL
135   };
136
137   scr.vtable = &vtable;
138
139   if (setjmp(jmp) == 0) {
140      const char *str =
141         glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
142      EXPECT_EQ((char *)0, str);
143   } else {
144      EXPECT_FALSE(got_sigsegv);
145   }
146}
147
148/**
149 * glXQueryRendererStringMESA will not call the screen query_render_string
150 * function with an invalid GLX enum value, and it will return NULL.
151 */
152TEST_F(query_renderer_string_test, invalid_attribute)
153{
154   static const attribute_test_vector invalid_attributes[] = {
155      /* These values are just plain invalid for use with this extension.
156       */
157      E(0),
158      E(GLX_VENDOR),
159      E(GLX_VERSION),
160      E(GLX_EXTENSIONS),
161      E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
162      E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
163
164      /* These enums are part of the extension, but they are not allowed for
165       * the string query.
166       */
167      E(GLX_RENDERER_VERSION_MESA),
168      E(GLX_RENDERER_ACCELERATED_MESA),
169      E(GLX_RENDERER_VIDEO_MEMORY_MESA),
170      E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA),
171      E(GLX_RENDERER_PREFERRED_PROFILE_MESA),
172      E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA),
173      E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA),
174      E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA),
175      E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA),
176      E(GLX_RENDERER_ID_MESA),
177   };
178
179   for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
180      query_renderer_integer_called = false;
181      query_renderer_string_called = false;
182
183      const char *str =
184         glXQueryRendererStringMESA(&dpy, 0, 0, invalid_attributes[i].value);
185      EXPECT_EQ((char *)0, str) << invalid_attributes[i].string;
186      EXPECT_FALSE(query_renderer_integer_called)
187         << invalid_attributes[i].string;
188      EXPECT_FALSE(query_renderer_string_called)
189         << invalid_attributes[i].string;
190   }
191}
192
193/**
194 * glXQueryRendererStringMESA will not call GetGLXScreenConfigs if the display
195 * pointer is \c NULL.  It will also not segfault.
196 */
197TEST_F(query_renderer_string_test, null_display_pointer)
198{
199   if (setjmp(jmp) == 0) {
200      GetGLXScreenConfigs_called = false;
201
202      const char *str =
203         glXQueryRendererStringMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
204      EXPECT_EQ((char *)0, str);
205      EXPECT_FALSE(GetGLXScreenConfigs_called);
206   } else {
207      EXPECT_FALSE(got_sigsegv);
208   }
209}
210
211/**
212 * glXQueryRendererStringMESA will return error if GetGLXScreenConfigs returns
213 * NULL.  It will also not segfault.
214 */
215TEST_F(query_renderer_string_test, null_screen_pointer)
216{
217   psc = NULL;
218
219   if (setjmp(jmp) == 0) {
220      GetGLXScreenConfigs_called = false;
221
222      const char *str =
223         glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
224      EXPECT_EQ((char *)0, str);
225      EXPECT_TRUE(GetGLXScreenConfigs_called);
226   } else {
227      EXPECT_FALSE(got_sigsegv);
228   }
229}
230
231/**
232 * glXQueryRendererStringMESA will not call the screen query_render_string
233 * function if the renderer is invalid, and it will return NULL.
234 */
235TEST_F(query_renderer_string_test, invalid_renderer_index)
236{
237   static const int invalid_renderer_indices[] = {
238      -1,
239      1,
240      999,
241   };
242
243   if (setjmp(jmp) == 0) {
244      for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
245         const char *str =
246            glXQueryRendererStringMESA(&dpy, 0,
247                                       invalid_renderer_indices[i],
248                                       GLX_RENDERER_VENDOR_ID_MESA);
249         EXPECT_EQ((char *)0, str) << invalid_renderer_indices[i];
250         EXPECT_FALSE(query_renderer_integer_called)
251            << invalid_renderer_indices[i];
252         EXPECT_FALSE(query_renderer_string_called)
253            << invalid_renderer_indices[i];
254      }
255   } else {
256      EXPECT_FALSE(got_sigsegv);
257   }
258}
259
260/**
261 * glXQueryCurrentRendererStringMESA will return error if there is no context
262 * current.  It will also not segfault.
263 */
264TEST_F(query_renderer_string_test, no_current_context)
265{
266   if (setjmp(jmp) == 0) {
267      const char *str =
268         glXQueryCurrentRendererStringMESA(GLX_RENDERER_VENDOR_ID_MESA);
269      EXPECT_EQ((char *)0, str);
270   } else {
271      EXPECT_FALSE(got_sigsegv);
272   }
273}
274
275/**
276 * glXQueryCurrentRendererIntegerMESA will return \c NULL if the
277 * query_render_string vtable entry is \c NULL.  It will also not segfault.
278 */
279TEST_F(query_renderer_integer_test, null_query_render_string)
280{
281   struct glx_screen_vtable vtable = {
282      NULL,
283      NULL,
284      NULL,
285      NULL
286   };
287
288   scr.vtable = &vtable;
289
290   if (setjmp(jmp) == 0) {
291      unsigned value = 0xDEADBEEF;
292      Bool success = glXQueryRendererIntegerMESA(&dpy, 0, 0,
293                                                 GLX_RENDERER_VENDOR_ID_MESA,
294                                                 &value);
295      EXPECT_FALSE(success);
296      EXPECT_EQ(0xDEADBEEF, value);
297   } else {
298      EXPECT_FALSE(got_sigsegv);
299   }
300}
301
302/**
303 * glXQueryCurrentRendererIntegerMESA will not call the screen
304 * query_render_string function with an invalid GLX enum value, and it will
305 * return NULL.
306 */
307TEST_F(query_renderer_integer_test, invalid_attribute)
308{
309   static const attribute_test_vector invalid_attributes[] = {
310      /* These values are just plain invalid for use with this extension.
311       */
312      E(0),
313      E(GLX_VENDOR),
314      E(GLX_VERSION),
315      E(GLX_EXTENSIONS),
316      E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
317      E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
318      E(GLX_RENDERER_VERSION_MESA + 0x10000),
319      E(GLX_RENDERER_ACCELERATED_MESA + 0x10000),
320      E(GLX_RENDERER_VIDEO_MEMORY_MESA + 0x10000),
321      E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA + 0x10000),
322      E(GLX_RENDERER_PREFERRED_PROFILE_MESA + 0x10000),
323      E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA + 0x10000),
324      E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA + 0x10000),
325      E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA + 0x10000),
326      E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA + 0x10000),
327      E(GLX_RENDERER_ID_MESA + 0x10000),
328   };
329
330   for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
331      query_renderer_integer_called = false;
332      query_renderer_string_called = false;
333
334      unsigned value = 0xDEADBEEF;
335      Bool success =
336         glXQueryRendererIntegerMESA(&dpy, 0, 0,
337                                     invalid_attributes[i].value,
338                                     &value);
339      EXPECT_FALSE(success) << invalid_attributes[i].string;
340      EXPECT_EQ(0xDEADBEEF, value) << invalid_attributes[i].string;
341      EXPECT_FALSE(query_renderer_integer_called)
342         << invalid_attributes[i].string;
343      EXPECT_FALSE(query_renderer_string_called)
344         << invalid_attributes[i].string;
345   }
346}
347
348/**
349 * glXQueryCurrentRendererIntegerMESA will not call GetGLXScreenConfigs if the
350 * display pointer is \c NULL.  It will also not segfault.
351 */
352TEST_F(query_renderer_integer_test, null_display_pointer)
353{
354   if (setjmp(jmp) == 0) {
355      GetGLXScreenConfigs_called = false;
356
357      unsigned value = 0xDEADBEEF;
358      Bool success =
359         glXQueryRendererIntegerMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
360                                     &value);
361      EXPECT_FALSE(success);
362      EXPECT_EQ(0xDEADBEEF, value);
363      EXPECT_FALSE(GetGLXScreenConfigs_called);
364   } else {
365      EXPECT_FALSE(got_sigsegv);
366   }
367}
368
369/**
370 * glXQueryCurrentRendererIntegerMESA will return error if GetGLXScreenConfigs
371 * returns NULL.  It will also not segfault.
372 */
373TEST_F(query_renderer_integer_test, null_screen_pointer)
374{
375   psc = NULL;
376
377   if (setjmp(jmp) == 0) {
378      GetGLXScreenConfigs_called = false;
379
380      unsigned value = 0xDEADBEEF;
381      Bool success =
382         glXQueryRendererIntegerMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
383            &value);
384      EXPECT_FALSE(success);
385      EXPECT_EQ(0xDEADBEEF, value);
386      EXPECT_TRUE(GetGLXScreenConfigs_called);
387   } else {
388      EXPECT_FALSE(got_sigsegv);
389   }
390}
391
392/**
393 * glXQueryRendererIntegerMESA will not call the screen query_render_integer
394 * function if the renderer is invalid, and it will return NULL.
395 */
396TEST_F(query_renderer_integer_test, invalid_renderer_index)
397{
398   static const int invalid_renderer_indices[] = {
399      -1,
400      1,
401      999,
402   };
403
404   if (setjmp(jmp) == 0) {
405      for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
406         unsigned value = 0xDEADBEEF;
407         Bool success =
408            glXQueryRendererIntegerMESA(&dpy, 0,
409                                        invalid_renderer_indices[i],
410                                        GLX_RENDERER_VENDOR_ID_MESA,
411                                        &value);
412         EXPECT_FALSE(success) << invalid_renderer_indices[i];
413         EXPECT_EQ(0xDEADBEEF, value) << invalid_renderer_indices[i];
414         EXPECT_FALSE(query_renderer_integer_called)
415            << invalid_renderer_indices[i];
416         EXPECT_FALSE(query_renderer_string_called)
417            << invalid_renderer_indices[i];
418      }
419   } else {
420      EXPECT_FALSE(got_sigsegv);
421   }
422}
423
424/**
425 * glXQueryCurrentRendererIntegerMESA will return error if there is no context
426 * current.  It will also not segfault.
427 */
428TEST_F(query_renderer_integer_test, no_current_context)
429{
430   if (setjmp(jmp) == 0) {
431      unsigned value = 0xDEADBEEF;
432      Bool success =
433         glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA,
434                                            &value);
435      EXPECT_FALSE(success);
436      EXPECT_EQ(0xDEADBEEF, value);
437   } else {
438      EXPECT_FALSE(got_sigsegv);
439   }
440}
441