this repo has no description
1#include <stdlib.h>
2#include <stdio.h> // for fprintf(stderr, "unimplemented")
3
4#include <pthread.h>
5
6#include <OpenGL/OpenGL.h>
7#include <OpenGL/CGLInternal.h>
8#include <CoreFoundation/CFDictionary.h>
9#include <pthread.h>
10
11// Try to get the right (generic) type definitions.
12// In particular, we really want EGLNativeDisplayType to be void *,
13// not int as it is if __APPLE__ is defined.
14#undef APPLE
15#undef __APPLE__
16
17#define __unix__
18#define EGL_NO_X11
19
20#include <EGL/egl.h>
21
22#define APPLE
23#define __APPLE__
24
25static EGLDisplay display;
26
27static EGLConfig config;
28static int num_config;
29
30static EGLint const attribute_list[] = {
31 EGL_RED_SIZE, 1,
32 EGL_GREEN_SIZE, 1,
33 EGL_BLUE_SIZE, 1,
34 EGL_NONE
35};
36
37struct _CGLDisplay
38{
39 EGLDisplay display;
40 EGLConfig config;
41 int num_config;
42};
43
44static CFMutableDictionaryRef g_displays;
45static pthread_mutex_t g_displaysMutex = PTHREAD_MUTEX_INITIALIZER;
46
47struct _CGLContextObj {
48 GLuint retain_count;
49 pthread_mutex_t lock;
50 EGLContext egl_context;
51 EGLSurface egl_surface;
52 // EGL has no function for getting the current swap interval,
53 // so we need to save the last set value. The default is 1.
54 int swap_interval;
55};
56
57struct _CGLPixelFormatObj {
58 GLuint retain_count;
59 CGLPixelFormatAttribute *attributes;
60};
61
62static inline int attribute_has_argument(CGLPixelFormatAttribute attr) {
63 switch (attr) {
64 case kCGLPFAAuxBuffers:
65 case kCGLPFAColorSize:
66 case kCGLPFAAlphaSize:
67 case kCGLPFADepthSize:
68 case kCGLPFAStencilSize:
69 case kCGLPFAAccumSize:
70 case kCGLPFARendererID:
71 case kCGLPFADisplayMask:
72 return 1;
73 default:
74 return 0;
75 }
76}
77
78__attribute__((constructor))
79static void _CGLInitialize(void)
80{
81 g_displays = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
82}
83
84static int attributes_count(const CGLPixelFormatAttribute *attrs) {
85 int result;
86 for (result = 0; attrs[result] != 0; result++) {
87 if (attribute_has_argument(attrs[result])) {
88 result++;
89 }
90 }
91 return result;
92}
93
94CGLError CGLRegisterNativeDisplay(void *native_display) {
95
96 display = eglGetDisplay(native_display);
97
98 if (display == EGL_NO_DISPLAY) {
99 return kCGLBadConnection;
100 }
101
102 eglInitialize(display, NULL, NULL);
103 eglChooseConfig(display, attribute_list, &config, 1, &num_config);
104
105 eglBindAPI(EGL_OPENGL_API);
106
107 return kCGLNoError;
108}
109
110static struct _CGLDisplay* getCGLDisplay(CGSConnectionID cid)
111{
112 struct _CGLDisplay* rv;
113
114 pthread_mutex_lock(&g_displaysMutex);
115 rv = (struct _CGLDisplay*) CFDictionaryGetValue(g_displays, (const void*)(unsigned long) cid);
116 pthread_mutex_unlock(&g_displaysMutex);
117
118 if (!rv)
119 {
120 EGLDisplay disp = eglGetDisplay(_CGSNativeDisplay(cid));
121 if (disp == EGL_NO_DISPLAY)
122 return NULL;
123
124 rv = (struct _CGLDisplay*) malloc(sizeof(*rv));
125 rv->display = disp;
126
127 eglInitialize(rv->display, NULL, NULL);
128 eglChooseConfig(rv->display, attribute_list, &rv->config, 1, &rv->num_config);
129
130 eglBindAPI(EGL_OPENGL_API);
131
132 pthread_mutex_lock(&g_displaysMutex);
133 CFDictionaryAddValue(g_displays, (const void*)(unsigned long) cid, rv);
134 pthread_mutex_unlock(&g_displaysMutex);
135 }
136
137 return rv;
138}
139
140CGLError CGLSetSurface(CGLContextObj gl, CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid)
141{
142 struct _CGLDisplay* disp = getCGLDisplay(cid);
143 if (!disp)
144 return kCGLBadConnection;
145
146 EGLNativeWindowType window;
147 if (sid)
148 window = (EGLNativeWindowType) _CGSNativeWindowForSurfaceID(cid, wid, sid);
149 else
150 window = (EGLNativeWindowType) _CGSNativeWindowForID(cid, wid);
151
152 if (!window)
153 return kCGLBadWindow;
154
155 gl->egl_surface = eglCreateWindowSurface(disp->display, disp->config, window, NULL);
156 if (gl->egl_surface == EGL_NO_SURFACE)
157 return kCGLBadState;
158 return kCGLNoError;
159}
160
161CGLWindowRef CGLGetWindow(void *native_window) {
162
163 EGLNativeWindowType window = (EGLNativeWindowType) native_window;
164 EGLSurface surface = eglCreateWindowSurface(display, config, window, NULL);
165
166 if (surface == EGL_NO_SURFACE) {
167 return NULL;
168 }
169
170 return (CGLWindowRef) surface;
171}
172
173CGL_EXPORT void CGLDestroyWindow(CGLWindowRef window) {
174 eglDestroySurface(display, (EGLSurface) window);
175}
176
177CGL_EXPORT CGLError CGLContextMakeCurrentAndAttachToWindow(CGLContextObj context, CGLWindowRef window) {
178 if (!context)
179 return kCGLBadContext;
180 context->egl_surface = (EGLSurface) window;
181 return CGLSetCurrentContext(context);
182}
183
184static pthread_key_t current_context_key;
185
186static void make_key() {
187 pthread_key_create(¤t_context_key, NULL);
188}
189
190static pthread_key_t get_current_context_key() {
191 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
192 pthread_once(&key_once, make_key);
193 return current_context_key;
194}
195
196CGLContextObj CGLGetCurrentContext(void) {
197 pthread_key_t key = get_current_context_key();
198 return pthread_getspecific(key);
199}
200
201CGLError CGLSetCurrentContext(CGLContextObj context) {
202 pthread_key_t key = get_current_context_key();
203 pthread_setspecific(key, context);
204
205 if (context != NULL) {
206 EGLSurface surface = context->egl_surface;
207 eglMakeCurrent(display, surface, surface, context->egl_context);
208 } else {
209 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
210 }
211
212 return kCGLNoError; // FIXME
213}
214
215CGLError CGLChoosePixelFormat(
216 const CGLPixelFormatAttribute *attrs,
217 CGLPixelFormatObj *result,
218 GLint *number_of_screens
219) {
220 CGLPixelFormatObj format = malloc(sizeof(struct _CGLPixelFormatObj));
221 int count = attributes_count(attrs);
222
223 format->retain_count = 1;
224 format->attributes = malloc(sizeof(CGLPixelFormatAttribute) * count);
225 for (int i = 0; i < count; i++) {
226 format->attributes[i] = attrs[i];
227 }
228
229 *result = format;
230 *number_of_screens = 1;
231
232 return kCGLNoError;
233}
234
235CGLError CGLDescribePixelFormat(
236 CGLPixelFormatObj format,
237 GLint sreen_num,
238 CGLPixelFormatAttribute attr,
239 GLint *value
240) {
241 for (int i = 0; format->attributes[i] != 0; i++) {
242 int has_arg = attribute_has_argument(format->attributes[i]);
243
244 if (format->attributes[i] == attr) {
245 if (has_arg) {
246 *value = format->attributes[i + 1];
247 } else {
248 *value = 1;
249 }
250 return kCGLNoError;
251 }
252
253 if (has_arg) {
254 i++;
255 }
256 }
257
258 *value = 0;
259 return kCGLNoError;
260}
261
262CGLPixelFormatObj CGLRetainPixelFormat(CGLPixelFormatObj format) {
263 if (format == NULL) {
264 return NULL;
265 }
266
267 format->retain_count++;
268 return format;
269}
270
271void CGLReleasePixelFormat(CGLPixelFormatObj format) {
272 if (format == NULL) {
273 return;
274 }
275
276 format->retain_count--;
277
278 if (format->retain_count == 0) {
279 free(format->attributes);
280 free(format);
281 }
282}
283
284CGLError CGLDestroyPixelFormat(CGLPixelFormatObj pixelFormat) {
285 CGLReleasePixelFormat(pixelFormat);
286 return kCGLNoError;
287}
288
289GLuint CGLGetPixelFormatRetainCount(CGLPixelFormatObj pixelFormat) {
290 return pixelFormat->retain_count;
291}
292
293CGLError CGLCreateContext(CGLPixelFormatObj pixelFormat, CGLContextObj share, CGLContextObj *resultp) {
294
295 EGLContext egl_share = EGL_NO_CONTEXT;
296 if (share != NULL) {
297 egl_share = share->egl_context;
298 }
299 EGLContext egl_context = eglCreateContext(display, config, egl_share, NULL);
300
301 if (egl_context == EGL_NO_CONTEXT) {
302 return kCGLBadContext;
303 }
304
305 CGLContextObj context = malloc(sizeof(struct _CGLContextObj));
306
307 context->retain_count = 1;
308 pthread_mutex_init(&(context->lock), NULL);
309 context->egl_context = egl_context;
310 context->egl_surface = NULL;
311 context->swap_interval = 1;
312
313 *resultp = context;
314
315 return kCGLNoError;
316}
317
318CGLContextObj CGLRetainContext(CGLContextObj context) {
319 if (context == NULL) {
320 return NULL;
321 }
322
323 context->retain_count++;
324 return context;
325}
326
327void CGLReleaseContext(CGLContextObj context) {
328 if (context == NULL) {
329 return;
330 }
331
332 context->retain_count--;
333
334 if (context->retain_count != 0) {
335 return;
336 }
337
338 if (CGLGetCurrentContext() == context) {
339 CGLSetCurrentContext(NULL);
340 }
341
342 pthread_mutex_destroy(&(context->lock));
343
344 eglDestroyContext(display, context->egl_context);
345
346 free(context);
347}
348
349GLuint CGLGetContextRetainCount(CGLContextObj context) {
350 if (context == NULL) {
351 return 0;
352 }
353
354 return context->retain_count;
355}
356
357CGLError CGLDestroyContext(CGLContextObj context) {
358 CGLReleaseContext(context);
359
360 return kCGLNoError;
361}
362
363CGLError CGLLockContext(CGLContextObj context) {
364 pthread_mutex_lock(&(context->lock));
365 return kCGLNoError;
366}
367
368CGLError CGLUnlockContext(CGLContextObj context) {
369 pthread_mutex_unlock(&(context->lock));
370 return kCGLNoError;
371}
372
373CGLError CGLFlushDrawable(CGLContextObj context) {
374 eglSwapBuffers(display,context->egl_surface);
375 return kCGLNoError;
376}
377
378CGLError CGLSetParameter(CGLContextObj context, CGLContextParameter parameter, const GLint *value) {
379 if (!value)
380 return kCGLBadAddress;
381
382 if (parameter == kCGLCPSwapInterval)
383 {
384 GLint v = *value;
385 EGLBoolean success = eglSwapInterval(display, v);
386 if (success)
387 context->swap_interval = v;
388 return success ? kCGLNoError : kCGLBadValue;
389 }
390 fprintf(stderr, "CGLSetParameter unimplemented for parameter %d\n", parameter);
391 return kCGLNoError;
392}
393
394CGLError CGLGetParameter(CGLContextObj context, CGLContextParameter parameter, GLint *value) {
395 if (!value)
396 return kCGLBadAddress;
397
398 if (parameter == kCGLCPSwapInterval)
399 {
400 *value = context->swap_interval;
401 return kCGLNoError;
402 }
403 fprintf(stderr, "CGLGetParameter unimplemented for parameter %d\n", parameter);
404 return kCGLNoError;
405}
406
407CGLError CGLDescribeRenderer(CGLRendererInfoObj rend, long rend_num, CGLRendererProperty prop, long *value) {
408 return kCGLNoError;
409}
410
411CGLError CGLQueryRendererInfo(unsigned long display_mask, CGLRendererInfoObj *rend, long *nrend) {
412 return kCGLNoError;
413}
414
415CGLError CGLDestroyRendererInfo(CGLRendererInfoObj rend) {
416 return kCGLNoError;
417}