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