• 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(&pcp->base);
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,struct glx_config * modes)260 driwindowsCreateDrawable(struct glx_screen *base, XID xDrawable,
261                          GLXDrawable drawable, struct glx_config *modes)
262 {
263    struct driwindows_drawable *pdp;
264    struct driwindows_screen *psc = (struct driwindows_screen *) base;
265 
266    pdp = calloc(1, sizeof(*pdp));
267    if (!pdp)
268       return NULL;
269 
270    pdp->base.xDrawable = xDrawable;
271    pdp->base.drawable = drawable;
272    pdp->base.psc = &psc->base;
273 
274    /*
275       By this stage, the X drawable already exists, but the GLX drawable may
276       not.
277 
278       Query the server with the XID to find the correct HWND, HPBUFFERARB or
279       HBITMAP
280    */
281 
282    unsigned int type;
283    void *handle;
284 
285    if (!XWindowsDRIQueryDrawable(psc->base.dpy, base->scr, drawable, &type, &handle))
286    {
287       free(pdp);
288       return NULL;
289    }
290 
291    /* No handle found is a failure */
292    if (!handle) {
293       free(pdp);
294       return NULL;
295    }
296 
297    /* Create a new drawable */
298    pdp->windowsDrawable = windows_create_drawable(type, handle);
299 
300    if (!pdp->windowsDrawable) {
301       free(pdp);
302       return NULL;
303    }
304 
305    pdp->base.destroyDrawable = driwindowsDestroyDrawable;
306 
307    return &pdp->base;
308 }
309 
310 static int64_t
driwindowsSwapBuffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)311 driwindowsSwapBuffers(__GLXDRIdrawable * pdraw,
312                  int64_t target_msc, int64_t divisor, int64_t remainder,
313                  Bool flush)
314 {
315    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
316 
317    (void) target_msc;
318    (void) divisor;
319    (void) remainder;
320 
321    if (flush) {
322       glFlush();
323    }
324 
325    windows_swap_buffers(pdp->windowsDrawable);
326 
327    return 0;
328 }
329 
330 static void
driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)331 driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw,
332                    int x, int y, int width, int height, Bool flush)
333 {
334    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
335 
336    if (flush) {
337       glFlush();
338    }
339 
340    windows_copy_subbuffer(pdp->windowsDrawable, x, y, width, height);
341 }
342 
343 static void
driwindowsDestroyScreen(struct glx_screen * base)344 driwindowsDestroyScreen(struct glx_screen *base)
345 {
346    struct driwindows_screen *psc = (struct driwindows_screen *) base;
347 
348    /* Free the direct rendering per screen data */
349    psc->driScreen = NULL;
350    free(psc);
351 }
352 
353 static const struct glx_screen_vtable driwindows_screen_vtable = {
354    .create_context         = driwindows_create_context,
355    .create_context_attribs = driwindows_create_context_attribs,
356    .query_renderer_integer = NULL,
357    .query_renderer_string  = NULL,
358 };
359 
360 static Bool
driwindowsBindExtensions(struct driwindows_screen * psc)361 driwindowsBindExtensions(struct driwindows_screen *psc)
362 {
363    Bool result = 1;
364 
365    const struct
366    {
367       char *wglext;
368       char *glxext;
369       Bool mandatory;
370    } extensionMap[] = {
371       { "WGL_ARB_make_current_read", "GLX_SGI_make_current_read", 0 },
372       { "WGL_EXT_swap_control", "GLX_SGI_swap_control", 0 },
373       { "WGL_EXT_swap_control", "GLX_MESA_swap_control", 0 },
374 //      { "WGL_ARB_render_texture", "GLX_EXT_texture_from_pixmap", 0 },
375 // Not exactly equivalent, needs some more glue to be written
376       { "WGL_ARB_pbuffer", "GLX_SGIX_pbuffer", 1 },
377       { "WGL_ARB_multisample", "GLX_ARB_multisample", 1 },
378       { "WGL_ARB_multisample", "GLX_SGIS_multisample", 1 },
379       { "WGL_ARB_create_context", "GLX_ARB_create_context", 0 },
380       { "WGL_ARB_create_context_profile", "GLX_ARB_create_context_profile", 0 },
381       { "WGL_ARB_create_context_robustness", "GLX_ARB_create_context_robustness", 0 },
382       { "WGL_EXT_create_context_es2_profile", "GLX_EXT_create_context_es2_profile", 0 },
383    };
384 
385    char *wgl_extensions;
386    char *gl_extensions;
387    int i;
388 
389    windows_extensions(&gl_extensions, &wgl_extensions);
390 
391    for (i = 0; i < ARRAY_SIZE(extensionMap); i++) {
392       if (strstr(wgl_extensions, extensionMap[i].wglext)) {
393           __glXEnableDirectExtension(&psc->base, extensionMap[i].glxext);
394           InfoMessageF("enabled %s\n", extensionMap[i].glxext);
395       }
396       else if (extensionMap[i].mandatory) {
397          ErrorMessageF("required WGL extension %s is missing\n", extensionMap[i].wglext);
398          result = 0;
399       }
400    }
401 
402    /*
403        Because it pre-dates WGL_EXT_extensions_string, GL_WIN_swap_hint might
404        only be in GL_EXTENSIONS
405    */
406    if (strstr(gl_extensions, "GL_WIN_swap_hint")) {
407       psc->copySubBuffer = 1;
408       __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
409       InfoMessageF("enabled GLX_MESA_copy_sub_buffer\n");
410    }
411 
412    free(gl_extensions);
413    free(wgl_extensions);
414 
415    return result;
416 }
417 
418 static struct glx_config *
driwindowsMapConfigs(struct glx_display * priv,int screen,struct glx_config * configs,struct glx_config * fbconfigs)419 driwindowsMapConfigs(struct glx_display *priv, int screen, struct glx_config *configs, struct glx_config *fbconfigs)
420 {
421    struct glx_config head, *tail, *m;
422 
423    tail = &head;
424    head.next = NULL;
425 
426    for (m = configs; m; m = m->next) {
427       int fbconfigID = GLX_DONT_CARE;
428       if (fbconfigs) {
429          /*
430            visuals have fbconfigID of GLX_DONT_CARE, so search for a fbconfig
431            with matching visualID and get the fbconfigID from there
432          */
433          struct glx_config *f;
434          for (f = fbconfigs; f; f = f->next) {
435             if (f->visualID == m->visualID)
436                fbconfigID = f->fbconfigID;
437          }
438       }
439       else {
440          fbconfigID = m->fbconfigID;
441       }
442 
443       int pxfi;
444       XWindowsDRIFBConfigToPixelFormat(priv->dpy, screen, fbconfigID, &pxfi);
445       if (pxfi == 0)
446          continue;
447 
448       struct driwindows_config *config = malloc(sizeof(*config));
449 
450       tail->next = &config->base;
451       if (tail->next == NULL)
452          continue;
453 
454       config->base = *m;
455       config->pxfi = pxfi;
456 
457       tail = tail->next;
458    }
459 
460    return head.next;
461 }
462 
463 static struct glx_screen *
driwindowsCreateScreen(int screen,struct glx_display * priv)464 driwindowsCreateScreen(int screen, struct glx_display *priv)
465 {
466    __GLXDRIscreen *psp;
467    struct driwindows_screen *psc;
468    struct glx_config *configs = NULL, *visuals = NULL;
469    int directCapable;
470 
471    psc = calloc(1, sizeof *psc);
472    if (psc == NULL)
473       return NULL;
474 
475    if (!glx_screen_init(&psc->base, screen, priv)) {
476       free(psc);
477       return NULL;
478    }
479 
480    if (!XWindowsDRIQueryDirectRenderingCapable(psc->base.dpy, screen, &directCapable) ||
481        !directCapable) {
482       ErrorMessageF("Screen is not Windows-DRI capable\n");
483       goto handle_error;
484    }
485 
486    /* discover native supported extensions */
487    if (!driwindowsBindExtensions(psc)) {
488       goto handle_error;
489    }
490 
491    /* Augment configs with pxfi information */
492    configs = driwindowsMapConfigs(priv, screen, psc->base.configs, NULL);
493    visuals = driwindowsMapConfigs(priv, screen, psc->base.visuals, configs);
494 
495    if (!configs || !visuals) {
496        ErrorMessageF("No fbConfigs or visuals found\n");
497        goto handle_error;
498    }
499 
500    glx_config_destroy_list(psc->base.configs);
501    psc->base.configs = configs;
502    glx_config_destroy_list(psc->base.visuals);
503    psc->base.visuals = visuals;
504 
505    psc->base.vtable = &driwindows_screen_vtable;
506    psp = &psc->vtable;
507    psc->base.driScreen = psp;
508    psp->destroyScreen = driwindowsDestroyScreen;
509    psp->createDrawable = driwindowsCreateDrawable;
510    psp->swapBuffers = driwindowsSwapBuffers;
511 
512    if (psc->copySubBuffer)
513       psp->copySubBuffer = driwindowsCopySubBuffer;
514 
515    return &psc->base;
516 
517 handle_error:
518    glx_screen_cleanup(&psc->base);
519 
520    return NULL;
521 }
522 
523 /* Called from __glXFreeDisplayPrivate.
524  */
525 static void
driwindowsDestroyDisplay(__GLXDRIdisplay * dpy)526 driwindowsDestroyDisplay(__GLXDRIdisplay * dpy)
527 {
528    free(dpy);
529 }
530 
531 /*
532  * Allocate, initialize and return a  __GLXDRIdisplay object.
533  * This is called from __glXInitialize() when we are given a new
534  * display pointer.
535  */
536 _X_HIDDEN __GLXDRIdisplay *
driwindowsCreateDisplay(Display * dpy)537 driwindowsCreateDisplay(Display * dpy)
538 {
539    struct driwindows_display *pdpyp;
540 
541    int eventBase, errorBase;
542    int major, minor, patch;
543 
544    /* Verify server has Windows-DRI extension */
545    if (!XWindowsDRIQueryExtension(dpy, &eventBase, &errorBase)) {
546       ErrorMessageF("Windows-DRI extension not available\n");
547       return NULL;
548    }
549 
550    if (!XWindowsDRIQueryVersion(dpy, &major, &minor, &patch)) {
551       ErrorMessageF("Fetching Windows-DRI extension version failed\n");
552       return NULL;
553    }
554 
555    if (!windows_check_renderer()) {
556       ErrorMessageF("Windows-DRI extension disabled for GDI Generic renderer\n");
557       return NULL;
558    }
559 
560    pdpyp = malloc(sizeof *pdpyp);
561    if (pdpyp == NULL)
562       return NULL;
563 
564    pdpyp->base.destroyDisplay = driwindowsDestroyDisplay;
565    pdpyp->base.createScreen = driwindowsCreateScreen;
566 
567    pdpyp->event_base = eventBase;
568 
569    return &pdpyp->base;
570 }
571