I'm trying to use my XCB implementation with OpenGL but I encountered an error.
The problem is in the code below:
#include <dlfcn.h>
#include <iostream>
#include <xcb/xcb.h>
#include <X11/keysym.h>
#include <X11/XKBlib.h>
#include <X11/Xlib.h>
#include <X11/Xlib-xcb.h>
#include <sys/time.h>
#include <time.h>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <memory>
#include <GL/glx.h>
#include <GL/gl.h>
struct LinuxPlatformInternalState
{
Display *display;
xcb_connection_t *connection;
xcb_window_t window;
xcb_screen_t *screen;
xcb_atom_t wmDeleteProtocols;
xcb_atom_t wmDestroyWindow;
int screenCount;
};
static const int visualAttribs[] =
{
GLX_X_RENDERABLE, True,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_STENCIL_SIZE, 8,
GLX_DOUBLEBUFFER, True,
None};
int _getEventsMask()
{
return XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
}
unsigned int _getEventsValue()
{
return XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_STRUCTURE_NOTIFY;
}
int main(int argc, char **argv)
{
std::shared_ptr<LinuxPlatformInternalState> m_pstate = std::make_shared<LinuxPlatformInternalState>();
// connect to X Server
m_pstate->display = XOpenDisplay(0);
if (m_pstate->display == nullptr)
{
return false;
}
XAutoRepeatOff(m_pstate->display);
m_pstate->screenCount = XScreenCount(m_pstate->display);
// init XCB
m_pstate->connection = XGetXCBConnection(m_pstate->display);
if (m_pstate->connection == nullptr || xcb_connection_has_error(m_pstate->connection))
{
return false;
}
const xcb_setup_t *setup = xcb_get_setup(m_pstate->connection);
m_pstate->screen = xcb_setup_roots_iterator(setup).data;
m_pstate->window = xcb_generate_id(m_pstate->connection);
int eventsMask = _getEventsMask();
u_int32_t eventValues = _getEventsValue();
u_int32_t valueList[] = {m_pstate->screen->black_pixel, eventValues};
xcb_void_cookie_t cookie = xcb_create_window(
m_pstate->connection,
XCB_COPY_FROM_PARENT,
m_pstate->window,
m_pstate->screen->root,
0,
0,
800,
600,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
m_pstate->screen->root_visual,
eventsMask,
valueList);
if (cookie.sequence == 0)
{
return false;
}
std::string appName = "Test";
// change window title
xcb_change_property(
m_pstate->connection,
XCB_PROP_MODE_REPLACE,
m_pstate->window,
XCB_ATOM_WM_NAME,
XCB_ATOM_STRING,
0,
appName.length(),
appName.c_str());
xcb_void_cookie_t mappingCookie = xcb_map_window(m_pstate->connection, m_pstate->window);
if (mappingCookie.sequence == 0)
{
return -1;
}
// flush the stream
int flushResult = xcb_flush(m_pstate->connection);
if (flushResult <= 0)
{
return -1;
}
int numFbConfigs = 0;
int visualId = 0;
int defaultScreen = DefaultScreen(m_pstate->display);
GLXFBConfig *frameBufferConfigs = glXChooseFBConfig(m_pstate->display, defaultScreen, visualAttribs, &numFbConfigs);
if (!frameBufferConfigs || numFbConfigs <= 0)
{
if (frameBufferConfigs)
{
XFree(frameBufferConfigs);
}
return -1;
}
bool configFound = false;
for (int i = 0; i < numFbConfigs; ++i)
{
if (!glXGetFBConfigAttrib(m_pstate->display, frameBufferConfigs[i], GLX_VISUAL_ID, &visualId))
{
continue;
}
GLXContext context = glXCreateNewContext(m_pstate->display, frameBufferConfigs[i], GLX_RGBA_TYPE, 0, True);
if (!context)
{
continue;
}
GLXDrawable drawable = 0;
if (!m_pstate->window)
{
glXDestroyContext(m_pstate->display, context);
XFree(frameBufferConfigs);
continue;
}
GLXWindow glxwindow = glXCreateWindow(m_pstate->display, frameBufferConfigs[i], m_pstate->window, 0);
if (!glxwindow)
{
glXDestroyContext(m_pstate->display, context);
XFree(frameBufferConfigs);
continue;
}
drawable = glxwindow;
bool glxMakeCtxCurrentRes = glXMakeContextCurrent(m_pstate->display, drawable, drawable, context);
if (!glxMakeCtxCurrentRes)
{
glXDestroyContext(m_pstate->display, context);
glXDestroyWindow(m_pstate->display, glxwindow);
XFree(frameBufferConfigs);
continue;
}
configFound = true;
break;
}
if (!configFound)
{
XFree(frameBufferConfigs);
return -1;
}
XFree(frameBufferConfigs);
return 0;
}
When I'm trying to execute it, it gives the following output:
X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 18 (X_ChangeProperty)
Value in failed request: 0x0
Serial number of failed request: 9
Current serial number in output stream: 13
The problem seems to be related to the integer parameter defaultScreen
. I'm pretty confident m_pstate->display
is not the malformed or anything because I used it on another implementation of Vulkan in the same project without any issue, Of course the xcb_open_window
call worked fine.
Anyone has some kind of idea of what is the problem?
The problem is in xcb_change_property
call. The permissible values for the format
parameter are 8, 16 and 32. You are passing 0.
Since your data is a byte-string, you need to pass 8. This at least makes the program open a window in my experiment, and its title is Test
as expected.