| /* |
| Copyright (c) 2009 Apple Inc. |
| |
| Permission is hereby granted, free of charge, to any person |
| obtaining a copy of this software and associated documentation files |
| (the "Software"), to deal in the Software without restriction, |
| including without limitation the rights to use, copy, modify, merge, |
| publish, distribute, sublicense, and/or sell copies of the Software, |
| and to permit persons to whom the Software is furnished to do so, |
| subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT |
| HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| DEALINGS IN THE SOFTWARE. |
| |
| Except as contained in this notice, the name(s) of the above |
| copyright holders shall not be used in advertising or otherwise to |
| promote the sale, use or other dealings in this Software without |
| prior written authorization. |
| */ |
| |
| /* Must be before OpenGL.framework is included. Remove once fixed: |
| * <rdar://problem/7872773> |
| */ |
| #include <GL/gl.h> |
| #include <GL/glext.h> |
| #define __gltypes_h_ 1 |
| |
| /* Must be first for: |
| * <rdar://problem/6953344> |
| */ |
| #include "apple_glx_context.h" |
| #include "apple_glx_drawable.h" |
| |
| #include <stdbool.h> |
| #include <stdlib.h> |
| #include <pthread.h> |
| #include <assert.h> |
| #include "apple_glx.h" |
| #include "glxconfig.h" |
| #include "apple_cgl.h" |
| #include "util/debug.h" |
| |
| /* mesa defines in glew.h, Apple in glext.h. |
| * Due to namespace nightmares, just do it here. |
| */ |
| #ifndef GL_TEXTURE_RECTANGLE_EXT |
| #define GL_TEXTURE_RECTANGLE_EXT 0x84F5 |
| #endif |
| |
| static bool pbuffer_make_current(struct apple_glx_context *ac, |
| struct apple_glx_drawable *d); |
| |
| static void pbuffer_destroy(Display * dpy, struct apple_glx_drawable *d); |
| |
| static struct apple_glx_drawable_callbacks callbacks = { |
| .type = APPLE_GLX_DRAWABLE_PBUFFER, |
| .make_current = pbuffer_make_current, |
| .destroy = pbuffer_destroy |
| }; |
| |
| |
| /* Return true if an error occurred. */ |
| bool |
| pbuffer_make_current(struct apple_glx_context *ac, |
| struct apple_glx_drawable *d) |
| { |
| struct apple_glx_pbuffer *pbuf = &d->types.pbuffer; |
| CGLError cglerr; |
| |
| assert(APPLE_GLX_DRAWABLE_PBUFFER == d->type); |
| |
| cglerr = apple_cgl.set_pbuffer(ac->context_obj, pbuf->buffer_obj, 0, 0, 0); |
| |
| if (kCGLNoError != cglerr) { |
| fprintf(stderr, "set_pbuffer: %s\n", apple_cgl.error_string(cglerr)); |
| return true; |
| } |
| |
| if (!ac->made_current) { |
| apple_glapi_oglfw_viewport_scissor(0, 0, pbuf->width, pbuf->height); |
| ac->made_current = true; |
| } |
| |
| apple_glx_diagnostic("made pbuffer drawable 0x%lx current\n", d->drawable); |
| |
| return false; |
| } |
| |
| void |
| pbuffer_destroy(Display * dpy, struct apple_glx_drawable *d) |
| { |
| struct apple_glx_pbuffer *pbuf = &d->types.pbuffer; |
| |
| assert(APPLE_GLX_DRAWABLE_PBUFFER == d->type); |
| |
| apple_glx_diagnostic("destroying pbuffer for drawable 0x%lx\n", |
| d->drawable); |
| |
| apple_cgl.destroy_pbuffer(pbuf->buffer_obj); |
| XFreePixmap(dpy, pbuf->xid); |
| } |
| |
| /* Return true if an error occurred. */ |
| bool |
| apple_glx_pbuffer_destroy(Display * dpy, GLXPbuffer pbuf) |
| { |
| return !apple_glx_drawable_destroy_by_type(dpy, pbuf, |
| APPLE_GLX_DRAWABLE_PBUFFER); |
| } |
| |
| /* Return true if an error occurred. */ |
| bool |
| apple_glx_pbuffer_create(Display * dpy, GLXFBConfig config, |
| int width, int height, int *errorcode, |
| GLXPbuffer * result) |
| { |
| struct apple_glx_drawable *d; |
| struct apple_glx_pbuffer *pbuf = NULL; |
| CGLError err; |
| Window root; |
| int screen; |
| Pixmap xid; |
| struct glx_config *modes = (struct glx_config *) config; |
| |
| root = DefaultRootWindow(dpy); |
| screen = DefaultScreen(dpy); |
| |
| /* |
| * This pixmap is only used for a persistent XID. |
| * The XC-MISC extension cleans up XIDs and reuses them transparently, |
| * so we need to retain a server-side reference. |
| */ |
| xid = XCreatePixmap(dpy, root, (unsigned int) 1, |
| (unsigned int) 1, DefaultDepth(dpy, screen)); |
| |
| if (None == xid) { |
| *errorcode = BadAlloc; |
| return true; |
| } |
| |
| if (apple_glx_drawable_create(dpy, screen, xid, &d, &callbacks)) { |
| *errorcode = BadAlloc; |
| return true; |
| } |
| |
| /* The lock is held in d from create onward. */ |
| pbuf = &d->types.pbuffer; |
| |
| pbuf->xid = xid; |
| pbuf->width = width; |
| pbuf->height = height; |
| |
| err = apple_cgl.create_pbuffer(width, height, GL_TEXTURE_RECTANGLE_EXT, |
| (modes->alphaBits > 0) ? GL_RGBA : GL_RGB, |
| 0, &pbuf->buffer_obj); |
| |
| if (kCGLNoError != err) { |
| d->unlock(d); |
| d->destroy(d); |
| *errorcode = BadMatch; |
| return true; |
| } |
| |
| pbuf->fbconfigID = modes->fbconfigID; |
| |
| pbuf->event_mask = 0; |
| |
| *result = pbuf->xid; |
| |
| d->unlock(d); |
| |
| return false; |
| } |
| |
| |
| |
| /* Return true if an error occurred. */ |
| static bool |
| get_max_size(int *widthresult, int *heightresult) |
| { |
| CGLContextObj oldcontext; |
| GLint ar[2]; |
| |
| oldcontext = apple_cgl.get_current_context(); |
| |
| if (!oldcontext) { |
| /* |
| * There is no current context, so we need to make one in order |
| * to call glGetInteger. |
| */ |
| CGLPixelFormatObj pfobj; |
| CGLError err; |
| CGLPixelFormatAttribute attr[10]; |
| int c = 0; |
| GLint vsref = 0; |
| CGLContextObj newcontext; |
| |
| attr[c++] = kCGLPFAColorSize; |
| attr[c++] = 32; |
| attr[c++] = 0; |
| |
| err = apple_cgl.choose_pixel_format(attr, &pfobj, &vsref); |
| if (kCGLNoError != err) { |
| DebugMessageF("choose_pixel_format error in %s: %s\n", __func__, |
| apple_cgl.error_string(err)); |
| |
| return true; |
| } |
| |
| |
| err = apple_cgl.create_context(pfobj, NULL, &newcontext); |
| |
| if (kCGLNoError != err) { |
| DebugMessageF("create_context error in %s: %s\n", __func__, |
| apple_cgl.error_string(err)); |
| |
| apple_cgl.destroy_pixel_format(pfobj); |
| |
| return true; |
| } |
| |
| err = apple_cgl.set_current_context(newcontext); |
| |
| if (kCGLNoError != err) { |
| DebugMessageF("set_current_context error in %s: %s\n", __func__, |
| apple_cgl.error_string(err)); |
| return true; |
| } |
| |
| |
| glGetIntegerv(GL_MAX_VIEWPORT_DIMS, ar); |
| |
| apple_cgl.set_current_context(oldcontext); |
| apple_cgl.destroy_context(newcontext); |
| apple_cgl.destroy_pixel_format(pfobj); |
| } |
| else { |
| /* We have a valid context. */ |
| |
| glGetIntegerv(GL_MAX_VIEWPORT_DIMS, ar); |
| } |
| |
| *widthresult = ar[0]; |
| *heightresult = ar[1]; |
| |
| return false; |
| } |
| |
| bool |
| apple_glx_pbuffer_query(GLXPbuffer p, int attr, unsigned int *value) |
| { |
| bool result = false; |
| struct apple_glx_drawable *d; |
| struct apple_glx_pbuffer *pbuf; |
| |
| d = apple_glx_drawable_find_by_type(p, APPLE_GLX_DRAWABLE_PBUFFER, |
| APPLE_GLX_DRAWABLE_LOCK); |
| |
| if (d) { |
| pbuf = &d->types.pbuffer; |
| |
| switch (attr) { |
| case GLX_WIDTH: |
| *value = pbuf->width; |
| result = true; |
| break; |
| |
| case GLX_HEIGHT: |
| *value = pbuf->height; |
| result = true; |
| break; |
| |
| case GLX_PRESERVED_CONTENTS: |
| *value = true; |
| result = true; |
| break; |
| |
| case GLX_LARGEST_PBUFFER:{ |
| int width, height; |
| if (get_max_size(&width, &height)) { |
| fprintf(stderr, "internal error: " |
| "unable to find the largest pbuffer!\n"); |
| } |
| else { |
| *value = width; |
| result = true; |
| } |
| } |
| break; |
| |
| case GLX_FBCONFIG_ID: |
| *value = pbuf->fbconfigID; |
| result = true; |
| break; |
| } |
| |
| d->unlock(d); |
| } |
| |
| return result; |
| } |
| |
| bool |
| apple_glx_pbuffer_set_event_mask(GLXDrawable drawable, unsigned long mask) |
| { |
| struct apple_glx_drawable *d; |
| bool result = false; |
| |
| d = apple_glx_drawable_find_by_type(drawable, APPLE_GLX_DRAWABLE_PBUFFER, |
| APPLE_GLX_DRAWABLE_LOCK); |
| |
| if (d) { |
| d->types.pbuffer.event_mask = mask; |
| result = true; |
| d->unlock(d); |
| } |
| |
| return result; |
| } |
| |
| bool |
| apple_glx_pbuffer_get_event_mask(GLXDrawable drawable, unsigned long *mask) |
| { |
| struct apple_glx_drawable *d; |
| bool result = false; |
| |
| d = apple_glx_drawable_find_by_type(drawable, APPLE_GLX_DRAWABLE_PBUFFER, |
| APPLE_GLX_DRAWABLE_LOCK); |
| if (d) { |
| *mask = d->types.pbuffer.event_mask; |
| result = true; |
| d->unlock(d); |
| } |
| |
| return result; |
| } |