• 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 "util/macros.h"
28 #include "windows/xwindowsdri.h"
29 #include "windows/windowsgl.h"
30 
31 struct driwindows_display
32 {
33    __GLXDRIdisplay base;
34    int event_base;
35 };
36 
37 struct driwindows_context
38 {
39    struct glx_context base;
40    windowsContext *windowsContext;
41 };
42 
43 struct driwindows_config
44 {
45    struct glx_config base;
46    int pxfi;
47 };
48 
49 struct driwindows_screen
50 {
51    struct glx_screen base;
52    __DRIscreen *driScreen;
53    __GLXDRIscreen vtable;
54    Bool copySubBuffer;
55 };
56 
57 struct driwindows_drawable
58 {
59    __GLXDRIdrawable base;
60    windowsDrawable *windowsDrawable;
61 };
62 
63 /**
64  * GLXDRI functions
65  */
66 
67 static void
driwindows_destroy_context(struct glx_context * context)68 driwindows_destroy_context(struct glx_context *context)
69 {
70    struct driwindows_context *pcp = (struct driwindows_context *) context;
71 
72    driReleaseDrawables(&pcp->base);
73 
74    free((char *) context->extensions);
75 
76    windows_destroy_context(pcp->windowsContext);
77 
78    free(pcp);
79 }
80 
81 static int
driwindows_bind_context(struct glx_context * context,struct glx_context * old,GLXDrawable draw,GLXDrawable read)82 driwindows_bind_context(struct glx_context *context, struct glx_context *old,
83                         GLXDrawable draw, GLXDrawable read)
84 {
85    struct driwindows_context *pcp = (struct driwindows_context *) context;
86    struct driwindows_drawable *pdraw, *pread;
87 
88    pdraw = (struct driwindows_drawable *) driFetchDrawable(context, draw);
89    pread = (struct driwindows_drawable *) driFetchDrawable(context, read);
90 
91    driReleaseDrawables(old);
92 
93    if (pdraw == NULL || pread == NULL)
94       return GLXBadDrawable;
95 
96    if (windows_bind_context(pcp->windowsContext,
97                            pdraw->windowsDrawable, pread->windowsDrawable))
98       return Success;
99 
100    return GLXBadContext;
101 }
102 
103 static void
driwindows_unbind_context(struct glx_context * context,struct glx_context * new)104 driwindows_unbind_context(struct glx_context *context, struct glx_context *new)
105 {
106    struct driwindows_context *pcp = (struct driwindows_context *) context;
107 
108    windows_unbind_context(pcp->windowsContext);
109 }
110 
111 static const struct glx_context_vtable driwindows_context_vtable = {
112    .destroy             = driwindows_destroy_context,
113    .bind                = driwindows_bind_context,
114    .unbind              = driwindows_unbind_context,
115    .wait_gl             = NULL,
116    .wait_x              = NULL,
117 };
118 
119 static struct glx_context *
driwindows_create_context(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,int renderType)120 driwindows_create_context(struct glx_screen *base,
121                           struct glx_config *config_base,
122                           struct glx_context *shareList, int renderType)
123 {
124    struct driwindows_context *pcp, *pcp_shared;
125    struct driwindows_config *config = (struct driwindows_config *) config_base;
126    struct driwindows_screen *psc = (struct driwindows_screen *) base;
127    windowsContext *shared = NULL;
128 
129    if (!psc->base.driScreen)
130       return NULL;
131 
132    /* Check the renderType value */
133    if (!validate_renderType_against_config(config_base, renderType))
134        return NULL;
135 
136    if (shareList) {
137       /* If the shareList context is not on this renderer, we cannot possibly
138        * create a context that shares with it.
139        */
140       if (shareList->vtable->destroy != driwindows_destroy_context) {
141          return NULL;
142       }
143 
144       pcp_shared = (struct driwindows_context *) shareList;
145       shared = pcp_shared->windowsContext;
146    }
147 
148    pcp = calloc(1, sizeof *pcp);
149    if (pcp == NULL)
150       return NULL;
151 
152    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
153       free(pcp);
154       return NULL;
155    }
156 
157    pcp->base.renderType = renderType;
158 
159    InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
160 
161    pcp->windowsContext = windows_create_context(config->pxfi, shared);
162 
163    if (!pcp->windowsContext) {
164       free(pcp);
165       return NULL;
166    }
167 
168    pcp->base.vtable = &driwindows_context_vtable;
169 
170    return &pcp->base;
171 }
172 
173 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)174 driwindows_create_context_attribs(struct glx_screen *base,
175                                   struct glx_config *config_base,
176                                   struct glx_context *shareList,
177                                   unsigned num_attribs,
178                                   const uint32_t *attribs,
179                                   unsigned *error)
180 {
181    struct driwindows_context *pcp, *pcp_shared;
182    struct driwindows_config *config = (struct driwindows_config *) config_base;
183    struct driwindows_screen *psc = (struct driwindows_screen *) base;
184    windowsContext *shared = NULL;
185 
186    int i;
187    uint32_t renderType = GLX_RGBA_TYPE;
188 
189    /* Extract renderType from attribs */
190    for (i = 0; i < num_attribs; i++) {
191       switch (attribs[i * 2]) {
192       case GLX_RENDER_TYPE:
193          renderType = attribs[i * 2 + 1];
194          break;
195       }
196    }
197 
198    /*
199      Perhaps we should map GLX tokens to WGL tokens, but they appear to have
200      identical values, so far
201    */
202 
203    if (!psc->base.driScreen || !config_base)
204       return NULL;
205 
206    /* Check the renderType value */
207    if (!validate_renderType_against_config(config_base, renderType)) {
208        return NULL;
209    }
210 
211    if (shareList) {
212       /* If the shareList context is not on this renderer, we cannot possibly
213        * create a context that shares with it.
214        */
215       if (shareList->vtable->destroy != driwindows_destroy_context) {
216          return NULL;
217       }
218 
219       pcp_shared = (struct driwindows_context *) shareList;
220       shared = pcp_shared->windowsContext;
221    }
222 
223    pcp = calloc(1, sizeof *pcp);
224    if (pcp == NULL)
225       return NULL;
226 
227    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
228       free(pcp);
229       return NULL;
230    }
231 
232    pcp->base.renderType = renderType;
233 
234    InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
235 
236    pcp->windowsContext = windows_create_context_attribs(config->pxfi,
237                                                       shared,
238                                                       (const int *)attribs);
239    if (pcp->windowsContext == NULL) {
240       free(pcp);
241       return NULL;
242    }
243 
244    pcp->base.vtable = &driwindows_context_vtable;
245 
246    return &pcp->base;
247 }
248 
249 static void
driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw)250 driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw)
251 {
252    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
253 
254    windows_destroy_drawable(pdp->windowsDrawable);
255 
256    free(pdp);
257 }
258 
259 static __GLXDRIdrawable *
driwindowsCreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * modes)260 driwindowsCreateDrawable(struct glx_screen *base, XID xDrawable,
261                          GLXDrawable drawable, int type,
262                          struct glx_config *modes)
263 {
264    struct driwindows_drawable *pdp;
265    struct driwindows_screen *psc = (struct driwindows_screen *) base;
266 
267    pdp = calloc(1, sizeof(*pdp));
268    if (!pdp)
269       return NULL;
270 
271    pdp->base.xDrawable = xDrawable;
272    pdp->base.drawable = drawable;
273    pdp->base.psc = &psc->base;
274 
275    /*
276       By this stage, the X drawable already exists, but the GLX drawable may
277       not.
278 
279       Query the server with the XID to find the correct HWND, HPBUFFERARB or
280       HBITMAP
281    */
282 
283    unsigned int type;
284    void *handle;
285 
286    if (!XWindowsDRIQueryDrawable(psc->base.dpy, base->scr, drawable, &type, &handle))
287    {
288       free(pdp);
289       return NULL;
290    }
291 
292    /* No handle found is a failure */
293    if (!handle) {
294       free(pdp);
295       return NULL;
296    }
297 
298    /* Create a new drawable */
299    pdp->windowsDrawable = windows_create_drawable(type, handle);
300 
301    if (!pdp->windowsDrawable) {
302       free(pdp);
303       return NULL;
304    }
305 
306    pdp->base.destroyDrawable = driwindowsDestroyDrawable;
307 
308    return &pdp->base;
309 }
310 
311 static int64_t
driwindowsSwapBuffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)312 driwindowsSwapBuffers(__GLXDRIdrawable * pdraw,
313                  int64_t target_msc, int64_t divisor, int64_t remainder,
314                  Bool flush)
315 {
316    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
317 
318    (void) target_msc;
319    (void) divisor;
320    (void) remainder;
321 
322    if (flush) {
323       glFlush();
324    }
325 
326    windows_swap_buffers(pdp->windowsDrawable);
327 
328    return 0;
329 }
330 
331 static void
driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)332 driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw,
333                    int x, int y, int width, int height, Bool flush)
334 {
335    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
336 
337    if (flush) {
338       glFlush();
339    }
340 
341    windows_copy_subbuffer(pdp->windowsDrawable, x, y, width, height);
342 }
343 
344 static void
driwindowsDestroyScreen(struct glx_screen * base)345 driwindowsDestroyScreen(struct glx_screen *base)
346 {
347    struct driwindows_screen *psc = (struct driwindows_screen *) base;
348 
349    /* Free the direct rendering per screen data */
350    psc->driScreen = NULL;
351    free(psc);
352 }
353 
354 static const struct glx_screen_vtable driwindows_screen_vtable = {
355    .create_context         = driwindows_create_context,
356    .create_context_attribs = driwindows_create_context_attribs,
357    .query_renderer_integer = NULL,
358    .query_renderer_string  = NULL,
359 };
360 
361 static Bool
driwindowsBindExtensions(struct driwindows_screen * psc)362 driwindowsBindExtensions(struct driwindows_screen *psc)
363 {
364    Bool result = 1;
365 
366    const struct
367    {
368       char *wglext;
369       char *glxext;
370       Bool mandatory;
371    } extensionMap[] = {
372       { "WGL_ARB_make_current_read", "GLX_SGI_make_current_read", 0 },
373       { "WGL_EXT_swap_control", "GLX_SGI_swap_control", 0 },
374       { "WGL_EXT_swap_control", "GLX_MESA_swap_control", 0 },
375 //      { "WGL_ARB_render_texture", "GLX_EXT_texture_from_pixmap", 0 },
376 // Not exactly equivalent, needs some more glue to be written
377       { "WGL_ARB_pbuffer", "GLX_SGIX_pbuffer", 1 },
378       { "WGL_ARB_multisample", "GLX_ARB_multisample", 1 },
379       { "WGL_ARB_multisample", "GLX_SGIS_multisample", 1 },
380       { "WGL_ARB_create_context", "GLX_ARB_create_context", 0 },
381       { "WGL_ARB_create_context_profile", "GLX_ARB_create_context_profile", 0 },
382       { "WGL_ARB_create_context_robustness", "GLX_ARB_create_context_robustness", 0 },
383       { "WGL_EXT_create_context_es2_profile", "GLX_EXT_create_context_es2_profile", 0 },
384    };
385 
386    char *wgl_extensions;
387    char *gl_extensions;
388    int i;
389 
390    windows_extensions(&gl_extensions, &wgl_extensions);
391 
392    for (i = 0; i < ARRAY_SIZE(extensionMap); i++) {
393       if (strstr(wgl_extensions, extensionMap[i].wglext)) {
394           __glXEnableDirectExtension(&psc->base, extensionMap[i].glxext);
395           InfoMessageF("enabled %s\n", extensionMap[i].glxext);
396       }
397       else if (extensionMap[i].mandatory) {
398          ErrorMessageF("required WGL extension %s is missing\n", extensionMap[i].wglext);
399          result = 0;
400       }
401    }
402 
403    /*
404        Because it pre-dates WGL_EXT_extensions_string, GL_WIN_swap_hint might
405        only be in GL_EXTENSIONS
406    */
407    if (strstr(gl_extensions, "GL_WIN_swap_hint")) {
408       psc->copySubBuffer = 1;
409       __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
410       InfoMessageF("enabled GLX_MESA_copy_sub_buffer\n");
411    }
412 
413    free(gl_extensions);
414    free(wgl_extensions);
415 
416    return result;
417 }
418 
419 static struct glx_config *
driwindowsMapConfigs(struct glx_display * priv,int screen,struct glx_config * configs,struct glx_config * fbconfigs)420 driwindowsMapConfigs(struct glx_display *priv, int screen, struct glx_config *configs, struct glx_config *fbconfigs)
421 {
422    struct glx_config head, *tail, *m;
423 
424    tail = &head;
425    head.next = NULL;
426 
427    for (m = configs; m; m = m->next) {
428       int fbconfigID = GLX_DONT_CARE;
429       if (fbconfigs) {
430          /*
431            visuals have fbconfigID of GLX_DONT_CARE, so search for a fbconfig
432            with matching visualID and get the fbconfigID from there
433          */
434          struct glx_config *f;
435          for (f = fbconfigs; f; f = f->next) {
436             if (f->visualID == m->visualID)
437                fbconfigID = f->fbconfigID;
438          }
439       }
440       else {
441          fbconfigID = m->fbconfigID;
442       }
443 
444       int pxfi;
445       XWindowsDRIFBConfigToPixelFormat(priv->dpy, screen, fbconfigID, &pxfi);
446       if (pxfi == 0)
447          continue;
448 
449       struct driwindows_config *config = malloc(sizeof(*config));
450 
451       tail->next = &config->base;
452       if (tail->next == NULL)
453          continue;
454 
455       config->base = *m;
456       config->pxfi = pxfi;
457 
458       tail = tail->next;
459    }
460 
461    return head.next;
462 }
463 
464 static struct glx_screen *
driwindowsCreateScreen(int screen,struct glx_display * priv)465 driwindowsCreateScreen(int screen, struct glx_display *priv)
466 {
467    __GLXDRIscreen *psp;
468    struct driwindows_screen *psc;
469    struct glx_config *configs = NULL, *visuals = NULL;
470    int directCapable;
471 
472    psc = calloc(1, sizeof *psc);
473    if (psc == NULL)
474       return NULL;
475 
476    if (!glx_screen_init(&psc->base, screen, priv)) {
477       free(psc);
478       return NULL;
479    }
480 
481    if (!XWindowsDRIQueryDirectRenderingCapable(psc->base.dpy, screen, &directCapable) ||
482        !directCapable) {
483       ErrorMessageF("Screen is not Windows-DRI capable\n");
484       goto handle_error;
485    }
486 
487    /* discover native supported extensions */
488    if (!driwindowsBindExtensions(psc)) {
489       goto handle_error;
490    }
491 
492    /* Augment configs with pxfi information */
493    configs = driwindowsMapConfigs(priv, screen, psc->base.configs, NULL);
494    visuals = driwindowsMapConfigs(priv, screen, psc->base.visuals, configs);
495 
496    if (!configs || !visuals) {
497        ErrorMessageF("No fbConfigs or visuals found\n");
498        goto handle_error;
499    }
500 
501    glx_config_destroy_list(psc->base.configs);
502    psc->base.configs = configs;
503    glx_config_destroy_list(psc->base.visuals);
504    psc->base.visuals = visuals;
505 
506    psc->base.vtable = &driwindows_screen_vtable;
507    psp = &psc->vtable;
508    psc->base.driScreen = psp;
509    psp->destroyScreen = driwindowsDestroyScreen;
510    psp->createDrawable = driwindowsCreateDrawable;
511    psp->swapBuffers = driwindowsSwapBuffers;
512 
513    if (psc->copySubBuffer)
514       psp->copySubBuffer = driwindowsCopySubBuffer;
515 
516    return &psc->base;
517 
518 handle_error:
519    glx_screen_cleanup(&psc->base);
520 
521    return NULL;
522 }
523 
524 /* Called from __glXFreeDisplayPrivate.
525  */
526 static void
driwindowsDestroyDisplay(__GLXDRIdisplay * dpy)527 driwindowsDestroyDisplay(__GLXDRIdisplay * dpy)
528 {
529    free(dpy);
530 }
531 
532 /*
533  * Allocate, initialize and return a  __GLXDRIdisplay object.
534  * This is called from __glXInitialize() when we are given a new
535  * display pointer.
536  */
537 _X_HIDDEN __GLXDRIdisplay *
driwindowsCreateDisplay(Display * dpy)538 driwindowsCreateDisplay(Display * dpy)
539 {
540    struct driwindows_display *pdpyp;
541 
542    int eventBase, errorBase;
543    int major, minor, patch;
544 
545    /* Verify server has Windows-DRI extension */
546    if (!XWindowsDRIQueryExtension(dpy, &eventBase, &errorBase)) {
547       ErrorMessageF("Windows-DRI extension not available\n");
548       return NULL;
549    }
550 
551    if (!XWindowsDRIQueryVersion(dpy, &major, &minor, &patch)) {
552       ErrorMessageF("Fetching Windows-DRI extension version failed\n");
553       return NULL;
554    }
555 
556    if (!windows_check_renderer()) {
557       ErrorMessageF("Windows-DRI extension disabled for GDI Generic renderer\n");
558       return NULL;
559    }
560 
561    pdpyp = malloc(sizeof *pdpyp);
562    if (pdpyp == NULL)
563       return NULL;
564 
565    pdpyp->base.destroyDisplay = driwindowsDestroyDisplay;
566    pdpyp->base.createScreen = driwindowsCreateScreen;
567 
568    pdpyp->event_base = eventBase;
569 
570    return &pdpyp->base;
571 }
572