mirror of https://gitlab.freedesktop.org/mesa/mesa
610 lines
17 KiB
C
610 lines
17 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|