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 "windows/xwindowsdri.h"
28 #include "windows/windowsgl.h"
30 struct driwindows_display
36 struct driwindows_context
38 struct glx_context base
;
39 windowsContext
*windowsContext
;
42 struct driwindows_config
44 struct glx_config base
;
48 struct driwindows_screen
50 struct glx_screen base
;
51 __DRIscreen
*driScreen
;
52 __GLXDRIscreen vtable
;
56 struct driwindows_drawable
58 __GLXDRIdrawable base
;
59 windowsDrawable
*windowsDrawable
;
67 driwindows_destroy_context(struct glx_context
*context
)
69 struct driwindows_context
*pcp
= (struct driwindows_context
*) context
;
71 driReleaseDrawables(&pcp
->base
);
73 free((char *) context
->extensions
);
75 windows_destroy_context(pcp
->windowsContext
);
81 driwindows_bind_context(struct glx_context
*context
, struct glx_context
*old
,
82 GLXDrawable draw
, GLXDrawable read
)
84 struct driwindows_context
*pcp
= (struct driwindows_context
*) context
;
85 struct driwindows_drawable
*pdraw
, *pread
;
87 pdraw
= (struct driwindows_drawable
*) driFetchDrawable(context
, draw
);
88 pread
= (struct driwindows_drawable
*) driFetchDrawable(context
, read
);
90 driReleaseDrawables(&pcp
->base
);
92 if (pdraw
== NULL
|| pread
== NULL
)
93 return GLXBadDrawable
;
95 if (windows_bind_context(pcp
->windowsContext
,
96 pdraw
->windowsDrawable
, pread
->windowsDrawable
))
103 driwindows_unbind_context(struct glx_context
*context
, struct glx_context
*new)
105 struct driwindows_context
*pcp
= (struct driwindows_context
*) context
;
107 windows_unbind_context(pcp
->windowsContext
);
111 driwindows_bind_tex_image(Display
* dpy
,
112 GLXDrawable drawable
,
113 int buffer
, const int *attrib_list
)
115 struct glx_context
*gc
= __glXGetCurrentContext();
116 struct driwindows_context
*pcp
= (struct driwindows_context
*) gc
;
117 __GLXDRIdrawable
*base
= GetGLXDRIDrawable(dpy
, drawable
);
118 struct driwindows_drawable
*pdraw
= (struct driwindows_drawable
*) base
;
120 __glXInitialize(dpy
);
123 windows_setTexBuffer(pcp
->windowsContext
,
124 pdraw
->base
.textureTarget
,
125 pdraw
->base
.textureFormat
,
126 pdraw
->windowsDrawable
);
131 driwindows_release_tex_image(Display
* dpy
, GLXDrawable drawable
, int buffer
)
133 struct glx_context
*gc
= __glXGetCurrentContext();
134 struct driwindows_context
*pcp
= (struct driwindows_context
*) gc
;
135 __GLXDRIdrawable
*base
= GetGLXDRIDrawable(dpy
, drawable
);
136 struct glx_display
*dpyPriv
= __glXInitialize(dpy
);
137 struct driwindows_drawable
*pdraw
= (struct driwindows_drawable
*) base
;
139 if (dpyPriv
!= NULL
&& pdraw
!= NULL
) {
140 windows_releaseTexBuffer(pcp
->windowsContext
,
141 pdraw
->base
.textureTarget
,
142 pdraw
->windowsDrawable
);
146 static const struct glx_context_vtable driwindows_context_vtable
= {
147 .destroy
= driwindows_destroy_context
,
148 .bind
= driwindows_bind_context
,
149 .unbind
= driwindows_unbind_context
,
152 .use_x_font
= DRI_glXUseXFont
,
153 .bind_tex_image
= driwindows_bind_tex_image
,
154 .release_tex_image
= driwindows_release_tex_image
,
155 .get_proc_address
= NULL
,
158 static struct glx_context
*
159 driwindows_create_context(struct glx_screen
*base
,
160 struct glx_config
*config_base
,
161 struct glx_context
*shareList
, int renderType
)
163 struct driwindows_context
*pcp
, *pcp_shared
;
164 struct driwindows_config
*config
= (struct driwindows_config
*) config_base
;
165 struct driwindows_screen
*psc
= (struct driwindows_screen
*) base
;
166 windowsContext
*shared
= NULL
;
168 if (!psc
->base
.driScreen
)
171 /* Check the renderType value */
172 if (!validate_renderType_against_config(config_base
, renderType
))
176 /* If the shareList context is not on this renderer, we cannot possibly
177 * create a context that shares with it.
179 if (shareList
->vtable
->destroy
!= driwindows_destroy_context
) {
183 pcp_shared
= (struct driwindows_context
*) shareList
;
184 shared
= pcp_shared
->windowsContext
;
187 pcp
= calloc(1, sizeof *pcp
);
191 if (!glx_context_init(&pcp
->base
, &psc
->base
, &config
->base
)) {
196 pcp
->base
.renderType
= renderType
;
198 InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base
->visualID
, config_base
->fbconfigID
, config
->pxfi
);
200 pcp
->windowsContext
= windows_create_context(config
->pxfi
, shared
);
202 if (!pcp
->windowsContext
) {
207 pcp
->base
.vtable
= &driwindows_context_vtable
;
212 static struct glx_context
*
213 driwindows_create_context_attribs(struct glx_screen
*base
,
214 struct glx_config
*config_base
,
215 struct glx_context
*shareList
,
216 unsigned num_attribs
,
217 const uint32_t *attribs
,
220 struct driwindows_context
*pcp
, *pcp_shared
;
221 struct driwindows_config
*config
= (struct driwindows_config
*) config_base
;
222 struct driwindows_screen
*psc
= (struct driwindows_screen
*) base
;
223 windowsContext
*shared
= NULL
;
226 uint32_t renderType
= GLX_RGBA_TYPE
;
228 /* Extract renderType from attribs */
229 for (i
= 0; i
< num_attribs
; i
++) {
230 switch (attribs
[i
* 2]) {
231 case GLX_RENDER_TYPE
:
232 renderType
= attribs
[i
* 2 + 1];
238 Perhaps we should map GLX tokens to WGL tokens, but they appear to have
239 identical values, so far
242 if (!psc
->base
.driScreen
)
245 /* Check the renderType value */
246 if (!validate_renderType_against_config(config_base
, renderType
)) {
251 /* If the shareList context is not on this renderer, we cannot possibly
252 * create a context that shares with it.
254 if (shareList
->vtable
->destroy
!= driwindows_destroy_context
) {
258 pcp_shared
= (struct driwindows_context
*) shareList
;
259 shared
= pcp_shared
->windowsContext
;
262 pcp
= calloc(1, sizeof *pcp
);
266 if (!glx_context_init(&pcp
->base
, &psc
->base
, &config
->base
)) {
271 pcp
->base
.renderType
= renderType
;
273 InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base
->visualID
, config_base
->fbconfigID
, config
->pxfi
);
275 pcp
->windowsContext
= windows_create_context_attribs(config
->pxfi
,
277 (const int *)attribs
);
278 if (pcp
->windowsContext
== NULL
) {
283 pcp
->base
.vtable
= &driwindows_context_vtable
;
289 driwindowsDestroyDrawable(__GLXDRIdrawable
* pdraw
)
291 struct driwindows_drawable
*pdp
= (struct driwindows_drawable
*) pdraw
;
293 windows_destroy_drawable(pdp
->windowsDrawable
);
298 static __GLXDRIdrawable
*
299 driwindowsCreateDrawable(struct glx_screen
*base
, XID xDrawable
,
300 GLXDrawable drawable
, struct glx_config
*modes
)
302 struct driwindows_drawable
*pdp
;
303 struct driwindows_screen
*psc
= (struct driwindows_screen
*) base
;
305 pdp
= calloc(1, sizeof(*pdp
));
309 pdp
->base
.xDrawable
= xDrawable
;
310 pdp
->base
.drawable
= drawable
;
311 pdp
->base
.psc
= &psc
->base
;
314 By this stage, the X drawable already exists, but the GLX drawable may
317 Query the server with the XID to find the correct HWND, HPBUFFERARB or
324 if (!XWindowsDRIQueryDrawable(psc
->base
.dpy
, base
->scr
, drawable
, &type
, &handle
))
330 /* No handle found is a failure */
336 /* Create a new drawable */
337 pdp
->windowsDrawable
= windows_create_drawable(type
, handle
);
339 if (!pdp
->windowsDrawable
) {
344 pdp
->base
.destroyDrawable
= driwindowsDestroyDrawable
;
350 driwindowsSwapBuffers(__GLXDRIdrawable
* pdraw
,
351 int64_t target_msc
, int64_t divisor
, int64_t remainder
,
354 struct driwindows_drawable
*pdp
= (struct driwindows_drawable
*) pdraw
;
364 windows_swap_buffers(pdp
->windowsDrawable
);
370 driwindowsCopySubBuffer(__GLXDRIdrawable
* pdraw
,
371 int x
, int y
, int width
, int height
, Bool flush
)
373 struct driwindows_drawable
*pdp
= (struct driwindows_drawable
*) pdraw
;
379 windows_copy_subbuffer(pdp
->windowsDrawable
, x
, y
, width
, height
);
383 driwindowsDestroyScreen(struct glx_screen
*base
)
385 struct driwindows_screen
*psc
= (struct driwindows_screen
*) base
;
387 /* Free the direct rendering per screen data */
388 psc
->driScreen
= NULL
;
392 static const struct glx_screen_vtable driwindows_screen_vtable
= {
393 .create_context
= driwindows_create_context
,
394 .create_context_attribs
= driwindows_create_context_attribs
,
395 .query_renderer_integer
= NULL
,
396 .query_renderer_string
= NULL
,
400 driwindowsBindExtensions(struct driwindows_screen
*psc
)
410 { "WGL_ARB_make_current_read", "GLX_SGI_make_current_read", 0 },
411 { "WGL_EXT_swap_control", "GLX_SGI_swap_control", 0 },
412 { "WGL_EXT_swap_control", "GLX_MESA_swap_control", 0 },
413 // { "WGL_ARB_render_texture", "GLX_EXT_texture_from_pixmap", 0 },
414 // Not exactly equivalent, needs some more glue to be written
415 { "WGL_ARB_pbuffer", "GLX_SGIX_pbuffer", 1 },
416 { "WGL_ARB_multisample", "GLX_ARB_multisample", 1 },
417 { "WGL_ARB_multisample", "GLX_SGIS_multisample", 1 },
418 { "WGL_ARB_create_context", "GLX_ARB_create_context", 0 },
419 { "WGL_ARB_create_context_profile", "GLX_ARB_create_context_profile", 0 },
420 { "WGL_ARB_create_context_robustness", "GLX_ARB_create_context_robustness", 0 },
421 { "WGL_EXT_create_context_es2_profile", "GLX_EXT_create_context_es2_profile", 0 },
424 char *wgl_extensions
;
428 windows_extensions(&gl_extensions
, &wgl_extensions
);
430 for (i
= 0; i
< sizeof(extensionMap
)/sizeof(extensionMap
[0]); i
++) {
431 if (strstr(wgl_extensions
, extensionMap
[i
].wglext
)) {
432 __glXEnableDirectExtension(&psc
->base
, extensionMap
[i
].glxext
);
433 InfoMessageF("enabled %s\n", extensionMap
[i
].glxext
);
435 else if (extensionMap
[i
].mandatory
) {
436 ErrorMessageF("required WGL extension %s is missing\n", extensionMap
[i
].wglext
);
442 Because it pre-dates WGL_EXT_extensions_string, GL_WIN_swap_hint might
443 only be in GL_EXTENSIONS
445 if (strstr(gl_extensions
, "GL_WIN_swap_hint")) {
446 psc
->copySubBuffer
= 1;
447 __glXEnableDirectExtension(&psc
->base
, "GLX_MESA_copy_sub_buffer");
448 InfoMessageF("enabled GLX_MESA_copy_sub_buffer\n");
452 free(wgl_extensions
);
457 static struct glx_config
*
458 driwindowsMapConfigs(struct glx_display
*priv
, int screen
, struct glx_config
*configs
, struct glx_config
*fbconfigs
)
460 struct glx_config head
, *tail
, *m
;
465 for (m
= configs
; m
; m
= m
->next
) {
466 int fbconfigID
= GLX_DONT_CARE
;
469 visuals have fbconfigID of GLX_DONT_CARE, so search for a fbconfig
470 with matching visualID and get the fbconfigID from there
472 struct glx_config
*f
;
473 for (f
= fbconfigs
; f
; f
= f
->next
) {
474 if (f
->visualID
== m
->visualID
)
475 fbconfigID
= f
->fbconfigID
;
479 fbconfigID
= m
->fbconfigID
;
483 XWindowsDRIFBConfigToPixelFormat(priv
->dpy
, screen
, fbconfigID
, &pxfi
);
487 struct driwindows_config
*config
= malloc(sizeof(*config
));
489 tail
->next
= &config
->base
;
490 if (tail
->next
== NULL
)
502 static struct glx_screen
*
503 driwindowsCreateScreen(int screen
, struct glx_display
*priv
)
506 struct driwindows_screen
*psc
;
507 struct glx_config
*configs
= NULL
, *visuals
= NULL
;
510 psc
= calloc(1, sizeof *psc
);
514 if (!glx_screen_init(&psc
->base
, screen
, priv
)) {
519 if (!XWindowsDRIQueryDirectRenderingCapable(psc
->base
.dpy
, screen
, &directCapable
) ||
521 ErrorMessageF("Screen is not Windows-DRI capable\n");
525 /* discover native supported extensions */
526 if (!driwindowsBindExtensions(psc
)) {
530 /* Augment configs with pxfi information */
531 configs
= driwindowsMapConfigs(priv
, screen
, psc
->base
.configs
, NULL
);
532 visuals
= driwindowsMapConfigs(priv
, screen
, psc
->base
.visuals
, configs
);
534 if (!configs
|| !visuals
) {
535 ErrorMessageF("No fbConfigs or visuals found\n");
539 glx_config_destroy_list(psc
->base
.configs
);
540 psc
->base
.configs
= configs
;
541 glx_config_destroy_list(psc
->base
.visuals
);
542 psc
->base
.visuals
= visuals
;
544 psc
->base
.vtable
= &driwindows_screen_vtable
;
546 psc
->base
.driScreen
= psp
;
547 psp
->destroyScreen
= driwindowsDestroyScreen
;
548 psp
->createDrawable
= driwindowsCreateDrawable
;
549 psp
->swapBuffers
= driwindowsSwapBuffers
;
551 if (psc
->copySubBuffer
)
552 psp
->copySubBuffer
= driwindowsCopySubBuffer
;
557 glx_screen_cleanup(&psc
->base
);
562 /* Called from __glXFreeDisplayPrivate.
565 driwindowsDestroyDisplay(__GLXDRIdisplay
* dpy
)
571 * Allocate, initialize and return a __GLXDRIdisplay object.
572 * This is called from __glXInitialize() when we are given a new
575 _X_HIDDEN __GLXDRIdisplay
*
576 driwindowsCreateDisplay(Display
* dpy
)
578 struct driwindows_display
*pdpyp
;
580 int eventBase
, errorBase
;
581 int major
, minor
, patch
;
583 /* Verify server has Windows-DRI extension */
584 if (!XWindowsDRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
585 ErrorMessageF("Windows-DRI extension not available\n");
589 if (!XWindowsDRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
590 ErrorMessageF("Fetching Windows-DRI extension version failed\n");
594 if (!windows_check_renderer()) {
595 ErrorMessageF("Windows-DRI extension disabled for GDI Generic renderer\n");
599 pdpyp
= malloc(sizeof *pdpyp
);
603 pdpyp
->base
.destroyDisplay
= driwindowsDestroyDisplay
;
604 pdpyp
->base
.createScreen
= driwindowsCreateScreen
;
606 pdpyp
->event_base
= eventBase
;