aboutsummaryrefslogtreecommitdiffstats
path: root/src/glx/driwindows_glx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glx/driwindows_glx.c')
-rw-r--r--src/glx/driwindows_glx.c609
1 files changed, 609 insertions, 0 deletions
diff --git a/src/glx/driwindows_glx.c b/src/glx/driwindows_glx.c
new file mode 100644
index 00000000000..02d95e7bfd2
--- /dev/null
+++ b/src/glx/driwindows_glx.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright © 2014 Jon Turney
+ *
+ * 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 "glxclient.h"
+#include "glx_error.h"
+#include "dri_common.h"
+#include "windows/xwindowsdri.h"
+#include "windows/windowsgl.h"
+
+struct driwindows_display
+{
+ __GLXDRIdisplay base;
+ int event_base;
+};
+
+struct driwindows_context
+{
+ struct glx_context base;
+ windowsContext *windowsContext;
+};
+
+struct driwindows_config
+{
+ struct glx_config base;
+ int pxfi;
+};
+
+struct driwindows_screen
+{
+ struct glx_screen base;
+ __DRIscreen *driScreen;
+ __GLXDRIscreen vtable;
+ Bool copySubBuffer;
+};
+
+struct driwindows_drawable
+{
+ __GLXDRIdrawable base;
+ windowsDrawable *windowsDrawable;
+};
+
+/**
+ * GLXDRI functions
+ */
+
+static void
+driwindows_destroy_context(struct glx_context *context)
+{
+ struct driwindows_context *pcp = (struct driwindows_context *) context;
+
+ driReleaseDrawables(&pcp->base);
+
+ free((char *) context->extensions);
+
+ windows_destroy_context(pcp->windowsContext);
+
+ free(pcp);
+}
+
+static int
+driwindows_bind_context(struct glx_context *context, struct glx_context *old,
+ GLXDrawable draw, GLXDrawable read)
+{
+ struct driwindows_context *pcp = (struct driwindows_context *) context;
+ struct driwindows_drawable *pdraw, *pread;
+
+ pdraw = (struct driwindows_drawable *) driFetchDrawable(context, draw);
+ pread = (struct driwindows_drawable *) driFetchDrawable(context, read);
+
+ driReleaseDrawables(&pcp->base);
+
+ if (pdraw == NULL || pread == NULL)
+ return GLXBadDrawable;
+
+ if (windows_bind_context(pcp->windowsContext,
+ pdraw->windowsDrawable, pread->windowsDrawable))
+ return Success;
+
+ return GLXBadContext;
+}
+
+static void
+driwindows_unbind_context(struct glx_context *context, struct glx_context *new)
+{
+ struct driwindows_context *pcp = (struct driwindows_context *) context;
+
+ windows_unbind_context(pcp->windowsContext);
+}
+
+static void
+driwindows_bind_tex_image(Display * dpy,
+ GLXDrawable drawable,
+ int buffer, const int *attrib_list)
+{
+ struct glx_context *gc = __glXGetCurrentContext();
+ struct driwindows_context *pcp = (struct driwindows_context *) gc;
+ __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
+ struct driwindows_drawable *pdraw = (struct driwindows_drawable *) base;
+
+ __glXInitialize(dpy);
+
+ if (pdraw != NULL) {
+ windows_setTexBuffer(pcp->windowsContext,
+ pdraw->base.textureTarget,
+ pdraw->base.textureFormat,
+ pdraw->windowsDrawable);
+ }
+}
+
+static void
+driwindows_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
+{
+ struct glx_context *gc = __glXGetCurrentContext();
+ struct driwindows_context *pcp = (struct driwindows_context *) gc;
+ __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
+ struct glx_display *dpyPriv = __glXInitialize(dpy);
+ struct driwindows_drawable *pdraw = (struct driwindows_drawable *) base;
+
+ if (dpyPriv != NULL && pdraw != NULL) {
+ windows_releaseTexBuffer(pcp->windowsContext,
+ pdraw->base.textureTarget,
+ pdraw->windowsDrawable);
+ }
+}
+
+static const struct glx_context_vtable driwindows_context_vtable = {
+ .destroy = driwindows_destroy_context,
+ .bind = driwindows_bind_context,
+ .unbind = driwindows_unbind_context,
+ .wait_gl = NULL,
+ .wait_x = NULL,
+ .use_x_font = DRI_glXUseXFont,
+ .bind_tex_image = driwindows_bind_tex_image,
+ .release_tex_image = driwindows_release_tex_image,
+ .get_proc_address = NULL,
+};
+
+static struct glx_context *
+driwindows_create_context(struct glx_screen *base,
+ struct glx_config *config_base,
+ struct glx_context *shareList, int renderType)
+{
+ struct driwindows_context *pcp, *pcp_shared;
+ struct driwindows_config *config = (struct driwindows_config *) config_base;
+ struct driwindows_screen *psc = (struct driwindows_screen *) base;
+ windowsContext *shared = NULL;
+
+ if (!psc->base.driScreen)
+ return NULL;
+
+ /* Check the renderType value */
+ if (!validate_renderType_against_config(config_base, renderType))
+ return NULL;
+
+ if (shareList) {
+ /* If the shareList context is not on this renderer, we cannot possibly
+ * create a context that shares with it.
+ */
+ if (shareList->vtable->destroy != driwindows_destroy_context) {
+ return NULL;
+ }
+
+ pcp_shared = (struct driwindows_context *) shareList;
+ shared = pcp_shared->windowsContext;
+ }
+
+ pcp = calloc(1, sizeof *pcp);
+ if (pcp == NULL)
+ return NULL;
+
+ if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->base.renderType = renderType;
+
+ InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
+
+ pcp->windowsContext = windows_create_context(config->pxfi, shared);
+
+ if (!pcp->windowsContext) {
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->base.vtable = &driwindows_context_vtable;
+
+ return &pcp->base;
+}
+
+static struct glx_context *
+driwindows_create_context_attribs(struct glx_screen *base,
+ struct glx_config *config_base,
+ struct glx_context *shareList,
+ unsigned num_attribs,
+ const uint32_t *attribs,
+ unsigned *error)
+{
+ struct driwindows_context *pcp, *pcp_shared;
+ struct driwindows_config *config = (struct driwindows_config *) config_base;
+ struct driwindows_screen *psc = (struct driwindows_screen *) base;
+ windowsContext *shared = NULL;
+
+ int i;
+ uint32_t renderType = GLX_RGBA_TYPE;
+
+ /* Extract renderType from attribs */
+ for (i = 0; i < num_attribs; i++) {
+ switch (attribs[i * 2]) {
+ case GLX_RENDER_TYPE:
+ renderType = attribs[i * 2 + 1];
+ break;
+ }
+ }
+
+ /*
+ Perhaps we should map GLX tokens to WGL tokens, but they appear to have
+ identical values, so far
+ */
+
+ if (!psc->base.driScreen)
+ return NULL;
+
+ /* Check the renderType value */
+ if (!validate_renderType_against_config(config_base, renderType)) {
+ return NULL;
+ }
+
+ if (shareList) {
+ /* If the shareList context is not on this renderer, we cannot possibly
+ * create a context that shares with it.
+ */
+ if (shareList->vtable->destroy != driwindows_destroy_context) {
+ return NULL;
+ }
+
+ pcp_shared = (struct driwindows_context *) shareList;
+ shared = pcp_shared->windowsContext;
+ }
+
+ pcp = calloc(1, sizeof *pcp);
+ if (pcp == NULL)
+ return NULL;
+
+ if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->base.renderType = renderType;
+
+ InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
+
+ pcp->windowsContext = windows_create_context_attribs(config->pxfi,
+ shared,
+ (const int *)attribs);
+ if (pcp->windowsContext == NULL) {
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->base.vtable = &driwindows_context_vtable;
+
+ return &pcp->base;
+}
+
+static void
+driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw)
+{
+ struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
+
+ windows_destroy_drawable(pdp->windowsDrawable);
+
+ free(pdp);
+}
+
+static __GLXDRIdrawable *
+driwindowsCreateDrawable(struct glx_screen *base, XID xDrawable,
+ GLXDrawable drawable, struct glx_config *modes)
+{
+ struct driwindows_drawable *pdp;
+ struct driwindows_screen *psc = (struct driwindows_screen *) base;
+
+ pdp = calloc(1, sizeof(*pdp));
+ if (!pdp)
+ return NULL;
+
+ pdp->base.xDrawable = xDrawable;
+ pdp->base.drawable = drawable;
+ pdp->base.psc = &psc->base;
+
+ /*
+ By this stage, the X drawable already exists, but the GLX drawable may
+ not.
+
+ Query the server with the XID to find the correct HWND, HPBUFFERARB or
+ HBITMAP
+ */
+
+ unsigned int type;
+ void *handle;
+
+ if (!XWindowsDRIQueryDrawable(psc->base.dpy, base->scr, drawable, &type, &handle))
+ {
+ free(pdp);
+ return NULL;
+ }
+
+ /* No handle found is a failure */
+ if (!handle) {
+ free(pdp);
+ return NULL;
+ }
+
+ /* Create a new drawable */
+ pdp->windowsDrawable = windows_create_drawable(type, handle);
+
+ if (!pdp->windowsDrawable) {
+ free(pdp);
+ return NULL;
+ }
+
+ pdp->base.destroyDrawable = driwindowsDestroyDrawable;
+
+ return &pdp->base;
+}
+
+static int64_t
+driwindowsSwapBuffers(__GLXDRIdrawable * pdraw,
+ int64_t target_msc, int64_t divisor, int64_t remainder,
+ Bool flush)
+{
+ struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
+
+ (void) target_msc;
+ (void) divisor;
+ (void) remainder;
+
+ if (flush) {
+ glFlush();
+ }
+
+ windows_swap_buffers(pdp->windowsDrawable);
+
+ return 0;
+}
+
+static void
+driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw,
+ int x, int y, int width, int height, Bool flush)
+{
+ struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
+
+ if (flush) {
+ glFlush();
+ }
+
+ windows_copy_subbuffer(pdp->windowsDrawable, x, y, width, height);
+}
+
+static void
+driwindowsDestroyScreen(struct glx_screen *base)
+{
+ struct driwindows_screen *psc = (struct driwindows_screen *) base;
+
+ /* Free the direct rendering per screen data */
+ psc->driScreen = NULL;
+ free(psc);
+}
+
+static const struct glx_screen_vtable driwindows_screen_vtable = {
+ .create_context = driwindows_create_context,
+ .create_context_attribs = driwindows_create_context_attribs,
+ .query_renderer_integer = NULL,
+ .query_renderer_string = NULL,
+};
+
+static Bool
+driwindowsBindExtensions(struct driwindows_screen *psc)
+{
+ Bool result = 1;
+
+ const struct
+ {
+ char *wglext;
+ char *glxext;
+ Bool mandatory;
+ } extensionMap[] = {
+ { "WGL_ARB_make_current_read", "GLX_SGI_make_current_read", 0 },
+ { "WGL_EXT_swap_control", "GLX_SGI_swap_control", 0 },
+ { "WGL_EXT_swap_control", "GLX_MESA_swap_control", 0 },
+// { "WGL_ARB_render_texture", "GLX_EXT_texture_from_pixmap", 0 },
+// Not exactly equivalent, needs some more glue to be written
+ { "WGL_ARB_pbuffer", "GLX_SGIX_pbuffer", 1 },
+ { "WGL_ARB_multisample", "GLX_ARB_multisample", 1 },
+ { "WGL_ARB_multisample", "GLX_SGIS_multisample", 1 },
+ { "WGL_ARB_create_context", "GLX_ARB_create_context", 0 },
+ { "WGL_ARB_create_context_profile", "GLX_ARB_create_context_profile", 0 },
+ { "WGL_ARB_create_context_robustness", "GLX_ARB_create_context_robustness", 0 },
+ { "WGL_EXT_create_context_es2_profile", "GLX_EXT_create_context_es2_profile", 0 },
+ };
+
+ char *wgl_extensions;
+ char *gl_extensions;
+ int i;
+
+ windows_extensions(&gl_extensions, &wgl_extensions);
+
+ for (i = 0; i < sizeof(extensionMap)/sizeof(extensionMap[0]); i++) {
+ if (strstr(wgl_extensions, extensionMap[i].wglext)) {
+ __glXEnableDirectExtension(&psc->base, extensionMap[i].glxext);
+ InfoMessageF("enabled %s\n", extensionMap[i].glxext);
+ }
+ else if (extensionMap[i].mandatory) {
+ ErrorMessageF("required WGL extension %s is missing\n", extensionMap[i].wglext);
+ result = 0;
+ }
+ }
+
+ /*
+ Because it pre-dates WGL_EXT_extensions_string, GL_WIN_swap_hint might
+ only be in GL_EXTENSIONS
+ */
+ if (strstr(gl_extensions, "GL_WIN_swap_hint")) {
+ psc->copySubBuffer = 1;
+ __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
+ InfoMessageF("enabled GLX_MESA_copy_sub_buffer\n");
+ }
+
+ free(gl_extensions);
+ free(wgl_extensions);
+
+ return result;
+}
+
+static struct glx_config *
+driwindowsMapConfigs(struct glx_display *priv, int screen, struct glx_config *configs, struct glx_config *fbconfigs)
+{
+ struct glx_config head, *tail, *m;
+
+ tail = &head;
+ head.next = NULL;
+
+ for (m = configs; m; m = m->next) {
+ int fbconfigID = GLX_DONT_CARE;
+ if (fbconfigs) {
+ /*
+ visuals have fbconfigID of GLX_DONT_CARE, so search for a fbconfig
+ with matching visualID and get the fbconfigID from there
+ */
+ struct glx_config *f;
+ for (f = fbconfigs; f; f = f->next) {
+ if (f->visualID == m->visualID)
+ fbconfigID = f->fbconfigID;
+ }
+ }
+ else {
+ fbconfigID = m->fbconfigID;
+ }
+
+ int pxfi;
+ XWindowsDRIFBConfigToPixelFormat(priv->dpy, screen, fbconfigID, &pxfi);
+ if (pxfi == 0)
+ continue;
+
+ struct driwindows_config *config = malloc(sizeof(*config));
+
+ tail->next = &config->base;
+ if (tail->next == NULL)
+ continue;
+
+ config->base = *m;
+ config->pxfi = pxfi;
+
+ tail = tail->next;
+ }
+
+ return head.next;
+}
+
+static struct glx_screen *
+driwindowsCreateScreen(int screen, struct glx_display *priv)
+{
+ __GLXDRIscreen *psp;
+ struct driwindows_screen *psc;
+ struct glx_config *configs = NULL, *visuals = NULL;
+ int directCapable;
+
+ psc = calloc(1, sizeof *psc);
+ if (psc == NULL)
+ return NULL;
+
+ if (!glx_screen_init(&psc->base, screen, priv)) {
+ free(psc);
+ return NULL;
+ }
+
+ if (!XWindowsDRIQueryDirectRenderingCapable(psc->base.dpy, screen, &directCapable) ||
+ !directCapable) {
+ ErrorMessageF("Screen is not Windows-DRI capable\n");
+ goto handle_error;
+ }
+
+ /* discover native supported extensions */
+ if (!driwindowsBindExtensions(psc)) {
+ goto handle_error;
+ }
+
+ /* Augment configs with pxfi information */
+ configs = driwindowsMapConfigs(priv, screen, psc->base.configs, NULL);
+ visuals = driwindowsMapConfigs(priv, screen, psc->base.visuals, configs);
+
+ if (!configs || !visuals) {
+ ErrorMessageF("No fbConfigs or visuals found\n");
+ goto handle_error;
+ }
+
+ glx_config_destroy_list(psc->base.configs);
+ psc->base.configs = configs;
+ glx_config_destroy_list(psc->base.visuals);
+ psc->base.visuals = visuals;
+
+ psc->base.vtable = &driwindows_screen_vtable;
+ psp = &psc->vtable;
+ psc->base.driScreen = psp;
+ psp->destroyScreen = driwindowsDestroyScreen;
+ psp->createDrawable = driwindowsCreateDrawable;
+ psp->swapBuffers = driwindowsSwapBuffers;
+
+ if (psc->copySubBuffer)
+ psp->copySubBuffer = driwindowsCopySubBuffer;
+
+ return &psc->base;
+
+handle_error:
+ glx_screen_cleanup(&psc->base);
+
+ return NULL;
+}
+
+/* Called from __glXFreeDisplayPrivate.
+ */
+static void
+driwindowsDestroyDisplay(__GLXDRIdisplay * dpy)
+{
+ free(dpy);
+}
+
+/*
+ * Allocate, initialize and return a __GLXDRIdisplay object.
+ * This is called from __glXInitialize() when we are given a new
+ * display pointer.
+ */
+_X_HIDDEN __GLXDRIdisplay *
+driwindowsCreateDisplay(Display * dpy)
+{
+ struct driwindows_display *pdpyp;
+
+ int eventBase, errorBase;
+ int major, minor, patch;
+
+ /* Verify server has Windows-DRI extension */
+ if (!XWindowsDRIQueryExtension(dpy, &eventBase, &errorBase)) {
+ ErrorMessageF("Windows-DRI extension not available\n");
+ return NULL;
+ }
+
+ if (!XWindowsDRIQueryVersion(dpy, &major, &minor, &patch)) {
+ ErrorMessageF("Fetching Windows-DRI extension version failed\n");
+ return NULL;
+ }
+
+ if (!windows_check_renderer()) {
+ ErrorMessageF("Windows-DRI extension disabled for GDI Generic renderer\n");
+ return NULL;
+ }
+
+ pdpyp = malloc(sizeof *pdpyp);
+ if (pdpyp == NULL)
+ return NULL;
+
+ pdpyp->base.destroyDisplay = driwindowsDestroyDisplay;
+ pdpyp->base.createScreen = driwindowsCreateScreen;
+
+ pdpyp->event_base = eventBase;
+
+ return &pdpyp->base;
+}