2 * Copyright © 2014 Jon Turney
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 #include "glxclient.h"
25 #include "glx_error.h"
26 #include "dri_common.h"
27 #include "util/macros.h"
28 #include "windows/xwindowsdri.h"
29 #include "windows/windowsgl.h"
31 struct driwindows_display
37 struct driwindows_context
39 struct glx_context base
;
40 windowsContext
*windowsContext
;
43 struct driwindows_config
45 struct glx_config base
;
49 struct driwindows_screen
51 struct glx_screen base
;
52 __DRIscreen
*driScreen
;
53 __GLXDRIscreen vtable
;
57 struct driwindows_drawable
59 __GLXDRIdrawable base
;
60 windowsDrawable
*windowsDrawable
;
68 driwindows_destroy_context(struct glx_context
*context
)
70 struct driwindows_context
*pcp
= (struct driwindows_context
*) context
;
72 driReleaseDrawables(&pcp
->base
);
74 free((char *) context
->extensions
);
76 windows_destroy_context(pcp
->windowsContext
);
82 driwindows_bind_context(struct glx_context
*context
, struct glx_context
*old
,
83 GLXDrawable draw
, GLXDrawable read
)
85 struct driwindows_context
*pcp
= (struct driwindows_context
*) context
;
86 struct driwindows_drawable
*pdraw
, *pread
;
88 pdraw
= (struct driwindows_drawable
*) driFetchDrawable(context
, draw
);
89 pread
= (struct driwindows_drawable
*) driFetchDrawable(context
, read
);
91 driReleaseDrawables(&pcp
->base
);
93 if (pdraw
== NULL
|| pread
== NULL
)
94 return GLXBadDrawable
;
96 if (windows_bind_context(pcp
->windowsContext
,
97 pdraw
->windowsDrawable
, pread
->windowsDrawable
))
100 return GLXBadContext
;
104 driwindows_unbind_context(struct glx_context
*context
, struct glx_context
*new)
106 struct driwindows_context
*pcp
= (struct driwindows_context
*) context
;
108 windows_unbind_context(pcp
->windowsContext
);
112 driwindows_bind_tex_image(Display
* dpy
,
113 GLXDrawable drawable
,
114 int buffer
, const int *attrib_list
)
116 struct glx_context
*gc
= __glXGetCurrentContext();
117 struct driwindows_context
*pcp
= (struct driwindows_context
*) gc
;
118 __GLXDRIdrawable
*base
= GetGLXDRIDrawable(dpy
, drawable
);
119 struct driwindows_drawable
*pdraw
= (struct driwindows_drawable
*) base
;
121 __glXInitialize(dpy
);
124 windows_setTexBuffer(pcp
->windowsContext
,
125 pdraw
->base
.textureTarget
,
126 pdraw
->base
.textureFormat
,
127 pdraw
->windowsDrawable
);
132 driwindows_release_tex_image(Display
* dpy
, GLXDrawable drawable
, int buffer
)
134 struct glx_context
*gc
= __glXGetCurrentContext();
135 struct driwindows_context
*pcp
= (struct driwindows_context
*) gc
;
136 __GLXDRIdrawable
*base
= GetGLXDRIDrawable(dpy
, drawable
);
137 struct glx_display
*dpyPriv
= __glXInitialize(dpy
);
138 struct driwindows_drawable
*pdraw
= (struct driwindows_drawable
*) base
;
140 if (dpyPriv
!= NULL
&& pdraw
!= NULL
) {
141 windows_releaseTexBuffer(pcp
->windowsContext
,
142 pdraw
->base
.textureTarget
,
143 pdraw
->windowsDrawable
);
147 static const struct glx_context_vtable driwindows_context_vtable
= {
148 .destroy
= driwindows_destroy_context
,
149 .bind
= driwindows_bind_context
,
150 .unbind
= driwindows_unbind_context
,
153 .use_x_font
= DRI_glXUseXFont
,
154 .bind_tex_image
= driwindows_bind_tex_image
,
155 .release_tex_image
= driwindows_release_tex_image
,
156 .get_proc_address
= NULL
,
159 static struct glx_context
*
160 driwindows_create_context(struct glx_screen
*base
,
161 struct glx_config
*config_base
,
162 struct glx_context
*shareList
, int renderType
)
164 struct driwindows_context
*pcp
, *pcp_shared
;
165 struct driwindows_config
*config
= (struct driwindows_config
*) config_base
;
166 struct driwindows_screen
*psc
= (struct driwindows_screen
*) base
;
167 windowsContext
*shared
= NULL
;
169 if (!psc
->base
.driScreen
)
172 /* Check the renderType value */
173 if (!validate_renderType_against_config(config_base
, renderType
))
177 /* If the shareList context is not on this renderer, we cannot possibly
178 * create a context that shares with it.
180 if (shareList
->vtable
->destroy
!= driwindows_destroy_context
) {
184 pcp_shared
= (struct driwindows_context
*) shareList
;
185 shared
= pcp_shared
->windowsContext
;
188 pcp
= calloc(1, sizeof *pcp
);
192 if (!glx_context_init(&pcp
->base
, &psc
->base
, &config
->base
)) {
197 pcp
->base
.renderType
= renderType
;
199 InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base
->visualID
, config_base
->fbconfigID
, config
->pxfi
);
201 pcp
->windowsContext
= windows_create_context(config
->pxfi
, shared
);
203 if (!pcp
->windowsContext
) {
208 pcp
->base
.vtable
= &driwindows_context_vtable
;
213 static struct glx_context
*
214 driwindows_create_context_attribs(struct glx_screen
*base
,
215 struct glx_config
*config_base
,
216 struct glx_context
*shareList
,
217 unsigned num_attribs
,
218 const uint32_t *attribs
,
221 struct driwindows_context
*pcp
, *pcp_shared
;
222 struct driwindows_config
*config
= (struct driwindows_config
*) config_base
;
223 struct driwindows_screen
*psc
= (struct driwindows_screen
*) base
;
224 windowsContext
*shared
= NULL
;
227 uint32_t renderType
= GLX_RGBA_TYPE
;
229 /* Extract renderType from attribs */
230 for (i
= 0; i
< num_attribs
; i
++) {
231 switch (attribs
[i
* 2]) {
232 case GLX_RENDER_TYPE
:
233 renderType
= attribs
[i
* 2 + 1];
239 Perhaps we should map GLX tokens to WGL tokens, but they appear to have
240 identical values, so far
243 if (!psc
->base
.driScreen
)
246 /* Check the renderType value */
247 if (!validate_renderType_against_config(config_base
, renderType
)) {
252 /* If the shareList context is not on this renderer, we cannot possibly
253 * create a context that shares with it.
255 if (shareList
->vtable
->destroy
!= driwindows_destroy_context
) {
259 pcp_shared
= (struct driwindows_context
*) shareList
;
260 shared
= pcp_shared
->windowsContext
;
263 pcp
= calloc(1, sizeof *pcp
);
267 if (!glx_context_init(&pcp
->base
, &psc
->base
, &config
->base
)) {
272 pcp
->base
.renderType
= renderType
;
274 InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base
->visualID
, config_base
->fbconfigID
, config
->pxfi
);
276 pcp
->windowsContext
= windows_create_context_attribs(config
->pxfi
,
278 (const int *)attribs
);
279 if (pcp
->windowsContext
== NULL
) {
284 pcp
->base
.vtable
= &driwindows_context_vtable
;
290 driwindowsDestroyDrawable(__GLXDRIdrawable
* pdraw
)
292 struct driwindows_drawable
*pdp
= (struct driwindows_drawable
*) pdraw
;
294 windows_destroy_drawable(pdp
->windowsDrawable
);
299 static __GLXDRIdrawable
*
300 driwindowsCreateDrawable(struct glx_screen
*base
, XID xDrawable
,
301 GLXDrawable drawable
, struct glx_config
*modes
)
303 struct driwindows_drawable
*pdp
;
304 struct driwindows_screen
*psc
= (struct driwindows_screen
*) base
;
306 pdp
= calloc(1, sizeof(*pdp
));
310 pdp
->base
.xDrawable
= xDrawable
;
311 pdp
->base
.drawable
= drawable
;
312 pdp
->base
.psc
= &psc
->base
;
315 By this stage, the X drawable already exists, but the GLX drawable may
318 Query the server with the XID to find the correct HWND, HPBUFFERARB or
325 if (!XWindowsDRIQueryDrawable(psc
->base
.dpy
, base
->scr
, drawable
, &type
, &handle
))
331 /* No handle found is a failure */
337 /* Create a new drawable */
338 pdp
->windowsDrawable
= windows_create_drawable(type
, handle
);
340 if (!pdp
->windowsDrawable
) {
345 pdp
->base
.destroyDrawable
= driwindowsDestroyDrawable
;
351 driwindowsSwapBuffers(__GLXDRIdrawable
* pdraw
,
352 int64_t target_msc
, int64_t divisor
, int64_t remainder
,
355 struct driwindows_drawable
*pdp
= (struct driwindows_drawable
*) pdraw
;
365 windows_swap_buffers(pdp
->windowsDrawable
);
371 driwindowsCopySubBuffer(__GLXDRIdrawable
* pdraw
,
372 int x
, int y
, int width
, int height
, Bool flush
)
374 struct driwindows_drawable
*pdp
= (struct driwindows_drawable
*) pdraw
;
380 windows_copy_subbuffer(pdp
->windowsDrawable
, x
, y
, width
, height
);
384 driwindowsDestroyScreen(struct glx_screen
*base
)
386 struct driwindows_screen
*psc
= (struct driwindows_screen
*) base
;
388 /* Free the direct rendering per screen data */
389 psc
->driScreen
= NULL
;
393 static const struct glx_screen_vtable driwindows_screen_vtable
= {
394 .create_context
= driwindows_create_context
,
395 .create_context_attribs
= driwindows_create_context_attribs
,
396 .query_renderer_integer
= NULL
,
397 .query_renderer_string
= NULL
,
401 driwindowsBindExtensions(struct driwindows_screen
*psc
)
411 { "WGL_ARB_make_current_read", "GLX_SGI_make_current_read", 0 },
412 { "WGL_EXT_swap_control", "GLX_SGI_swap_control", 0 },
413 { "WGL_EXT_swap_control", "GLX_MESA_swap_control", 0 },
414 // { "WGL_ARB_render_texture", "GLX_EXT_texture_from_pixmap", 0 },
415 // Not exactly equivalent, needs some more glue to be written
416 { "WGL_ARB_pbuffer", "GLX_SGIX_pbuffer", 1 },
417 { "WGL_ARB_multisample", "GLX_ARB_multisample", 1 },
418 { "WGL_ARB_multisample", "GLX_SGIS_multisample", 1 },
419 { "WGL_ARB_create_context", "GLX_ARB_create_context", 0 },
420 { "WGL_ARB_create_context_profile", "GLX_ARB_create_context_profile", 0 },
421 { "WGL_ARB_create_context_robustness", "GLX_ARB_create_context_robustness", 0 },
422 { "WGL_EXT_create_context_es2_profile", "GLX_EXT_create_context_es2_profile", 0 },
425 char *wgl_extensions
;
429 windows_extensions(&gl_extensions
, &wgl_extensions
);
431 for (i
= 0; i
< ARRAY_SIZE(extensionMap
); i
++) {
432 if (strstr(wgl_extensions
, extensionMap
[i
].wglext
)) {
433 __glXEnableDirectExtension(&psc
->base
, extensionMap
[i
].glxext
);
434 InfoMessageF("enabled %s\n", extensionMap
[i
].glxext
);
436 else if (extensionMap
[i
].mandatory
) {
437 ErrorMessageF("required WGL extension %s is missing\n", extensionMap
[i
].wglext
);
443 Because it pre-dates WGL_EXT_extensions_string, GL_WIN_swap_hint might
444 only be in GL_EXTENSIONS
446 if (strstr(gl_extensions
, "GL_WIN_swap_hint")) {
447 psc
->copySubBuffer
= 1;
448 __glXEnableDirectExtension(&psc
->base
, "GLX_MESA_copy_sub_buffer");
449 InfoMessageF("enabled GLX_MESA_copy_sub_buffer\n");
453 free(wgl_extensions
);
458 static struct glx_config
*
459 driwindowsMapConfigs(struct glx_display
*priv
, int screen
, struct glx_config
*configs
, struct glx_config
*fbconfigs
)
461 struct glx_config head
, *tail
, *m
;
466 for (m
= configs
; m
; m
= m
->next
) {
467 int fbconfigID
= GLX_DONT_CARE
;
470 visuals have fbconfigID of GLX_DONT_CARE, so search for a fbconfig
471 with matching visualID and get the fbconfigID from there
473 struct glx_config
*f
;
474 for (f
= fbconfigs
; f
; f
= f
->next
) {
475 if (f
->visualID
== m
->visualID
)
476 fbconfigID
= f
->fbconfigID
;
480 fbconfigID
= m
->fbconfigID
;
484 XWindowsDRIFBConfigToPixelFormat(priv
->dpy
, screen
, fbconfigID
, &pxfi
);
488 struct driwindows_config
*config
= malloc(sizeof(*config
));
490 tail
->next
= &config
->base
;
491 if (tail
->next
== NULL
)
503 static struct glx_screen
*
504 driwindowsCreateScreen(int screen
, struct glx_display
*priv
)
507 struct driwindows_screen
*psc
;
508 struct glx_config
*configs
= NULL
, *visuals
= NULL
;
511 psc
= calloc(1, sizeof *psc
);
515 if (!glx_screen_init(&psc
->base
, screen
, priv
)) {
520 if (!XWindowsDRIQueryDirectRenderingCapable(psc
->base
.dpy
, screen
, &directCapable
) ||
522 ErrorMessageF("Screen is not Windows-DRI capable\n");
526 /* discover native supported extensions */
527 if (!driwindowsBindExtensions(psc
)) {
531 /* Augment configs with pxfi information */
532 configs
= driwindowsMapConfigs(priv
, screen
, psc
->base
.configs
, NULL
);
533 visuals
= driwindowsMapConfigs(priv
, screen
, psc
->base
.visuals
, configs
);
535 if (!configs
|| !visuals
) {
536 ErrorMessageF("No fbConfigs or visuals found\n");
540 glx_config_destroy_list(psc
->base
.configs
);
541 psc
->base
.configs
= configs
;
542 glx_config_destroy_list(psc
->base
.visuals
);
543 psc
->base
.visuals
= visuals
;
545 psc
->base
.vtable
= &driwindows_screen_vtable
;
547 psc
->base
.driScreen
= psp
;
548 psp
->destroyScreen
= driwindowsDestroyScreen
;
549 psp
->createDrawable
= driwindowsCreateDrawable
;
550 psp
->swapBuffers
= driwindowsSwapBuffers
;
552 if (psc
->copySubBuffer
)
553 psp
->copySubBuffer
= driwindowsCopySubBuffer
;
558 glx_screen_cleanup(&psc
->base
);
563 /* Called from __glXFreeDisplayPrivate.
566 driwindowsDestroyDisplay(__GLXDRIdisplay
* dpy
)
572 * Allocate, initialize and return a __GLXDRIdisplay object.
573 * This is called from __glXInitialize() when we are given a new
576 _X_HIDDEN __GLXDRIdisplay
*
577 driwindowsCreateDisplay(Display
* dpy
)
579 struct driwindows_display
*pdpyp
;
581 int eventBase
, errorBase
;
582 int major
, minor
, patch
;
584 /* Verify server has Windows-DRI extension */
585 if (!XWindowsDRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
586 ErrorMessageF("Windows-DRI extension not available\n");
590 if (!XWindowsDRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
591 ErrorMessageF("Fetching Windows-DRI extension version failed\n");
595 if (!windows_check_renderer()) {
596 ErrorMessageF("Windows-DRI extension disabled for GDI Generic renderer\n");
600 pdpyp
= malloc(sizeof *pdpyp
);
604 pdpyp
->base
.destroyDisplay
= driwindowsDestroyDisplay
;
605 pdpyp
->base
.createScreen
= driwindowsCreateScreen
;
607 pdpyp
->event_base
= eventBase
;