direct-to-native-GL for GLX clients on Cygwin ("Windows-DRI")
[mesa.git] / src / glx / driwindows_glx.c
1 /*
2 * Copyright © 2014 Jon Turney
3 *
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:
10 *
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
13 * Software.
14 *
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
21 * IN THE SOFTWARE.
22 */
23
24 #include "glxclient.h"
25 #include "glx_error.h"
26 #include "dri_common.h"
27 #include "windows/xwindowsdri.h"
28 #include "windows/windowsgl.h"
29
30 struct driwindows_display
31 {
32 __GLXDRIdisplay base;
33 int event_base;
34 };
35
36 struct driwindows_context
37 {
38 struct glx_context base;
39 windowsContext *windowsContext;
40 };
41
42 struct driwindows_config
43 {
44 struct glx_config base;
45 int pxfi;
46 };
47
48 struct driwindows_screen
49 {
50 struct glx_screen base;
51 __DRIscreen *driScreen;
52 __GLXDRIscreen vtable;
53 Bool copySubBuffer;
54 };
55
56 struct driwindows_drawable
57 {
58 __GLXDRIdrawable base;
59 windowsDrawable *windowsDrawable;
60 };
61
62 /**
63 * GLXDRI functions
64 */
65
66 static void
67 driwindows_destroy_context(struct glx_context *context)
68 {
69 struct driwindows_context *pcp = (struct driwindows_context *) context;
70
71 driReleaseDrawables(&pcp->base);
72
73 free((char *) context->extensions);
74
75 windows_destroy_context(pcp->windowsContext);
76
77 free(pcp);
78 }
79
80 static int
81 driwindows_bind_context(struct glx_context *context, struct glx_context *old,
82 GLXDrawable draw, GLXDrawable read)
83 {
84 struct driwindows_context *pcp = (struct driwindows_context *) context;
85 struct driwindows_drawable *pdraw, *pread;
86
87 pdraw = (struct driwindows_drawable *) driFetchDrawable(context, draw);
88 pread = (struct driwindows_drawable *) driFetchDrawable(context, read);
89
90 driReleaseDrawables(&pcp->base);
91
92 if (pdraw == NULL || pread == NULL)
93 return GLXBadDrawable;
94
95 if (windows_bind_context(pcp->windowsContext,
96 pdraw->windowsDrawable, pread->windowsDrawable))
97 return Success;
98
99 return GLXBadContext;
100 }
101
102 static void
103 driwindows_unbind_context(struct glx_context *context, struct glx_context *new)
104 {
105 struct driwindows_context *pcp = (struct driwindows_context *) context;
106
107 windows_unbind_context(pcp->windowsContext);
108 }
109
110 static void
111 driwindows_bind_tex_image(Display * dpy,
112 GLXDrawable drawable,
113 int buffer, const int *attrib_list)
114 {
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;
119
120 __glXInitialize(dpy);
121
122 if (pdraw != NULL) {
123 windows_setTexBuffer(pcp->windowsContext,
124 pdraw->base.textureTarget,
125 pdraw->base.textureFormat,
126 pdraw->windowsDrawable);
127 }
128 }
129
130 static void
131 driwindows_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
132 {
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;
138
139 if (dpyPriv != NULL && pdraw != NULL) {
140 windows_releaseTexBuffer(pcp->windowsContext,
141 pdraw->base.textureTarget,
142 pdraw->windowsDrawable);
143 }
144 }
145
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,
150 .wait_gl = NULL,
151 .wait_x = NULL,
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,
156 };
157
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)
162 {
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;
167
168 if (!psc->base.driScreen)
169 return NULL;
170
171 /* Check the renderType value */
172 if (!validate_renderType_against_config(config_base, renderType))
173 return NULL;
174
175 if (shareList) {
176 /* If the shareList context is not on this renderer, we cannot possibly
177 * create a context that shares with it.
178 */
179 if (shareList->vtable->destroy != driwindows_destroy_context) {
180 return NULL;
181 }
182
183 pcp_shared = (struct driwindows_context *) shareList;
184 shared = pcp_shared->windowsContext;
185 }
186
187 pcp = calloc(1, sizeof *pcp);
188 if (pcp == NULL)
189 return NULL;
190
191 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
192 free(pcp);
193 return NULL;
194 }
195
196 pcp->base.renderType = renderType;
197
198 InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
199
200 pcp->windowsContext = windows_create_context(config->pxfi, shared);
201
202 if (!pcp->windowsContext) {
203 free(pcp);
204 return NULL;
205 }
206
207 pcp->base.vtable = &driwindows_context_vtable;
208
209 return &pcp->base;
210 }
211
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,
218 unsigned *error)
219 {
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;
224
225 int i;
226 uint32_t renderType = GLX_RGBA_TYPE;
227
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];
233 break;
234 }
235 }
236
237 /*
238 Perhaps we should map GLX tokens to WGL tokens, but they appear to have
239 identical values, so far
240 */
241
242 if (!psc->base.driScreen)
243 return NULL;
244
245 /* Check the renderType value */
246 if (!validate_renderType_against_config(config_base, renderType)) {
247 return NULL;
248 }
249
250 if (shareList) {
251 /* If the shareList context is not on this renderer, we cannot possibly
252 * create a context that shares with it.
253 */
254 if (shareList->vtable->destroy != driwindows_destroy_context) {
255 return NULL;
256 }
257
258 pcp_shared = (struct driwindows_context *) shareList;
259 shared = pcp_shared->windowsContext;
260 }
261
262 pcp = calloc(1, sizeof *pcp);
263 if (pcp == NULL)
264 return NULL;
265
266 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
267 free(pcp);
268 return NULL;
269 }
270
271 pcp->base.renderType = renderType;
272
273 InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
274
275 pcp->windowsContext = windows_create_context_attribs(config->pxfi,
276 shared,
277 (const int *)attribs);
278 if (pcp->windowsContext == NULL) {
279 free(pcp);
280 return NULL;
281 }
282
283 pcp->base.vtable = &driwindows_context_vtable;
284
285 return &pcp->base;
286 }
287
288 static void
289 driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw)
290 {
291 struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
292
293 windows_destroy_drawable(pdp->windowsDrawable);
294
295 free(pdp);
296 }
297
298 static __GLXDRIdrawable *
299 driwindowsCreateDrawable(struct glx_screen *base, XID xDrawable,
300 GLXDrawable drawable, struct glx_config *modes)
301 {
302 struct driwindows_drawable *pdp;
303 struct driwindows_screen *psc = (struct driwindows_screen *) base;
304
305 pdp = calloc(1, sizeof(*pdp));
306 if (!pdp)
307 return NULL;
308
309 pdp->base.xDrawable = xDrawable;
310 pdp->base.drawable = drawable;
311 pdp->base.psc = &psc->base;
312
313 /*
314 By this stage, the X drawable already exists, but the GLX drawable may
315 not.
316
317 Query the server with the XID to find the correct HWND, HPBUFFERARB or
318 HBITMAP
319 */
320
321 unsigned int type;
322 void *handle;
323
324 if (!XWindowsDRIQueryDrawable(psc->base.dpy, base->scr, drawable, &type, &handle))
325 {
326 free(pdp);
327 return NULL;
328 }
329
330 /* No handle found is a failure */
331 if (!handle) {
332 free(pdp);
333 return NULL;
334 }
335
336 /* Create a new drawable */
337 pdp->windowsDrawable = windows_create_drawable(type, handle);
338
339 if (!pdp->windowsDrawable) {
340 free(pdp);
341 return NULL;
342 }
343
344 pdp->base.destroyDrawable = driwindowsDestroyDrawable;
345
346 return &pdp->base;
347 }
348
349 static int64_t
350 driwindowsSwapBuffers(__GLXDRIdrawable * pdraw,
351 int64_t target_msc, int64_t divisor, int64_t remainder,
352 Bool flush)
353 {
354 struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
355
356 (void) target_msc;
357 (void) divisor;
358 (void) remainder;
359
360 if (flush) {
361 glFlush();
362 }
363
364 windows_swap_buffers(pdp->windowsDrawable);
365
366 return 0;
367 }
368
369 static void
370 driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw,
371 int x, int y, int width, int height, Bool flush)
372 {
373 struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
374
375 if (flush) {
376 glFlush();
377 }
378
379 windows_copy_subbuffer(pdp->windowsDrawable, x, y, width, height);
380 }
381
382 static void
383 driwindowsDestroyScreen(struct glx_screen *base)
384 {
385 struct driwindows_screen *psc = (struct driwindows_screen *) base;
386
387 /* Free the direct rendering per screen data */
388 psc->driScreen = NULL;
389 free(psc);
390 }
391
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,
397 };
398
399 static Bool
400 driwindowsBindExtensions(struct driwindows_screen *psc)
401 {
402 Bool result = 1;
403
404 const struct
405 {
406 char *wglext;
407 char *glxext;
408 Bool mandatory;
409 } extensionMap[] = {
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 },
422 };
423
424 char *wgl_extensions;
425 char *gl_extensions;
426 int i;
427
428 windows_extensions(&gl_extensions, &wgl_extensions);
429
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);
434 }
435 else if (extensionMap[i].mandatory) {
436 ErrorMessageF("required WGL extension %s is missing\n", extensionMap[i].wglext);
437 result = 0;
438 }
439 }
440
441 /*
442 Because it pre-dates WGL_EXT_extensions_string, GL_WIN_swap_hint might
443 only be in GL_EXTENSIONS
444 */
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");
449 }
450
451 free(gl_extensions);
452 free(wgl_extensions);
453
454 return result;
455 }
456
457 static struct glx_config *
458 driwindowsMapConfigs(struct glx_display *priv, int screen, struct glx_config *configs, struct glx_config *fbconfigs)
459 {
460 struct glx_config head, *tail, *m;
461
462 tail = &head;
463 head.next = NULL;
464
465 for (m = configs; m; m = m->next) {
466 int fbconfigID = GLX_DONT_CARE;
467 if (fbconfigs) {
468 /*
469 visuals have fbconfigID of GLX_DONT_CARE, so search for a fbconfig
470 with matching visualID and get the fbconfigID from there
471 */
472 struct glx_config *f;
473 for (f = fbconfigs; f; f = f->next) {
474 if (f->visualID == m->visualID)
475 fbconfigID = f->fbconfigID;
476 }
477 }
478 else {
479 fbconfigID = m->fbconfigID;
480 }
481
482 int pxfi;
483 XWindowsDRIFBConfigToPixelFormat(priv->dpy, screen, fbconfigID, &pxfi);
484 if (pxfi == 0)
485 continue;
486
487 struct driwindows_config *config = malloc(sizeof(*config));
488
489 tail->next = &config->base;
490 if (tail->next == NULL)
491 continue;
492
493 config->base = *m;
494 config->pxfi = pxfi;
495
496 tail = tail->next;
497 }
498
499 return head.next;
500 }
501
502 static struct glx_screen *
503 driwindowsCreateScreen(int screen, struct glx_display *priv)
504 {
505 __GLXDRIscreen *psp;
506 struct driwindows_screen *psc;
507 struct glx_config *configs = NULL, *visuals = NULL;
508 int directCapable;
509
510 psc = calloc(1, sizeof *psc);
511 if (psc == NULL)
512 return NULL;
513
514 if (!glx_screen_init(&psc->base, screen, priv)) {
515 free(psc);
516 return NULL;
517 }
518
519 if (!XWindowsDRIQueryDirectRenderingCapable(psc->base.dpy, screen, &directCapable) ||
520 !directCapable) {
521 ErrorMessageF("Screen is not Windows-DRI capable\n");
522 goto handle_error;
523 }
524
525 /* discover native supported extensions */
526 if (!driwindowsBindExtensions(psc)) {
527 goto handle_error;
528 }
529
530 /* Augment configs with pxfi information */
531 configs = driwindowsMapConfigs(priv, screen, psc->base.configs, NULL);
532 visuals = driwindowsMapConfigs(priv, screen, psc->base.visuals, configs);
533
534 if (!configs || !visuals) {
535 ErrorMessageF("No fbConfigs or visuals found\n");
536 goto handle_error;
537 }
538
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;
543
544 psc->base.vtable = &driwindows_screen_vtable;
545 psp = &psc->vtable;
546 psc->base.driScreen = psp;
547 psp->destroyScreen = driwindowsDestroyScreen;
548 psp->createDrawable = driwindowsCreateDrawable;
549 psp->swapBuffers = driwindowsSwapBuffers;
550
551 if (psc->copySubBuffer)
552 psp->copySubBuffer = driwindowsCopySubBuffer;
553
554 return &psc->base;
555
556 handle_error:
557 glx_screen_cleanup(&psc->base);
558
559 return NULL;
560 }
561
562 /* Called from __glXFreeDisplayPrivate.
563 */
564 static void
565 driwindowsDestroyDisplay(__GLXDRIdisplay * dpy)
566 {
567 free(dpy);
568 }
569
570 /*
571 * Allocate, initialize and return a __GLXDRIdisplay object.
572 * This is called from __glXInitialize() when we are given a new
573 * display pointer.
574 */
575 _X_HIDDEN __GLXDRIdisplay *
576 driwindowsCreateDisplay(Display * dpy)
577 {
578 struct driwindows_display *pdpyp;
579
580 int eventBase, errorBase;
581 int major, minor, patch;
582
583 /* Verify server has Windows-DRI extension */
584 if (!XWindowsDRIQueryExtension(dpy, &eventBase, &errorBase)) {
585 ErrorMessageF("Windows-DRI extension not available\n");
586 return NULL;
587 }
588
589 if (!XWindowsDRIQueryVersion(dpy, &major, &minor, &patch)) {
590 ErrorMessageF("Fetching Windows-DRI extension version failed\n");
591 return NULL;
592 }
593
594 if (!windows_check_renderer()) {
595 ErrorMessageF("Windows-DRI extension disabled for GDI Generic renderer\n");
596 return NULL;
597 }
598
599 pdpyp = malloc(sizeof *pdpyp);
600 if (pdpyp == NULL)
601 return NULL;
602
603 pdpyp->base.destroyDisplay = driwindowsDestroyDisplay;
604 pdpyp->base.createScreen = driwindowsCreateScreen;
605
606 pdpyp->event_base = eventBase;
607
608 return &pdpyp->base;
609 }