/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <gtest/gtest.h>
#include <string.h>
#include "glxclient.h"
#include "glx_error.h"
#include <xcb/glx.h>
#include "mock_xdisplay.h"
#include "fake_glx_screen.h"
static bool CreateContextAttribsARB_was_sent;
static xcb_glx_create_context_attribs_arb_request_t req;
static uint32_t sent_attribs[1024];
static uint32_t next_id;
struct glx_screen *psc;
extern "C" Bool
glx_context_init(struct glx_context *gc,
struct glx_screen *psc, struct glx_config *config)
{
gc->majorOpcode = 123;
gc->screen = psc->scr;
gc->psc = psc;
gc->config = config;
gc->isDirect = GL_TRUE;
gc->currentContextTag = -1;
return GL_TRUE;
}
bool GetGLXScreenConfigs_called = false;
extern "C" struct glx_screen *
GetGLXScreenConfigs(Display * dpy, int scrn)
{
(void) dpy;
(void) scrn;
GetGLXScreenConfigs_called = true;
return psc;
}
extern "C" uint32_t
xcb_generate_id(xcb_connection_t *c)
{
(void) c;
return next_id++;
}
extern "C" xcb_void_cookie_t
xcb_glx_create_context_attribs_arb_checked(xcb_connection_t *c,
xcb_glx_context_t context,
uint32_t fbconfig,
uint32_t screen,
uint32_t share_list,
uint8_t is_direct,
uint32_t num_attribs,
const uint32_t *attribs)
{
(void) c;
CreateContextAttribsARB_was_sent = true;
req.context = context;
req.fbconfig = fbconfig;
req.screen = screen;
req.share_list = share_list;
req.is_direct = is_direct;
req.num_attribs = num_attribs;
if (num_attribs != 0 && attribs != NULL)
memcpy(sent_attribs, attribs, num_attribs * 2 * sizeof(uint32_t));
xcb_void_cookie_t cookie;
cookie.sequence = 0xbadc0de;
return cookie;
}
extern "C" xcb_generic_error_t *
xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie)
{
return NULL;
}
extern "C" void
__glXSendErrorForXcb(Display * dpy, const xcb_generic_error_t *err)
{
}
extern "C" void
__glXSendError(Display * dpy, int_fast8_t errorCode, uint_fast32_t resourceID,
uint_fast16_t minorCode, bool coreX11error)
{
}
class glXCreateContextAttribARB_test : public ::testing::Test {
public:
virtual void SetUp();
/**
* Replace the existing screen with a direct-rendering screen
*/
void use_direct_rendering_screen();
mock_XDisplay *dpy;
struct glx_config fbc;
};
void
glXCreateContextAttribARB_test::SetUp()
{
CreateContextAttribsARB_was_sent = false;
memset(&req, 0, sizeof(req));
next_id = 99;
fake_glx_context::contexts_allocated = 0;
psc = new fake_glx_screen(NULL, 0, "");
this->dpy = new mock_XDisplay(1);
memset(&this->fbc, 0, sizeof(this->fbc));
this->fbc.fbconfigID = 0xbeefcafe;
}
void
glXCreateContextAttribARB_test::use_direct_rendering_screen()
{
struct glx_screen *direct_psc =
new fake_glx_screen_direct(psc->display,
psc->scr,
psc->serverGLXexts);
delete psc;
psc = direct_psc;
}
/**
* \name Verify detection of client-side errors
*/
/*@{*/
TEST_F(glXCreateContextAttribARB_test, NULL_display_returns_None)
{
GLXContext ctx =
glXCreateContextAttribsARB(NULL, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_EQ(None, ctx);
EXPECT_EQ(0, fake_glx_context::contexts_allocated);
}
TEST_F(glXCreateContextAttribARB_test, NULL_fbconfig_returns_None)
{
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, NULL, 0, False, NULL);
EXPECT_EQ(None, ctx);
EXPECT_EQ(0, fake_glx_context::contexts_allocated);
}
TEST_F(glXCreateContextAttribARB_test, NULL_screen_returns_None)
{
delete psc;
psc = NULL;
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_EQ(None, ctx);
EXPECT_EQ(0, fake_glx_context::contexts_allocated);
}
/*@}*/
/**
* \name Verify that correct protocol bits are sent to the server.
*/
/*@{*/
TEST_F(glXCreateContextAttribARB_test, does_send_protocol)
{
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_TRUE(CreateContextAttribsARB_was_sent);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_context)
{
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_EQ(99u, req.context);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_fbconfig)
{
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_EQ(0xbeefcafe, req.fbconfig);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_share_list)
{
GLXContext share =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
ASSERT_NE((GLXContext) 0, share);
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, share,
False, NULL);
struct glx_context *glx_ctx = (struct glx_context *) share;
EXPECT_EQ(glx_ctx->xid, req.share_list);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_is_direct_for_indirect_screen_and_direct_set_to_true)
{
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
True, NULL);
EXPECT_FALSE(req.is_direct);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_is_direct_for_indirect_screen_and_direct_set_to_false)
{
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_FALSE(req.is_direct);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_is_direct_for_direct_screen_and_direct_set_to_true)
{
this->use_direct_rendering_screen();
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
True, NULL);
EXPECT_TRUE(req.is_direct);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_is_direct_for_direct_screen_and_direct_set_to_false)
{
this->use_direct_rendering_screen();
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_FALSE(req.is_direct);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_screen)
{
this->fbc.screen = 7;
psc->scr = 7;
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_EQ(7u, req.screen);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_num_attribs)
{
/* Use zeros in the second half of each attribute pair to try and trick the
* implementation into termiating the list early.
*
* Use non-zero in the second half of the last attribute pair to try and
* trick the implementation into not terminating the list early enough.
*/
static const int attribs[] = {
1, 0,
2, 0,
3, 0,
4, 0,
0, 6,
0, 0
};
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, attribs);
EXPECT_EQ(4u, req.num_attribs);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_num_attribs_empty_list)
{
static const int attribs[] = {
0,
};
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, attribs);
EXPECT_EQ(0u, req.num_attribs);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_num_attribs_NULL_list_pointer)
{
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
EXPECT_EQ(0u, req.num_attribs);
}
TEST_F(glXCreateContextAttribARB_test, sent_correct_attrib_list)
{
int attribs[] = {
GLX_RENDER_TYPE, GLX_RGBA_TYPE,
GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
0
};
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, attribs);
for (unsigned i = 0; i < 6; i++) {
EXPECT_EQ((uint32_t) attribs[i], sent_attribs[i]);
}
}
/*@}*/
/**
* \name Verify details of the returned GLXContext
*/
/*@{*/
TEST_F(glXCreateContextAttribARB_test, correct_context)
{
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
/* Since the server did not return an error, the GLXContext should not be
* NULL.
*/
EXPECT_NE((GLXContext)0, ctx);
/* It shouldn't be the XID of the context either.
*/
EXPECT_NE((GLXContext)99, ctx);
}
TEST_F(glXCreateContextAttribARB_test, correct_context_xid)
{
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
/* Since the server did not return an error, the GLXContext should not be
* NULL.
*/
ASSERT_NE((GLXContext)0, ctx);
struct glx_context *glx_ctx = (struct glx_context *) ctx;
EXPECT_EQ(99u, glx_ctx->xid);
}
TEST_F(glXCreateContextAttribARB_test, correct_context_share_xid)
{
GLXContext first =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
ASSERT_NE((GLXContext) 0, first);
GLXContext second =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, first,
False, NULL);
ASSERT_NE((GLXContext) 0, second);
struct glx_context *share = (struct glx_context *) first;
struct glx_context *ctx = (struct glx_context *) second;
EXPECT_EQ(share->xid, ctx->share_xid);
}
TEST_F(glXCreateContextAttribARB_test, correct_context_isDirect_for_indirect_screen_and_direct_set_to_true)
{
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
True, NULL);
ASSERT_NE((GLXContext) 0, ctx);
struct glx_context *gc = (struct glx_context *) ctx;
EXPECT_FALSE(gc->isDirect);
}
TEST_F(glXCreateContextAttribARB_test, correct_context_isDirect_for_indirect_screen_and_direct_set_to_false)
{
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
ASSERT_NE((GLXContext) 0, ctx);
struct glx_context *gc = (struct glx_context *) ctx;
EXPECT_FALSE(gc->isDirect);
}
TEST_F(glXCreateContextAttribARB_test, correct_context_isDirect_for_direct_screen_and_direct_set_to_true)
{
this->use_direct_rendering_screen();
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
True, NULL);
ASSERT_NE((GLXContext) 0, ctx);
struct glx_context *gc = (struct glx_context *) ctx;
EXPECT_TRUE(gc->isDirect);
}
TEST_F(glXCreateContextAttribARB_test, correct_context_isDirect_for_direct_screen_and_direct_set_to_false)
{
this->use_direct_rendering_screen();
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
ASSERT_NE((GLXContext) 0, ctx);
struct glx_context *gc = (struct glx_context *) ctx;
EXPECT_FALSE(gc->isDirect);
}
TEST_F(glXCreateContextAttribARB_test, correct_indirect_context_client_state_private)
{
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
ASSERT_NE((GLXContext) 0, ctx);
struct glx_context *gc = (struct glx_context *) ctx;
ASSERT_FALSE(gc->isDirect);
EXPECT_EQ((struct __GLXattributeRec *) 0xcafebabe,
gc->client_state_private);
}
TEST_F(glXCreateContextAttribARB_test, correct_indirect_context_config)
{
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
ASSERT_NE((GLXContext) 0, ctx);
struct glx_context *gc = (struct glx_context *) ctx;
EXPECT_EQ(&this->fbc, gc->config);
}
TEST_F(glXCreateContextAttribARB_test, correct_context_screen_number)
{
this->fbc.screen = 7;
psc->scr = 7;
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
ASSERT_NE((GLXContext) 0, ctx);
struct glx_context *gc = (struct glx_context *) ctx;
EXPECT_EQ(7, gc->screen);
}
TEST_F(glXCreateContextAttribARB_test, correct_context_screen_pointer)
{
GLXContext ctx =
glXCreateContextAttribsARB(this->dpy, (GLXFBConfig) &this->fbc, 0,
False, NULL);
ASSERT_NE((GLXContext) 0, ctx);
struct glx_context *gc = (struct glx_context *) ctx;
EXPECT_EQ(psc, gc->psc);
}
/*@}*/