X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=glws_glx.cpp;h=c151db1c07fb91914c070699cc79fec4bc49f076;hb=ad60fd108d331796173ad54356855d9a2d0d87ba;hp=67a88290b7988804bb0f3c4c16c30fc083d6451a;hpb=f96d9029afc1b416750e38ba7176efd301ed079b;p=apitrace diff --git a/glws_glx.cpp b/glws_glx.cpp index 67a8829..c151db1 100644 --- a/glws_glx.cpp +++ b/glws_glx.cpp @@ -23,20 +23,35 @@ * **************************************************************************/ -#include "glimports.hpp" +#include +#include + +#include + +#include "glproc.hpp" #include "glws.hpp" namespace glws { +static Display *display = NULL; +static int screen = 0; + +static unsigned glxVersion = 0; +static const char *extensions = 0; +static bool has_GLX_ARB_create_context = false; + + class GlxVisual : public Visual { public: + GLXFBConfig fbconfig; XVisualInfo *visinfo; - GlxVisual(XVisualInfo *vi) : - visinfo(vi) + GlxVisual() : + fbconfig(0), + visinfo(0) {} ~GlxVisual() { @@ -45,26 +60,136 @@ public: }; +static void describeEvent(const XEvent &event) { + if (0) { + switch (event.type) { + case ConfigureNotify: + std::cerr << "ConfigureNotify"; + break; + case Expose: + std::cerr << "Expose"; + break; + case KeyPress: + std::cerr << "KeyPress"; + break; + case MapNotify: + std::cerr << "MapNotify"; + break; + case ReparentNotify: + std::cerr << "ReparentNotify"; + break; + default: + std::cerr << "Event " << event.type; + } + std::cerr << " " << event.xany.window << "\n"; + } +} + class GlxDrawable : public Drawable { public: - Display *display; Window window; - GlxDrawable(const Visual *vis, Display *dpy, Window win) : - Drawable(vis), - display(dpy), - window(win) - {} + GlxDrawable(const Visual *vis, int w, int h) : + Drawable(vis, w, h) + { + XVisualInfo *visinfo = static_cast(visual)->visinfo; + + Window root = RootWindow(display, screen); + + /* window attributes */ + XSetWindowAttributes attr; + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask; + + unsigned long mask; + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + int x = 0, y = 0; + + window = XCreateWindow( + display, root, + x, y, width, height, + 0, + visinfo->depth, + InputOutput, + visinfo->visual, + mask, + &attr); + + XSizeHints sizehints; + sizehints.x = x; + sizehints.y = y; + sizehints.width = width; + sizehints.height = height; + sizehints.flags = USSize | USPosition; + XSetNormalHints(display, window, &sizehints); + + const char *name = "glretrace"; + XSetStandardProperties( + display, window, name, name, + None, (char **)NULL, 0, &sizehints); + + glXWaitX(); + } + + void waitForEvent(int type) { + XEvent event; + do { + XWindowEvent(display, window, StructureNotifyMask, &event); + describeEvent(event); + } while (event.type != type); + } ~GlxDrawable() { XDestroyWindow(display, window); } - + void - resize(unsigned w, unsigned h) { + resize(int w, int h) { + if (w == width && h == height) { + return; + } + + glXWaitGL(); + + // We need to ensure that pending events are processed here, and XSync + // with discard = True guarantees that, but it appears the limited + // event processing we do so far is sufficient + //XSync(display, True); + Drawable::resize(w, h); + XResizeWindow(display, window, w, h); + + // Tell the window manager to respect the requested size + XSizeHints size_hints; + size_hints.max_width = size_hints.min_width = w; + size_hints.max_height = size_hints.min_height = h; + size_hints.flags = PMinSize | PMaxSize; + XSetWMNormalHints(display, window, &size_hints); + + waitForEvent(ConfigureNotify); + + glXWaitX(); + } + + void show(void) { + if (visible) { + return; + } + + glXWaitGL(); + + XMapWindow(display, window); + + waitForEvent(MapNotify); + + glXWaitX(); + + Drawable::show(); } void swapBuffers(void) { @@ -76,12 +201,10 @@ public: class GlxContext : public Context { public: - Display *display; GLXContext context; - - GlxContext(const Visual *vis, Display *dpy, GLXContext ctx) : - Context(vis), - display(dpy), + + GlxContext(const Visual *vis, Profile prof, GLXContext ctx) : + Context(vis, prof), context(ctx) {} @@ -90,136 +213,165 @@ public: } }; +void +init(void) { + display = XOpenDisplay(NULL); + if (!display) { + std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n"; + exit(1); + } -class GlxWindowSystem : public WindowSystem -{ -private: - Display *display; - int screen; + screen = DefaultScreen(display); -public: - GlxWindowSystem() { - display = XOpenDisplay(NULL); - screen = DefaultScreen(display); - } + int major = 0, minor = 0; + glXQueryVersion(display, &major, &minor); + glxVersion = (major << 8) | minor; + + extensions = glXQueryExtensionsString(display, screen); + has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions); +} - ~GlxWindowSystem() { +void +cleanup(void) { + if (display) { XCloseDisplay(display); + display = NULL; } +} - Visual * - createVisual(bool doubleBuffer) { - int single_attribs[] = { - GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DEPTH_SIZE, 1, - GLX_STENCIL_SIZE, 1, - None - }; - - int double_attribs[] = { - GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, 1, - GLX_STENCIL_SIZE, 1, - None - }; - - XVisualInfo *visinfo; - - visinfo = glXChooseVisual(display, screen, doubleBuffer ? double_attribs : single_attribs); +Visual * +createVisual(bool doubleBuffer, Profile profile) { + if (profile != PROFILE_COMPAT && + profile != PROFILE_CORE) { + return NULL; + } + + GlxVisual *visual = new GlxVisual; + + if (glxVersion >= 0x0103) { + Attributes attribs; + attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT); + attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT); + attribs.add(GLX_RED_SIZE, 1); + attribs.add(GLX_GREEN_SIZE, 1); + attribs.add(GLX_BLUE_SIZE, 1); + attribs.add(GLX_ALPHA_SIZE, 1); + attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE); + attribs.add(GLX_DEPTH_SIZE, 1); + attribs.add(GLX_STENCIL_SIZE, 1); + attribs.end(); + + int num_configs = 0; + GLXFBConfig * fbconfigs; + fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs); + assert(num_configs && fbconfigs); + visual->fbconfig = fbconfigs[0]; + assert(visual->fbconfig); + visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig); + assert(visual->visinfo); + } else { + Attributes attribs; + attribs.add(GLX_RGBA); + attribs.add(GLX_RED_SIZE, 1); + attribs.add(GLX_GREEN_SIZE, 1); + attribs.add(GLX_BLUE_SIZE, 1); + attribs.add(GLX_ALPHA_SIZE, 1); + if (doubleBuffer) { + attribs.add(GLX_DOUBLEBUFFER); + } + attribs.add(GLX_DEPTH_SIZE, 1); + attribs.add(GLX_STENCIL_SIZE, 1); + attribs.end(); - return new GlxVisual(visinfo); + visual->visinfo = glXChooseVisual(display, screen, attribs); } - - Drawable * - createDrawable(const Visual *visual) - { - XVisualInfo *visinfo = dynamic_cast(visual)->visinfo; - Window root = RootWindow(display, screen); + return visual; +} - /* window attributes */ - XSetWindowAttributes attr; - attr.background_pixel = 0; - attr.border_pixel = 0; - attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone); - attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; - - unsigned long mask; - mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; +Drawable * +createDrawable(const Visual *visual, int width, int height) +{ + return new GlxDrawable(visual, width, height); +} - int x = 0, y = 0, width = 256, height = 256; +Context * +createContext(const Visual *_visual, Context *shareContext, Profile profile) +{ + const GlxVisual *visual = static_cast(_visual); + GLXContext share_context = NULL; + GLXContext context; - Window window = XCreateWindow( - display, root, - x, y, width, height, - 0, - visinfo->depth, - InputOutput, - visinfo->visual, - mask, - &attr); + if (shareContext) { + share_context = static_cast(shareContext)->context; + } - XSizeHints sizehints; - sizehints.x = x; - sizehints.y = y; - sizehints.width = width; - sizehints.height = height; - sizehints.flags = USSize | USPosition; - XSetNormalHints(display, window, &sizehints); + if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) { + Attributes attribs; - const char *name = "glretrace"; - XSetStandardProperties( - display, window, name, name, - None, (char **)NULL, 0, &sizehints); + attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE); + if (debug) { + attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB); + } - XMapWindow(display, window); + switch (profile) { + case PROFILE_COMPAT: + break; + case PROFILE_CORE: + // XXX: This will invariable return a 3.2 context, when supported. + // We probably should have a PROFILE_CORE_XX per version. + attribs.add(GLX_CONTEXT_MAJOR_VERSION_ARB, 3); + attribs.add(GLX_CONTEXT_MINOR_VERSION_ARB, 2); + attribs.add(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB); + break; + default: + return NULL; + } - return new GlxDrawable(visual, display, window); - } + attribs.end(); - Context * - createContext(const Visual *visual) - { - XVisualInfo *visinfo = dynamic_cast(visual)->visinfo; - GLXContext context = glXCreateContext(display, visinfo, NULL, True); - return new GlxContext(visual, display, context); - } + context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs); + } else { + if (profile != PROFILE_COMPAT) { + return NULL; + } - bool - makeCurrent(Drawable *drawable, Context *context) - { - if (!drawable || !context) { - return glXMakeCurrent(display, None, NULL); + if (glxVersion >= 0x103) { + context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True); } else { - GlxDrawable *glxDrawable = dynamic_cast(drawable); - GlxContext *glxContext = dynamic_cast(context); - - return glXMakeCurrent(display, glxDrawable->window, glxContext->context); + context = glXCreateContext(display, visual->visinfo, share_context, True); } } - bool - processEvents(void) { - while (XPending(display) > 0) { - XEvent event; - XNextEvent(display, &event); - // TODO - } - return true; + if (!context) { + return NULL; } -}; + return new GlxContext(visual, profile, context); +} + +bool +makeCurrent(Drawable *drawable, Context *context) +{ + if (!drawable || !context) { + return glXMakeCurrent(display, None, NULL); + } else { + GlxDrawable *glxDrawable = static_cast(drawable); + GlxContext *glxContext = static_cast(context); -WindowSystem *createNativeWindowSystem(void) { - return new GlxWindowSystem(); + return glXMakeCurrent(display, glxDrawable->window, glxContext->context); + } +} + +bool +processEvents(void) { + while (XPending(display) > 0) { + XEvent event; + XNextEvent(display, &event); + describeEvent(event); + } + return true; } -} /* namespace glretrace */ +} /* namespace glws */