1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
#include "../../../include/mgl/graphics/backend/glx.h"
#include "../../../include/mgl/mgl.h"
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xrender.h>
static void mgl_graphics_glx_deinit(mgl_graphics *self);
typedef struct {
GLXContext glx_context;
GLXFBConfig *fbconfigs;
GLXFBConfig fbconfig;
XVisualInfo *visual_info;
} mgl_graphics_glx;
static bool xvisual_match_alpha(Display *dpy, XVisualInfo *visual_info, bool alpha) {
XRenderPictFormat *pict_format = XRenderFindVisualFormat(dpy, visual_info->visual);
if(!pict_format)
return false;
return (alpha && pict_format->direct.alphaMask > 0) || (!alpha && pict_format->direct.alphaMask == 0);
}
static bool mgl_graphics_glx_choose_config(mgl_graphics_glx *self, mgl_context *context, bool alpha) {
const int attr[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, alpha ? 8 : 0,
// TODO:
//GLX_DEPTH_SIZE, 0,
None
};
self->fbconfigs = NULL;
self->visual_info = NULL;
self->fbconfig = NULL;
int numfbconfigs = 0;
self->fbconfigs = context->gl.glXChooseFBConfig(context->connection, DefaultScreen(context->connection), attr, &numfbconfigs);
for(int i = 0; i < numfbconfigs; i++) {
self->visual_info = (XVisualInfo*)context->gl.glXGetVisualFromFBConfig(context->connection, self->fbconfigs[i]);
if(!self->visual_info)
continue;
if(xvisual_match_alpha(context->connection, self->visual_info, alpha)) {
self->fbconfig = self->fbconfigs[i];
break;
} else {
XFree(self->visual_info);
self->visual_info = NULL;
self->fbconfig = NULL;
}
}
if(!self->fbconfig) {
fprintf(stderr, "mgl error: mgl_graphics_glx_choose_config: no appropriate glx config found\n");
return false;
}
if(!self->visual_info) {
fprintf(stderr, "mgl error: mgl_graphics_glx_choose_config: no appropriate visual found\n");
return false;
}
return true;
}
static bool mgl_graphics_glx_make_context_current(mgl_graphics *self, mgl_window_handle window) {
mgl_graphics_glx *impl = self->impl;
mgl_context *context = mgl_get_context();
return context->gl.glXMakeContextCurrent(context->connection, (GLXDrawable)window, (GLXDrawable)window, impl->glx_context) != 0;
}
static void mgl_graphics_glx_swap_buffers(mgl_graphics *self, mgl_window_handle window) {
(void)self;
mgl_context *context = mgl_get_context();
context->gl.glXSwapBuffers(context->connection, (GLXDrawable)window);
}
/* TODO: Use gl OML present for other platforms than nvidia? nvidia doesn't support present yet */
/* TODO: check for glx swap control extension string (GLX_EXT_swap_control, etc) */
static bool mgl_graphics_glx_set_swap_interval(mgl_graphics *self, mgl_window_handle window, bool enabled) {
(void)self;
mgl_context *context = mgl_get_context();
int result = 0;
if(context->gl.glXSwapIntervalEXT) {
context->gl.glXSwapIntervalEXT(context->connection, (GLXDrawable)window, enabled);
} else if(context->gl.glXSwapIntervalMESA) {
result = context->gl.glXSwapIntervalMESA(enabled);
} else if(context->gl.glXSwapIntervalSGI) {
result = context->gl.glXSwapIntervalSGI(enabled);
} else {
static int warned = 0;
if (!warned) {
warned = 1;
fprintf(stderr, "mgl warning: setting vertical sync not supported\n");
}
}
if(result != 0)
fprintf(stderr, "mgl warning: setting vertical sync failed\n");
return result == 0;
}
static void* mgl_graphics_glx_get_xvisual_info(mgl_graphics *self) {
mgl_graphics_glx *impl = self->impl;
return impl->visual_info;
}
bool mgl_graphics_glx_init(mgl_graphics *self) {
mgl_graphics_glx *impl = calloc(1, sizeof(mgl_graphics_glx));
if(!impl)
return false;
self->deinit = mgl_graphics_glx_deinit;
self->make_context_current = mgl_graphics_glx_make_context_current;
self->swap_buffers = mgl_graphics_glx_swap_buffers;
self->set_swap_interval = mgl_graphics_glx_set_swap_interval;
self->get_xvisual_info = mgl_graphics_glx_get_xvisual_info;
self->impl = impl;
mgl_context *context = mgl_get_context();
if(!mgl_graphics_glx_choose_config(impl, context, self->alpha)) {
mgl_graphics_glx_deinit(self);
return false;
}
impl->glx_context = context->gl.glXCreateNewContext(context->connection, impl->fbconfig, GLX_RGBA_TYPE, 0, True);
if(!impl->glx_context) {
fprintf(stderr, "mgl error: mgl_graphics_glx_init: glXCreateContext failed\n");
mgl_graphics_glx_deinit(self);
return false;
}
return true;
}
void mgl_graphics_glx_deinit(mgl_graphics *self) {
mgl_graphics_glx *impl = self->impl;
if(!impl)
return;
mgl_context *context = mgl_get_context();
if(impl->glx_context) {
context->gl.glXMakeContextCurrent(context->connection, None, None, NULL);
context->gl.glXDestroyContext(context->connection, impl->glx_context);
impl->glx_context = NULL;
}
if(impl->visual_info) {
XFree(impl->visual_info);
impl->visual_info = NULL;
}
if(impl->fbconfigs) {
XFree(impl->fbconfigs);
impl->fbconfigs = NULL;
}
impl->fbconfig = NULL;
free(self->impl);
self->impl = NULL;
}
|