1 /*
2  Copyright (c) 2009 Apple Inc.
3 
4  Permission is hereby granted, free of charge, to any person
5  obtaining a copy of this software and associated documentation files
6  (the "Software"), to deal in the Software without restriction,
7  including without limitation the rights to use, copy, modify, merge,
8  publish, distribute, sublicense, and/or sell copies of the Software,
9  and to permit persons to whom the Software is furnished to do so,
10  subject to the following conditions:
11 
12  The above copyright notice and this permission notice shall be
13  included in all copies or substantial portions of the Software.
14 
15  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
19  HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  DEALINGS IN THE SOFTWARE.
23 
24  Except as contained in this notice, the name(s) of the above
25  copyright holders shall not be used in advertising or otherwise to
26  promote the sale, use or other dealings in this Software without
27  prior written authorization.
28 */
29 
30 /* Must be before OpenGL.framework is included.  Remove once fixed:
31  * <rdar://problem/7872773>
32  */
33 #include <GL/gl.h>
34 #include <GL/glext.h>
35 #define __gltypes_h_ 1
36 
37 /* Must be first for:
38  * <rdar://problem/6953344>
39  */
40 #include "apple_glx_context.h"
41 #include "apple_glx_drawable.h"
42 
43 #include <stdbool.h>
44 #include <stdlib.h>
45 #include <pthread.h>
46 #include <assert.h>
47 #include "apple_glx.h"
48 #include "glxconfig.h"
49 #include "apple_cgl.h"
50 #include "util/debug.h"
51 
52 /* mesa defines in glew.h, Apple in glext.h.
53  * Due to namespace nightmares, just do it here.
54  */
55 #ifndef GL_TEXTURE_RECTANGLE_EXT
56 #define GL_TEXTURE_RECTANGLE_EXT 0x84F5
57 #endif
58 
59 static bool pbuffer_make_current(struct apple_glx_context *ac,
60                                  struct apple_glx_drawable *d);
61 
62 static void pbuffer_destroy(Display * dpy, struct apple_glx_drawable *d);
63 
64 static struct apple_glx_drawable_callbacks callbacks = {
65    .type = APPLE_GLX_DRAWABLE_PBUFFER,
66    .make_current = pbuffer_make_current,
67    .destroy = pbuffer_destroy
68 };
69 
70 
71 /* Return true if an error occurred. */
72 bool
pbuffer_make_current(struct apple_glx_context * ac,struct apple_glx_drawable * d)73 pbuffer_make_current(struct apple_glx_context *ac,
74                      struct apple_glx_drawable *d)
75 {
76    struct apple_glx_pbuffer *pbuf = &d->types.pbuffer;
77    CGLError cglerr;
78 
79    assert(APPLE_GLX_DRAWABLE_PBUFFER == d->type);
80 
81    cglerr = apple_cgl.set_pbuffer(ac->context_obj, pbuf->buffer_obj, 0, 0, 0);
82 
83    if (kCGLNoError != cglerr) {
84       fprintf(stderr, "set_pbuffer: %s\n", apple_cgl.error_string(cglerr));
85       return true;
86    }
87 
88    if (!ac->made_current) {
89       apple_glapi_oglfw_viewport_scissor(0, 0, pbuf->width, pbuf->height);
90       ac->made_current = true;
91    }
92 
93    apple_glx_diagnostic("made pbuffer drawable 0x%lx current\n", d->drawable);
94 
95    return false;
96 }
97 
98 void
pbuffer_destroy(Display * dpy,struct apple_glx_drawable * d)99 pbuffer_destroy(Display * dpy, struct apple_glx_drawable *d)
100 {
101    struct apple_glx_pbuffer *pbuf = &d->types.pbuffer;
102 
103    assert(APPLE_GLX_DRAWABLE_PBUFFER == d->type);
104 
105    apple_glx_diagnostic("destroying pbuffer for drawable 0x%lx\n",
106                         d->drawable);
107 
108    apple_cgl.destroy_pbuffer(pbuf->buffer_obj);
109    XFreePixmap(dpy, pbuf->xid);
110 }
111 
112 /* Return true if an error occurred. */
113 bool
apple_glx_pbuffer_destroy(Display * dpy,GLXPbuffer pbuf)114 apple_glx_pbuffer_destroy(Display * dpy, GLXPbuffer pbuf)
115 {
116    return !apple_glx_drawable_destroy_by_type(dpy, pbuf,
117                                               APPLE_GLX_DRAWABLE_PBUFFER);
118 }
119 
120 /* Return true if an error occurred. */
121 bool
apple_glx_pbuffer_create(Display * dpy,GLXFBConfig config,int width,int height,int * errorcode,GLXPbuffer * result)122 apple_glx_pbuffer_create(Display * dpy, GLXFBConfig config,
123                          int width, int height, int *errorcode,
124                          GLXPbuffer * result)
125 {
126    struct apple_glx_drawable *d;
127    struct apple_glx_pbuffer *pbuf = NULL;
128    CGLError err;
129    Window root;
130    int screen;
131    Pixmap xid;
132    struct glx_config *modes = (struct glx_config *) config;
133 
134    root = DefaultRootWindow(dpy);
135    screen = DefaultScreen(dpy);
136 
137    /*
138     * This pixmap is only used for a persistent XID.
139     * The XC-MISC extension cleans up XIDs and reuses them transparently,
140     * so we need to retain a server-side reference.
141     */
142    xid = XCreatePixmap(dpy, root, (unsigned int) 1,
143                        (unsigned int) 1, DefaultDepth(dpy, screen));
144 
145    if (None == xid) {
146       *errorcode = BadAlloc;
147       return true;
148    }
149 
150    if (apple_glx_drawable_create(dpy, screen, xid, &d, &callbacks)) {
151       *errorcode = BadAlloc;
152       return true;
153    }
154 
155    /* The lock is held in d from create onward. */
156    pbuf = &d->types.pbuffer;
157 
158    pbuf->xid = xid;
159    pbuf->width = width;
160    pbuf->height = height;
161 
162    err = apple_cgl.create_pbuffer(width, height, GL_TEXTURE_RECTANGLE_EXT,
163                                   (modes->alphaBits > 0) ? GL_RGBA : GL_RGB,
164                                   0, &pbuf->buffer_obj);
165 
166    if (kCGLNoError != err) {
167       d->unlock(d);
168       d->destroy(d);
169       *errorcode = BadMatch;
170       return true;
171    }
172 
173    pbuf->fbconfigID = modes->fbconfigID;
174 
175    pbuf->event_mask = 0;
176 
177    *result = pbuf->xid;
178 
179    d->unlock(d);
180 
181    return false;
182 }
183 
184 
185 
186 /* Return true if an error occurred. */
187 static bool
get_max_size(int * widthresult,int * heightresult)188 get_max_size(int *widthresult, int *heightresult)
189 {
190    CGLContextObj oldcontext;
191    GLint ar[2];
192 
193    oldcontext = apple_cgl.get_current_context();
194 
195    if (!oldcontext) {
196       /*
197        * There is no current context, so we need to make one in order
198        * to call glGetInteger.
199        */
200       CGLPixelFormatObj pfobj;
201       CGLError err;
202       CGLPixelFormatAttribute attr[10];
203       int c = 0;
204       GLint vsref = 0;
205       CGLContextObj newcontext;
206 
207       attr[c++] = kCGLPFAColorSize;
208       attr[c++] = 32;
209       attr[c++] = 0;
210 
211       err = apple_cgl.choose_pixel_format(attr, &pfobj, &vsref);
212       if (kCGLNoError != err) {
213          if (env_var_as_boolean("LIBGL_DIAGNOSTIC", false)) {
214             printf("choose_pixel_format error in %s: %s\n", __func__,
215                    apple_cgl.error_string(err));
216          }
217 
218          return true;
219       }
220 
221 
222       err = apple_cgl.create_context(pfobj, NULL, &newcontext);
223 
224       if (kCGLNoError != err) {
225          if (env_var_as_boolean("LIBGL_DIAGNOSTIC", false)) {
226             printf("create_context error in %s: %s\n", __func__,
227                    apple_cgl.error_string(err));
228          }
229 
230          apple_cgl.destroy_pixel_format(pfobj);
231 
232          return true;
233       }
234 
235       err = apple_cgl.set_current_context(newcontext);
236 
237       if (kCGLNoError != err) {
238          printf("set_current_context error in %s: %s\n", __func__,
239                 apple_cgl.error_string(err));
240          return true;
241       }
242 
243 
244       glGetIntegerv(GL_MAX_VIEWPORT_DIMS, ar);
245 
246       apple_cgl.set_current_context(oldcontext);
247       apple_cgl.destroy_context(newcontext);
248       apple_cgl.destroy_pixel_format(pfobj);
249    }
250    else {
251       /* We have a valid context. */
252 
253       glGetIntegerv(GL_MAX_VIEWPORT_DIMS, ar);
254    }
255 
256    *widthresult = ar[0];
257    *heightresult = ar[1];
258 
259    return false;
260 }
261 
262 bool
apple_glx_pbuffer_query(GLXPbuffer p,int attr,unsigned int * value)263 apple_glx_pbuffer_query(GLXPbuffer p, int attr, unsigned int *value)
264 {
265    bool result = false;
266    struct apple_glx_drawable *d;
267    struct apple_glx_pbuffer *pbuf;
268 
269    d = apple_glx_drawable_find_by_type(p, APPLE_GLX_DRAWABLE_PBUFFER,
270                                        APPLE_GLX_DRAWABLE_LOCK);
271 
272    if (d) {
273       pbuf = &d->types.pbuffer;
274 
275       switch (attr) {
276       case GLX_WIDTH:
277          *value = pbuf->width;
278          result = true;
279          break;
280 
281       case GLX_HEIGHT:
282          *value = pbuf->height;
283          result = true;
284          break;
285 
286       case GLX_PRESERVED_CONTENTS:
287          *value = true;
288          result = true;
289          break;
290 
291       case GLX_LARGEST_PBUFFER:{
292             int width, height;
293             if (get_max_size(&width, &height)) {
294                fprintf(stderr, "internal error: "
295                        "unable to find the largest pbuffer!\n");
296             }
297             else {
298                *value = width;
299                result = true;
300             }
301          }
302          break;
303 
304       case GLX_FBCONFIG_ID:
305          *value = pbuf->fbconfigID;
306          result = true;
307          break;
308       }
309 
310       d->unlock(d);
311    }
312 
313    return result;
314 }
315 
316 bool
apple_glx_pbuffer_set_event_mask(GLXDrawable drawable,unsigned long mask)317 apple_glx_pbuffer_set_event_mask(GLXDrawable drawable, unsigned long mask)
318 {
319    struct apple_glx_drawable *d;
320    bool result = false;
321 
322    d = apple_glx_drawable_find_by_type(drawable, APPLE_GLX_DRAWABLE_PBUFFER,
323                                        APPLE_GLX_DRAWABLE_LOCK);
324 
325    if (d) {
326       d->types.pbuffer.event_mask = mask;
327       result = true;
328       d->unlock(d);
329    }
330 
331    return result;
332 }
333 
334 bool
apple_glx_pbuffer_get_event_mask(GLXDrawable drawable,unsigned long * mask)335 apple_glx_pbuffer_get_event_mask(GLXDrawable drawable, unsigned long *mask)
336 {
337    struct apple_glx_drawable *d;
338    bool result = false;
339 
340    d = apple_glx_drawable_find_by_type(drawable, APPLE_GLX_DRAWABLE_PBUFFER,
341                                        APPLE_GLX_DRAWABLE_LOCK);
342    if (d) {
343       *mask = d->types.pbuffer.event_mask;
344       result = true;
345       d->unlock(d);
346    }
347 
348    return result;
349 }
350