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
60static bool pbuffer_make_current(struct apple_glx_context *ac,
61                                 struct apple_glx_drawable *d);
62
63static void pbuffer_destroy(Display * dpy, struct apple_glx_drawable *d);
64
65static 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. */
73bool
74pbuffer_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
99void
100pbuffer_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. */
114bool
115apple_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. */
122bool
123apple_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. */
188static bool
189get_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
259bool
260apple_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
313bool
314apple_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
331bool
332apple_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