1/*
2 * Copyright © 2011 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 <string.h>
25
26#include "glxclient.h"
27#include "glx_error.h"
28
29#include <xcb/glx.h>
30#include "mock_xdisplay.h"
31#include "fake_glx_screen.h"
32
33static bool CreateContextAttribsARB_was_sent;
34static xcb_glx_create_context_attribs_arb_request_t req;
35static uint32_t sent_attribs[1024];
36static uint32_t next_id;
37
38
39struct glx_screen *psc;
40
41extern "C" Bool
42glx_context_init(struct glx_context *gc,
43		 struct glx_screen *psc, struct glx_config *config)
44{
45   gc->majorOpcode = 123;
46   gc->screen = psc->scr;
47   gc->psc = psc;
48   gc->config = config;
49   gc->isDirect = GL_TRUE;
50   gc->currentContextTag = -1;
51
52   return GL_TRUE;
53}
54
55bool GetGLXScreenConfigs_called = false;
56
57extern "C" struct glx_screen *
58GetGLXScreenConfigs(Display * dpy, int scrn)
59{
60   (void) dpy;
61   (void) scrn;
62
63   GetGLXScreenConfigs_called = true;
64   return psc;
65}
66
67extern "C" uint32_t
68xcb_generate_id(xcb_connection_t *c)
69{
70   (void) c;
71
72   return next_id++;
73}
74
75extern "C" xcb_void_cookie_t
76xcb_glx_create_context_attribs_arb_checked(xcb_connection_t *c,
77					   xcb_glx_context_t context,
78					   uint32_t fbconfig,
79					   uint32_t screen,
80					   uint32_t share_list,
81					   uint8_t is_direct,
82					   uint32_t num_attribs,
83					   const uint32_t *attribs)
84{
85   (void) c;
86
87   CreateContextAttribsARB_was_sent = true;
88   req.context = context;
89   req.fbconfig = fbconfig;
90   req.screen = screen;
91   req.share_list = share_list;
92   req.is_direct = is_direct;
93   req.num_attribs = num_attribs;
94
95   if (num_attribs != 0 && attribs != NULL)
96      memcpy(sent_attribs, attribs, num_attribs * 2 * sizeof(uint32_t));
97
98   xcb_void_cookie_t cookie;
99   cookie.sequence = 0xbadc0de;
100
101   return cookie;
102}
103
104extern "C" xcb_void_cookie_t
105xcb_glx_destroy_context(xcb_connection_t *c, xcb_glx_context_t context)
106{
107   xcb_void_cookie_t cookie;
108   cookie.sequence = 0xbadc0de;
109
110   return cookie;
111}
112
113extern "C" xcb_generic_error_t *
114xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie)
115{
116   return NULL;
117}
118
119extern "C" void
120__glXSendErrorForXcb(Display * dpy, const xcb_generic_error_t *err)
121{
122}
123
124extern "C" void
125__glXSendError(Display * dpy, int_fast8_t errorCode, uint_fast32_t resourceID,
126               uint_fast16_t minorCode, bool coreX11error)
127{
128}
129
130class glXCreateContextAttribARB_test : public ::testing::Test {
131public:
132   virtual void SetUp();
133   virtual void TearDown();
134
135   /**
136    * Replace the existing screen with a direct-rendering screen
137    */
138   void use_direct_rendering_screen();
139
140   mock_XDisplay *dpy;
141   GLXContext ctx;
142   struct glx_config fbc;
143};
144
145void
146glXCreateContextAttribARB_test::SetUp()
147{
148   CreateContextAttribsARB_was_sent = false;
149   memset(&req, 0, sizeof(req));
150   next_id = 99;
151   fake_glx_context::contexts_allocated = 0;
152   psc = new fake_glx_screen(NULL, 0, "");
153
154   this->dpy = new mock_XDisplay(1);
155
156   memset(&this->fbc, 0, sizeof(this->fbc));
157   this->fbc.fbconfigID = 0xbeefcafe;
158
159   this->ctx = NULL;
160}
161
162void
163glXCreateContextAttribARB_test::TearDown()
164{
165   if (ctx)
166      delete (fake_glx_context *)ctx;
167
168   delete (fake_glx_screen *)psc;
169
170   delete this->dpy;
171}
172
173void
174glXCreateContextAttribARB_test::use_direct_rendering_screen()
175{
176   struct glx_screen *direct_psc =
177      new fake_glx_screen_direct(psc->display,
178				 psc->scr,
179				 psc->serverGLXexts);
180
181   delete (fake_glx_screen *)psc;
182   psc = direct_psc;
183}
184
185/**
186 * \name Verify detection of client-side errors
187 */
188/*@{*/
189TEST_F(glXCreateContextAttribARB_test, NULL_display_returns_None)
190{
191   GLXContext ctx =
192      glXCreateContextAttribsARB(NULL, (GLXFBConfig) &this->fbc, 0,
193				 False, NULL);
194
195   EXPECT_EQ(None, ctx);
196   EXPECT_EQ(0, fake_glx_context::contexts_allocated);
197}
198
199TEST_F(glXCreateContextAttribARB_test, NULL_screen_returns_None)
200{
201   delete (fake_glx_screen *)psc;
202   psc = NULL;
203
204   GLXContext ctx =
205      glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
206				 False, NULL);
207
208   EXPECT_EQ(None, ctx);
209   EXPECT_EQ(0, fake_glx_context::contexts_allocated);
210}
211/*@}*/
212
213/**
214 * \name Verify that correct protocol bits are sent to the server.
215 */
216/*@{*/
217TEST_F(glXCreateContextAttribARB_test, does_send_protocol)
218{
219   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
220			      False, NULL);
221
222   EXPECT_TRUE(CreateContextAttribsARB_was_sent);
223}
224
225TEST_F(glXCreateContextAttribARB_test, sent_correct_context)
226{
227   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
228			      False, NULL);
229   EXPECT_EQ(99u, req.context);
230}
231
232TEST_F(glXCreateContextAttribARB_test, sent_correct_fbconfig)
233{
234   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
235			      False, NULL);
236
237   EXPECT_EQ(0xbeefcafe, req.fbconfig);
238}
239
240TEST_F(glXCreateContextAttribARB_test, sent_correct_share_list)
241{
242   GLXContext share =
243      glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
244				 False, NULL);
245
246   ASSERT_NE((GLXContext) 0, share);
247
248   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, share,
249			      False, NULL);
250
251   struct glx_context *glx_ctx = (struct glx_context *) share;
252   EXPECT_EQ(glx_ctx->xid, req.share_list);
253
254   delete (fake_glx_context *)share;
255}
256
257TEST_F(glXCreateContextAttribARB_test, sent_correct_is_direct_for_indirect_screen_and_direct_set_to_true)
258{
259   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
260			      True, NULL);
261
262   EXPECT_FALSE(req.is_direct);
263}
264
265TEST_F(glXCreateContextAttribARB_test, sent_correct_is_direct_for_indirect_screen_and_direct_set_to_false)
266{
267   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
268			      False, NULL);
269
270   EXPECT_FALSE(req.is_direct);
271}
272
273TEST_F(glXCreateContextAttribARB_test, sent_correct_is_direct_for_direct_screen_and_direct_set_to_true)
274{
275   this->use_direct_rendering_screen();
276
277   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
278			      True, NULL);
279
280   EXPECT_TRUE(req.is_direct);
281}
282
283TEST_F(glXCreateContextAttribARB_test, sent_correct_is_direct_for_direct_screen_and_direct_set_to_false)
284{
285   this->use_direct_rendering_screen();
286
287   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
288			      False, NULL);
289
290   EXPECT_FALSE(req.is_direct);
291}
292
293TEST_F(glXCreateContextAttribARB_test, sent_correct_screen)
294{
295   this->fbc.screen = 7;
296   psc->scr = 7;
297
298   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
299			      False, NULL);
300
301   EXPECT_EQ(7u, req.screen);
302}
303
304TEST_F(glXCreateContextAttribARB_test, sent_correct_num_attribs)
305{
306   /* Use zeros in the second half of each attribute pair to try and trick the
307    * implementation into termiating the list early.
308    *
309    * Use non-zero in the second half of the last attribute pair to try and
310    * trick the implementation into not terminating the list early enough.
311    */
312   static const int attribs[] = {
313      1, 0,
314      2, 0,
315      3, 0,
316      4, 0,
317      0, 6,
318      0, 0
319   };
320
321   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
322			      False, attribs);
323
324   EXPECT_EQ(4u, req.num_attribs);
325}
326
327TEST_F(glXCreateContextAttribARB_test, sent_correct_num_attribs_empty_list)
328{
329   static const int attribs[] = {
330      0,
331   };
332
333   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
334			      False, attribs);
335
336   EXPECT_EQ(0u, req.num_attribs);
337}
338
339TEST_F(glXCreateContextAttribARB_test, sent_correct_num_attribs_NULL_list_pointer)
340{
341   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
342			      False, NULL);
343
344   EXPECT_EQ(0u, req.num_attribs);
345}
346
347TEST_F(glXCreateContextAttribARB_test, sent_correct_attrib_list)
348{
349   int attribs[] = {
350      GLX_RENDER_TYPE, GLX_RGBA_TYPE,
351      GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
352      GLX_CONTEXT_MINOR_VERSION_ARB, 2,
353      0
354   };
355
356   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
357			      False, attribs);
358
359   for (unsigned i = 0; i < 6; i++) {
360      EXPECT_EQ((uint32_t) attribs[i], sent_attribs[i]);
361   }
362}
363/*@}*/
364
365/**
366 * \name Verify details of the returned GLXContext
367 */
368/*@{*/
369TEST_F(glXCreateContextAttribARB_test, correct_context)
370{
371   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
372				 False, NULL);
373
374   /* Since the server did not return an error, the GLXContext should not be
375    * NULL.
376    */
377   EXPECT_NE((GLXContext)0, ctx);
378
379   /* It shouldn't be the XID of the context either.
380    */
381   EXPECT_NE((GLXContext)99, ctx);
382}
383
384TEST_F(glXCreateContextAttribARB_test, correct_context_xid)
385{
386   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
387				 False, NULL);
388
389   /* Since the server did not return an error, the GLXContext should not be
390    * NULL.
391    */
392   ASSERT_NE((GLXContext)0, ctx);
393
394   struct glx_context *glx_ctx = (struct glx_context *) ctx;
395   EXPECT_EQ(99u, glx_ctx->xid);
396}
397
398TEST_F(glXCreateContextAttribARB_test, correct_context_share_xid)
399{
400   GLXContext first =
401      glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
402				 False, NULL);
403
404   ASSERT_NE((GLXContext) 0, first);
405
406   GLXContext second =
407      glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, first,
408				 False, NULL);
409
410   ASSERT_NE((GLXContext) 0, second);
411
412   struct glx_context *share = (struct glx_context *) first;
413   struct glx_context *ctx = (struct glx_context *) second;
414   EXPECT_EQ(share->xid, ctx->share_xid);
415
416   delete (fake_glx_context *)first;
417   delete (fake_glx_context *)second;
418}
419
420TEST_F(glXCreateContextAttribARB_test, correct_context_isDirect_for_indirect_screen_and_direct_set_to_true)
421{
422   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
423				 True, NULL);
424
425   ASSERT_NE((GLXContext) 0, ctx);
426
427   struct glx_context *gc = (struct glx_context *) ctx;
428
429   EXPECT_FALSE(gc->isDirect);
430}
431
432TEST_F(glXCreateContextAttribARB_test, correct_context_isDirect_for_indirect_screen_and_direct_set_to_false)
433{
434   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
435				 False, NULL);
436
437   ASSERT_NE((GLXContext) 0, ctx);
438
439   struct glx_context *gc = (struct glx_context *) ctx;
440
441   EXPECT_FALSE(gc->isDirect);
442}
443
444TEST_F(glXCreateContextAttribARB_test, correct_context_isDirect_for_direct_screen_and_direct_set_to_true)
445{
446   this->use_direct_rendering_screen();
447
448   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
449				 True, NULL);
450
451   ASSERT_NE((GLXContext) 0, ctx);
452
453   struct glx_context *gc = (struct glx_context *) ctx;
454
455   EXPECT_TRUE(gc->isDirect);
456}
457
458TEST_F(glXCreateContextAttribARB_test, correct_context_isDirect_for_direct_screen_and_direct_set_to_false)
459{
460   this->use_direct_rendering_screen();
461
462   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
463				 False, NULL);
464
465   ASSERT_NE((GLXContext) 0, ctx);
466
467   struct glx_context *gc = (struct glx_context *) ctx;
468
469   EXPECT_FALSE(gc->isDirect);
470}
471
472TEST_F(glXCreateContextAttribARB_test, correct_indirect_context_client_state_private)
473{
474   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
475				 False, NULL);
476
477   ASSERT_NE((GLXContext) 0, ctx);
478
479   struct glx_context *gc = (struct glx_context *) ctx;
480
481   ASSERT_FALSE(gc->isDirect);
482   EXPECT_EQ((struct __GLXattributeRec *) 0xcafebabe,
483	     gc->client_state_private);
484}
485
486TEST_F(glXCreateContextAttribARB_test, correct_indirect_context_config)
487{
488   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
489				 False, NULL);
490
491   ASSERT_NE((GLXContext) 0, ctx);
492
493   struct glx_context *gc = (struct glx_context *) ctx;
494
495   EXPECT_EQ(&this->fbc, gc->config);
496}
497
498TEST_F(glXCreateContextAttribARB_test, correct_context_screen_number)
499{
500   this->fbc.screen = 7;
501   psc->scr = 7;
502
503   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
504				 False, NULL);
505
506   ASSERT_NE((GLXContext) 0, ctx);
507
508   struct glx_context *gc = (struct glx_context *) ctx;
509
510   EXPECT_EQ(7, gc->screen);
511}
512
513TEST_F(glXCreateContextAttribARB_test, correct_context_screen_pointer)
514{
515   ctx = glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
516				 False, NULL);
517
518   ASSERT_NE((GLXContext) 0, ctx);
519
520   struct glx_context *gc = (struct glx_context *) ctx;
521
522   EXPECT_EQ(psc, gc->psc);
523}
524/*@}*/
525