• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
driwindows_destroy_context(struct glx_context * context)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
driwindows_bind_context(struct glx_context * context,struct glx_context * old,GLXDrawable draw,GLXDrawable read)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
driwindows_unbind_context(struct glx_context * context,struct glx_context * new)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
driwindows_bind_tex_image(Display * dpy,GLXDrawable drawable,int buffer,const int * attrib_list)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
driwindows_release_tex_image(Display * dpy,GLXDrawable drawable,int buffer)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 *
driwindows_create_context(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,int renderType)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 *
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)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
driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw)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 *
driwindowsCreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,struct glx_config * modes)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
driwindowsSwapBuffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)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
driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)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
driwindowsDestroyScreen(struct glx_screen * base)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
driwindowsBindExtensions(struct driwindows_screen * psc)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 *
driwindowsMapConfigs(struct glx_display * priv,int screen,struct glx_config * configs,struct glx_config * fbconfigs)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 *
driwindowsCreateScreen(int screen,struct glx_display * priv)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
driwindowsDestroyDisplay(__GLXDRIdisplay * dpy)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 *
driwindowsCreateDisplay(Display * dpy)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 }
610