Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/glx/driwindows_glx.c
4558 views
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
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
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
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 *
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 *
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
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 *
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
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
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
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
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 *
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 *
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
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 *
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
572