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#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
28
29#include "glxclient.h"
30#include "glx_error.h"
31#include "dri2.h"
32#include "GL/internal/dri_interface.h"
33#include "dri2_priv.h"
34
35struct attribute_test_vector {
36   const char *glx_string;
37   const char *dri_string;
38   int glx_attribute;
39   int dri_attribute;
40};
41
42#define E(g, d) { # g, # d, g, d }
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
55class dri2_query_renderer_string_test : public ::testing::Test {
56public:
57   virtual void SetUp();
58   virtual void TearDown();
59
60   struct sigaction sa;
61   struct sigaction old_sa;
62};
63
64class dri2_query_renderer_integer_test :
65   public dri2_query_renderer_string_test {
66};
67
68static bool queryString_called = false;
69static int queryString_attribute = -1;
70
71static bool queryInteger_called = false;
72static int queryInteger_attribute = -1;
73
74static int
75fake_queryInteger(__DRIscreen *screen, int attribute, unsigned int *val)
76{
77   (void) screen;
78
79   queryInteger_attribute = attribute;
80   queryInteger_called = true;
81
82   switch (attribute) {
83   case __DRI2_RENDERER_VENDOR_ID:
84      *val = ~__DRI2_RENDERER_VENDOR_ID;
85      return 0;
86   case __DRI2_RENDERER_DEVICE_ID:
87      *val = ~__DRI2_RENDERER_DEVICE_ID;
88      return 0;
89   case __DRI2_RENDERER_VERSION:
90      *val = ~__DRI2_RENDERER_VERSION;
91      return 0;
92   case __DRI2_RENDERER_ACCELERATED:
93      *val = ~__DRI2_RENDERER_ACCELERATED;
94      return 0;
95   case __DRI2_RENDERER_VIDEO_MEMORY:
96      *val = ~__DRI2_RENDERER_VIDEO_MEMORY;
97      return 0;
98   case __DRI2_RENDERER_UNIFIED_MEMORY_ARCHITECTURE:
99      *val = ~__DRI2_RENDERER_UNIFIED_MEMORY_ARCHITECTURE;
100      return 0;
101   case __DRI2_RENDERER_PREFERRED_PROFILE:
102      *val = ~__DRI2_RENDERER_PREFERRED_PROFILE;
103      return 0;
104   case __DRI2_RENDERER_OPENGL_CORE_PROFILE_VERSION:
105      *val = ~__DRI2_RENDERER_OPENGL_CORE_PROFILE_VERSION;
106      return 0;
107   case __DRI2_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION:
108      *val = ~__DRI2_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION;
109      return 0;
110   case __DRI2_RENDERER_OPENGL_ES_PROFILE_VERSION:
111      *val = ~__DRI2_RENDERER_OPENGL_ES_PROFILE_VERSION;
112      return 0;
113   case __DRI2_RENDERER_OPENGL_ES2_PROFILE_VERSION:
114      *val = ~__DRI2_RENDERER_OPENGL_ES2_PROFILE_VERSION;
115      return 0;
116   }
117
118   return -1;
119}
120
121static int
122fake_queryString(__DRIscreen *screen, int attribute, const char **val)
123{
124   (void) screen;
125
126   queryString_attribute = attribute;
127   queryString_called = true;
128
129   switch (attribute) {
130   case __DRI2_RENDERER_VENDOR_ID:
131      *val = "__DRI2_RENDERER_VENDOR_ID";
132      return 0;
133   case __DRI2_RENDERER_DEVICE_ID:
134      *val = "__DRI2_RENDERER_DEVICE_ID";
135      return 0;
136   }
137
138   return -1;
139}
140
141static const __DRI2rendererQueryExtension rendererQueryExt = {
142   { __DRI2_RENDERER_QUERY, 1 },
143
144   fake_queryInteger,
145   fake_queryString
146};
147
148void dri2_query_renderer_string_test::SetUp()
149{
150   got_sigsegv = false;
151
152   sa.sa_handler = sigsegv_handler;
153   sigemptyset(&sa.sa_mask);
154   sa.sa_flags = 0;
155   sigaction(SIGSEGV, &sa, &old_sa);
156}
157
158void dri2_query_renderer_string_test::TearDown()
159{
160   sigaction(SIGSEGV, &old_sa, NULL);
161}
162
163/**
164 * dri2_query_renderer_string will return an error if the rendererQuery
165 * extension is not present.  It will also not segfault.
166 */
167TEST_F(dri2_query_renderer_string_test, DRI2_RENDERER_QUERY_not_supported)
168{
169   struct dri2_screen dsc;
170
171   memset(&dsc, 0, sizeof(dsc));
172
173   if (setjmp(jmp) == 0) {
174      static const char original_value[] = "0xDEADBEEF";
175      const char *value = original_value;
176      const int success =
177         dri2_query_renderer_string(&dsc.base,
178                                    GLX_RENDERER_VENDOR_ID_MESA, &value);
179
180      EXPECT_EQ(-1, success);
181      EXPECT_EQ(original_value, value);
182   } else {
183      EXPECT_FALSE(got_sigsegv);
184   }
185}
186
187/**
188 * dri2_query_renderer_string will call queryString with the correct DRI2 enum
189 * for each GLX attribute value.
190 *
191 * \note
192 * This test does \b not perform any checking for invalid GLX attribte values.
193 * Other unit tests verify that invalid values are filtered before
194 * dri2_query_renderer_string is called.
195 */
196TEST_F(dri2_query_renderer_string_test, valid_attribute_mapping)
197{
198   struct dri2_screen dsc;
199   struct attribute_test_vector valid_attributes[] = {
200      E(GLX_RENDERER_VENDOR_ID_MESA,
201        __DRI2_RENDERER_VENDOR_ID),
202      E(GLX_RENDERER_DEVICE_ID_MESA,
203        __DRI2_RENDERER_DEVICE_ID),
204   };
205
206   memset(&dsc, 0, sizeof(dsc));
207   dsc.rendererQuery = &rendererQueryExt;
208
209   if (setjmp(jmp) == 0) {
210      for (unsigned i = 0; i < ARRAY_SIZE(valid_attributes); i++) {
211         static const char original_value[] = "original value";
212         const char *value = original_value;
213         const int success =
214            dri2_query_renderer_string(&dsc.base,
215                                       valid_attributes[i].glx_attribute,
216                                       &value);
217
218         EXPECT_EQ(0, success);
219         EXPECT_EQ(valid_attributes[i].dri_attribute, queryString_attribute)
220            << valid_attributes[i].glx_string;
221         EXPECT_STREQ(valid_attributes[i].dri_string, value)
222            << valid_attributes[i].glx_string;
223      }
224   } else {
225      EXPECT_FALSE(got_sigsegv);
226   }
227}
228
229/**
230 * dri2_query_renderer_integer will return an error if the rendererQuery
231 * extension is not present.  It will also not segfault.
232 */
233TEST_F(dri2_query_renderer_integer_test, DRI2_RENDERER_QUERY_not_supported)
234{
235   struct dri2_screen dsc;
236
237   memset(&dsc, 0, sizeof(dsc));
238
239   if (setjmp(jmp) == 0) {
240      unsigned int value = 0xDEADBEEF;
241      const int success =
242         dri2_query_renderer_integer(&dsc.base,
243                                    GLX_RENDERER_VENDOR_ID_MESA, &value);
244
245      EXPECT_EQ(-1, success);
246      EXPECT_EQ(0xDEADBEEF, value);
247   } else {
248      EXPECT_FALSE(got_sigsegv);
249   }
250}
251
252/**
253 * dri2_query_renderer_integer will call queryInteger with the correct DRI2 enum
254 * for each GLX attribute value.
255 *
256 * \note
257 * This test does \b not perform any checking for invalid GLX attribte values.
258 * Other unit tests verify that invalid values are filtered before
259 * dri2_query_renderer_integer is called.
260 */
261TEST_F(dri2_query_renderer_integer_test, valid_attribute_mapping)
262{
263   struct dri2_screen dsc;
264   struct attribute_test_vector valid_attributes[] = {
265      E(GLX_RENDERER_VENDOR_ID_MESA,
266        __DRI2_RENDERER_VENDOR_ID),
267      E(GLX_RENDERER_DEVICE_ID_MESA,
268        __DRI2_RENDERER_DEVICE_ID),
269      E(GLX_RENDERER_VERSION_MESA,
270        __DRI2_RENDERER_VERSION),
271      E(GLX_RENDERER_ACCELERATED_MESA,
272        __DRI2_RENDERER_ACCELERATED),
273      E(GLX_RENDERER_VIDEO_MEMORY_MESA,
274        __DRI2_RENDERER_VIDEO_MEMORY),
275      E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA,
276        __DRI2_RENDERER_UNIFIED_MEMORY_ARCHITECTURE),
277      E(GLX_RENDERER_PREFERRED_PROFILE_MESA,
278        __DRI2_RENDERER_PREFERRED_PROFILE),
279      E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA,
280        __DRI2_RENDERER_OPENGL_CORE_PROFILE_VERSION),
281      E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA,
282        __DRI2_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION),
283      E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA,
284        __DRI2_RENDERER_OPENGL_ES_PROFILE_VERSION),
285      E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA,
286        __DRI2_RENDERER_OPENGL_ES2_PROFILE_VERSION),
287   };
288
289   memset(&dsc, 0, sizeof(dsc));
290   dsc.rendererQuery = &rendererQueryExt;
291
292   if (setjmp(jmp) == 0) {
293      for (unsigned i = 0; i < ARRAY_SIZE(valid_attributes); i++) {
294         unsigned int value = 0xDEADBEEF;
295         const int success =
296            dri2_query_renderer_integer(&dsc.base,
297                                       valid_attributes[i].glx_attribute,
298                                       &value);
299
300         EXPECT_EQ(0, success);
301         EXPECT_EQ(valid_attributes[i].dri_attribute, queryInteger_attribute)
302            << valid_attributes[i].glx_string;
303         EXPECT_EQ((unsigned int) ~valid_attributes[i].dri_attribute, value)
304            << valid_attributes[i].glx_string;
305      }
306   } else {
307      EXPECT_FALSE(got_sigsegv);
308   }
309}
310
311#endif /* GLX_DIRECT_RENDERING */
312