• 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,GLXDrawable draw,GLXDrawable read)82 driwindows_bind_context(struct glx_context *context, 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)103 driwindows_unbind_context(struct glx_context *context)
104 {
105    struct driwindows_context *pcp = (struct driwindows_context *) context;
106 
107    windows_unbind_context(pcp->windowsContext);
108 }
109 
110 static const struct glx_context_vtable driwindows_context_vtable = {
111    .destroy             = driwindows_destroy_context,
112    .bind                = driwindows_bind_context,
113    .unbind              = driwindows_unbind_context,
114    .wait_gl             = NULL,
115    .wait_x              = NULL,
116 };
117 
118 static struct glx_context *
driwindows_create_context(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,int renderType)119 driwindows_create_context(struct glx_screen *base,
120                           struct glx_config *config_base,
121                           struct glx_context *shareList, int renderType)
122 {
123    struct driwindows_context *pcp, *pcp_shared;
124    struct driwindows_config *config = (struct driwindows_config *) config_base;
125    struct driwindows_screen *psc = (struct driwindows_screen *) base;
126    windowsContext *shared = NULL;
127 
128    if (!psc->base.driScreen)
129       return NULL;
130 
131    /* Check the renderType value */
132    if (!validate_renderType_against_config(config_base, renderType))
133        return NULL;
134 
135    if (shareList) {
136       /* If the shareList context is not on this renderer, we cannot possibly
137        * create a context that shares with it.
138        */
139       if (shareList->vtable->destroy != driwindows_destroy_context) {
140          return NULL;
141       }
142 
143       pcp_shared = (struct driwindows_context *) shareList;
144       shared = pcp_shared->windowsContext;
145    }
146 
147    pcp = calloc(1, sizeof *pcp);
148    if (pcp == NULL)
149       return NULL;
150 
151    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
152       free(pcp);
153       return NULL;
154    }
155 
156    pcp->base.renderType = renderType;
157 
158    InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
159 
160    pcp->windowsContext = windows_create_context(config->pxfi, shared);
161 
162    if (!pcp->windowsContext) {
163       free(pcp);
164       return NULL;
165    }
166 
167    pcp->base.vtable = &driwindows_context_vtable;
168 
169    return &pcp->base;
170 }
171 
172 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)173 driwindows_create_context_attribs(struct glx_screen *base,
174                                   struct glx_config *config_base,
175                                   struct glx_context *shareList,
176                                   unsigned num_attribs,
177                                   const uint32_t *attribs,
178                                   unsigned *error)
179 {
180    struct driwindows_context *pcp, *pcp_shared;
181    struct driwindows_config *config = (struct driwindows_config *) config_base;
182    struct driwindows_screen *psc = (struct driwindows_screen *) base;
183    windowsContext *shared = NULL;
184 
185    int i;
186    uint32_t renderType = GLX_RGBA_TYPE;
187 
188    /* Extract renderType from attribs */
189    for (i = 0; i < num_attribs; i++) {
190       switch (attribs[i * 2]) {
191       case GLX_RENDER_TYPE:
192          renderType = attribs[i * 2 + 1];
193          break;
194       }
195    }
196 
197    /*
198      Perhaps we should map GLX tokens to WGL tokens, but they appear to have
199      identical values, so far
200    */
201 
202    if (!psc->base.driScreen || !config_base)
203       return NULL;
204 
205    /* Check the renderType value */
206    if (!validate_renderType_against_config(config_base, renderType)) {
207        return NULL;
208    }
209 
210    if (shareList) {
211       /* If the shareList context is not on this renderer, we cannot possibly
212        * create a context that shares with it.
213        */
214       if (shareList->vtable->destroy != driwindows_destroy_context) {
215          return NULL;
216       }
217 
218       pcp_shared = (struct driwindows_context *) shareList;
219       shared = pcp_shared->windowsContext;
220    }
221 
222    pcp = calloc(1, sizeof *pcp);
223    if (pcp == NULL)
224       return NULL;
225 
226    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
227       free(pcp);
228       return NULL;
229    }
230 
231    pcp->base.renderType = renderType;
232 
233    InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
234 
235    pcp->windowsContext = windows_create_context_attribs(config->pxfi,
236                                                       shared,
237                                                       (const int *)attribs);
238    if (pcp->windowsContext == NULL) {
239       free(pcp);
240       return NULL;
241    }
242 
243    pcp->base.vtable = &driwindows_context_vtable;
244 
245    return &pcp->base;
246 }
247 
248 static void
driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw)249 driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw)
250 {
251    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
252 
253    windows_destroy_drawable(pdp->windowsDrawable);
254 
255    free(pdp);
256 }
257 
258 static __GLXDRIdrawable *
driwindowsCreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * modes)259 driwindowsCreateDrawable(struct glx_screen *base, XID xDrawable,
260                          GLXDrawable drawable, int type,
261                          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