xref: /third_party/mesa3d/src/glx/driwindows_glx.c (revision bf215546)
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
31struct driwindows_display
32{
33   __GLXDRIdisplay base;
34   int event_base;
35};
36
37struct driwindows_context
38{
39   struct glx_context base;
40   windowsContext *windowsContext;
41};
42
43struct driwindows_config
44{
45   struct glx_config base;
46   int pxfi;
47};
48
49struct driwindows_screen
50{
51   struct glx_screen base;
52   __DRIscreen *driScreen;
53   __GLXDRIscreen vtable;
54   Bool copySubBuffer;
55};
56
57struct driwindows_drawable
58{
59   __GLXDRIdrawable base;
60   windowsDrawable *windowsDrawable;
61};
62
63/**
64 * GLXDRI functions
65 */
66
67static void
68driwindows_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
81static int
82driwindows_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
103static void
104driwindows_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
111static 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
119static struct glx_context *
120driwindows_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
173static struct glx_context *
174driwindows_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
249static void
250driwindowsDestroyDrawable(__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
259static __GLXDRIdrawable *
260driwindowsCreateDrawable(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
311static int64_t
312driwindowsSwapBuffers(__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
331static void
332driwindowsCopySubBuffer(__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
344static void
345driwindowsDestroyScreen(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
354static 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
361static Bool
362driwindowsBindExtensions(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
419static struct glx_config *
420driwindowsMapConfigs(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
464static struct glx_screen *
465driwindowsCreateScreen(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
518handle_error:
519   glx_screen_cleanup(&psc->base);
520
521   return NULL;
522}
523
524/* Called from __glXFreeDisplayPrivate.
525 */
526static void
527driwindowsDestroyDisplay(__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 *
538driwindowsCreateDisplay(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