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 "glxclient.h"
48 #include "apple_glx.h"
49 #include "glxconfig.h"
50 #include "apple_cgl.h"
51 #include "util/debug.h"
52
53 /* mesa defines in glew.h, Apple in glext.h.
54 * Due to namespace nightmares, just do it here.
55 */
56 #ifndef GL_TEXTURE_RECTANGLE_EXT
57 #define GL_TEXTURE_RECTANGLE_EXT 0x84F5
58 #endif
59
60 static bool pbuffer_make_current(struct apple_glx_context *ac,
61 struct apple_glx_drawable *d);
62
63 static void pbuffer_destroy(Display * dpy, struct apple_glx_drawable *d);
64
65 static struct apple_glx_drawable_callbacks callbacks = {
66 .type = APPLE_GLX_DRAWABLE_PBUFFER,
67 .make_current = pbuffer_make_current,
68 .destroy = pbuffer_destroy
69 };
70
71
72 /* Return true if an error occurred. */
73 bool
pbuffer_make_current(struct apple_glx_context * ac,struct apple_glx_drawable * d)74 pbuffer_make_current(struct apple_glx_context *ac,
75 struct apple_glx_drawable *d)
76 {
77 struct apple_glx_pbuffer *pbuf = &d->types.pbuffer;
78 CGLError cglerr;
79
80 assert(APPLE_GLX_DRAWABLE_PBUFFER == d->type);
81
82 cglerr = apple_cgl.set_pbuffer(ac->context_obj, pbuf->buffer_obj, 0, 0, 0);
83
84 if (kCGLNoError != cglerr) {
85 fprintf(stderr, "set_pbuffer: %s\n", apple_cgl.error_string(cglerr));
86 return true;
87 }
88
89 if (!ac->made_current) {
90 apple_glapi_oglfw_viewport_scissor(0, 0, pbuf->width, pbuf->height);
91 ac->made_current = true;
92 }
93
94 apple_glx_diagnostic("made pbuffer drawable 0x%lx current\n", d->drawable);
95
96 return false;
97 }
98
99 void
pbuffer_destroy(Display * dpy,struct apple_glx_drawable * d)100 pbuffer_destroy(Display * dpy, struct apple_glx_drawable *d)
101 {
102 struct apple_glx_pbuffer *pbuf = &d->types.pbuffer;
103
104 assert(APPLE_GLX_DRAWABLE_PBUFFER == d->type);
105
106 apple_glx_diagnostic("destroying pbuffer for drawable 0x%lx\n",
107 d->drawable);
108
109 apple_cgl.destroy_pbuffer(pbuf->buffer_obj);
110 XFreePixmap(dpy, pbuf->xid);
111 }
112
113 /* Return true if an error occurred. */
114 bool
apple_glx_pbuffer_destroy(Display * dpy,GLXPbuffer pbuf)115 apple_glx_pbuffer_destroy(Display * dpy, GLXPbuffer pbuf)
116 {
117 return !apple_glx_drawable_destroy_by_type(dpy, pbuf,
118 APPLE_GLX_DRAWABLE_PBUFFER);
119 }
120
121 /* Return true if an error occurred. */
122 bool
apple_glx_pbuffer_create(Display * dpy,GLXFBConfig config,int width,int height,int * errorcode,GLXPbuffer * result)123 apple_glx_pbuffer_create(Display * dpy, GLXFBConfig config,
124 int width, int height, int *errorcode,
125 GLXPbuffer * result)
126 {
127 struct apple_glx_drawable *d;
128 struct apple_glx_pbuffer *pbuf = NULL;
129 CGLError err;
130 Window root;
131 int screen;
132 Pixmap xid;
133 struct glx_config *modes = (struct glx_config *) config;
134
135 root = DefaultRootWindow(dpy);
136 screen = DefaultScreen(dpy);
137
138 /*
139 * This pixmap is only used for a persistent XID.
140 * The XC-MISC extension cleans up XIDs and reuses them transparently,
141 * so we need to retain a server-side reference.
142 */
143 xid = XCreatePixmap(dpy, root, (unsigned int) 1,
144 (unsigned int) 1, DefaultDepth(dpy, screen));
145
146 if (None == xid) {
147 *errorcode = BadAlloc;
148 return true;
149 }
150
151 if (apple_glx_drawable_create(dpy, screen, xid, &d, &callbacks)) {
152 *errorcode = BadAlloc;
153 return true;
154 }
155
156 /* The lock is held in d from create onward. */
157 pbuf = &d->types.pbuffer;
158
159 pbuf->xid = xid;
160 pbuf->width = width;
161 pbuf->height = height;
162
163 err = apple_cgl.create_pbuffer(width, height, GL_TEXTURE_RECTANGLE_EXT,
164 (modes->alphaBits > 0) ? GL_RGBA : GL_RGB,
165 0, &pbuf->buffer_obj);
166
167 if (kCGLNoError != err) {
168 d->unlock(d);
169 d->destroy(d);
170 *errorcode = BadMatch;
171 return true;
172 }
173
174 pbuf->fbconfigID = modes->fbconfigID;
175
176 pbuf->event_mask = 0;
177
178 *result = pbuf->xid;
179
180 d->unlock(d);
181
182 return false;
183 }
184
185
186
187 /* Return true if an error occurred. */
188 static bool
get_max_size(int * widthresult,int * heightresult)189 get_max_size(int *widthresult, int *heightresult)
190 {
191 CGLContextObj oldcontext;
192 GLint ar[2];
193
194 oldcontext = apple_cgl.get_current_context();
195
196 if (!oldcontext) {
197 /*
198 * There is no current context, so we need to make one in order
199 * to call glGetInteger.
200 */
201 CGLPixelFormatObj pfobj;
202 CGLError err;
203 CGLPixelFormatAttribute attr[10];
204 int c = 0;
205 GLint vsref = 0;
206 CGLContextObj newcontext;
207
208 attr[c++] = kCGLPFAColorSize;
209 attr[c++] = 32;
210 attr[c++] = 0;
211
212 err = apple_cgl.choose_pixel_format(attr, &pfobj, &vsref);
213 if (kCGLNoError != err) {
214 DebugMessageF("choose_pixel_format error in %s: %s\n", __func__,
215 apple_cgl.error_string(err));
216
217 return true;
218 }
219
220
221 err = apple_cgl.create_context(pfobj, NULL, &newcontext);
222
223 if (kCGLNoError != err) {
224 DebugMessageF("create_context error in %s: %s\n", __func__,
225 apple_cgl.error_string(err));
226
227 apple_cgl.destroy_pixel_format(pfobj);
228
229 return true;
230 }
231
232 err = apple_cgl.set_current_context(newcontext);
233
234 if (kCGLNoError != err) {
235 DebugMessageF("set_current_context error in %s: %s\n", __func__,
236 apple_cgl.error_string(err));
237 return true;
238 }
239
240
241 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, ar);
242
243 apple_cgl.set_current_context(oldcontext);
244 apple_cgl.destroy_context(newcontext);
245 apple_cgl.destroy_pixel_format(pfobj);
246 }
247 else {
248 /* We have a valid context. */
249
250 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, ar);
251 }
252
253 *widthresult = ar[0];
254 *heightresult = ar[1];
255
256 return false;
257 }
258
259 bool
apple_glx_pbuffer_query(GLXPbuffer p,int attr,unsigned int * value)260 apple_glx_pbuffer_query(GLXPbuffer p, int attr, unsigned int *value)
261 {
262 bool result = false;
263 struct apple_glx_drawable *d;
264 struct apple_glx_pbuffer *pbuf;
265
266 d = apple_glx_drawable_find_by_type(p, APPLE_GLX_DRAWABLE_PBUFFER,
267 APPLE_GLX_DRAWABLE_LOCK);
268
269 if (d) {
270 pbuf = &d->types.pbuffer;
271
272 switch (attr) {
273 case GLX_WIDTH:
274 *value = pbuf->width;
275 result = true;
276 break;
277
278 case GLX_HEIGHT:
279 *value = pbuf->height;
280 result = true;
281 break;
282
283 case GLX_PRESERVED_CONTENTS:
284 *value = true;
285 result = true;
286 break;
287
288 case GLX_LARGEST_PBUFFER:{
289 int width, height;
290 if (get_max_size(&width, &height)) {
291 fprintf(stderr, "internal error: "
292 "unable to find the largest pbuffer!\n");
293 }
294 else {
295 *value = width;
296 result = true;
297 }
298 }
299 break;
300
301 case GLX_FBCONFIG_ID:
302 *value = pbuf->fbconfigID;
303 result = true;
304 break;
305 }
306
307 d->unlock(d);
308 }
309
310 return result;
311 }
312
313 bool
apple_glx_pbuffer_set_event_mask(GLXDrawable drawable,unsigned long mask)314 apple_glx_pbuffer_set_event_mask(GLXDrawable drawable, unsigned long mask)
315 {
316 struct apple_glx_drawable *d;
317 bool result = false;
318
319 d = apple_glx_drawable_find_by_type(drawable, APPLE_GLX_DRAWABLE_PBUFFER,
320 APPLE_GLX_DRAWABLE_LOCK);
321
322 if (d) {
323 d->types.pbuffer.event_mask = mask;
324 result = true;
325 d->unlock(d);
326 }
327
328 return result;
329 }
330
331 bool
apple_glx_pbuffer_get_event_mask(GLXDrawable drawable,unsigned long * mask)332 apple_glx_pbuffer_get_event_mask(GLXDrawable drawable, unsigned long *mask)
333 {
334 struct apple_glx_drawable *d;
335 bool result = false;
336
337 d = apple_glx_drawable_find_by_type(drawable, APPLE_GLX_DRAWABLE_PBUFFER,
338 APPLE_GLX_DRAWABLE_LOCK);
339 if (d) {
340 *mask = d->types.pbuffer.event_mask;
341 result = true;
342 d->unlock(d);
343 }
344
345 return result;
346 }
347