/* * Mac driver OpenGL support * * Copyright 2012 Alexandre Julliard * Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include "macdrv.h" #include "winuser.h" #include "winternl.h" #include "wine/library.h" #include "wine/debug.h" #include "wine/wgl.h" #include "wine/wgl_driver.h" #include "wine/wglext.h" #define __gl_h_ #include #include #include #include WINE_DEFAULT_DEBUG_CHANNEL(wgl); struct gl_info { char *glVersion; char *glExtensions; char wglExtensions[4096]; GLint max_viewport_dims[2]; }; static struct gl_info gl_info; struct wgl_context { HDC hdc; int format; macdrv_opengl_context context; CGLContextObj cglcontext; macdrv_view draw_view; struct wgl_pbuffer *draw_pbuffer; macdrv_view read_view; struct wgl_pbuffer *read_pbuffer; BOOL has_been_current; BOOL sharing; }; struct wgl_pbuffer { CGLPBufferObj pbuffer; int format; BOOL no_texture; int max_level; GLint level; GLenum face; }; static CFMutableDictionaryRef dc_pbuffers; static CRITICAL_SECTION dc_pbuffers_section; static CRITICAL_SECTION_DEBUG dc_pbuffers_section_debug = { 0, 0, &dc_pbuffers_section, { &dc_pbuffers_section_debug.ProcessLocksList, &dc_pbuffers_section_debug.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": dc_pbuffers_section") } }; static CRITICAL_SECTION dc_pbuffers_section = { &dc_pbuffers_section_debug, -1, 0, 0, 0, 0 }; static struct opengl_funcs opengl_funcs; #define USE_GL_FUNC(name) #name, static const char *opengl_func_names[] = { ALL_WGL_FUNCS }; #undef USE_GL_FUNC static void (*pglCopyColorTable)(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); static void (*pglCopyPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); static void (*pglReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); static void (*pglViewport)(GLint x, GLint y, GLsizei width, GLsizei height); struct color_mode { GLint mode; int bits_per_pixel; GLint color_bits; /* including alpha_bits */ int red_bits, red_shift; int green_bits, green_shift; int blue_bits, blue_shift; GLint alpha_bits, alpha_shift; BOOL is_float; }; static const struct color_mode color_modes[] = { { kCGLRGB444Bit, 16, 12, 4, 8, 4, 4, 4, 0, 0, 0, FALSE }, { kCGLARGB4444Bit, 16, 16, 4, 8, 4, 4, 4, 0, 4, 12, FALSE }, { kCGLRGB444A8Bit, 24, 20, 4, 8, 4, 4, 4, 0, 8, 16, FALSE }, { kCGLRGB555Bit, 16, 15, 5, 10, 5, 5, 5, 0, 0, 0, FALSE }, { kCGLARGB1555Bit, 16, 16, 5, 10, 5, 5, 5, 0, 1, 15, FALSE }, { kCGLRGB555A8Bit, 24, 23, 5, 10, 5, 5, 5, 0, 8, 16, FALSE }, { kCGLRGB565Bit, 16, 16, 5, 11, 6, 5, 5, 0, 0, 0, FALSE }, { kCGLRGB565A8Bit, 24, 24, 5, 11, 6, 5, 5, 0, 8, 16, FALSE }, { kCGLRGB888Bit, 32, 24, 8, 16, 8, 8, 8, 0, 0, 0, FALSE }, { kCGLARGB8888Bit, 32, 32, 8, 16, 8, 8, 8, 0, 8, 24, FALSE }, { kCGLRGB888A8Bit, 40, 32, 8, 16, 8, 8, 8, 0, 8, 32, FALSE }, { kCGLRGB101010Bit, 32, 30, 10, 20, 10, 10, 10, 0, 0, 0, FALSE }, { kCGLARGB2101010Bit, 32, 32, 10, 20, 10, 10, 10, 0, 2, 30, FALSE }, { kCGLRGB101010_A8Bit, 40, 38, 10, 20, 10, 10, 10, 0, 8, 32, FALSE }, { kCGLRGB121212Bit, 48, 36, 12, 24, 12, 12, 12, 0, 0, 0, FALSE }, { kCGLARGB12121212Bit, 48, 48, 12, 24, 12, 12, 12, 0, 12, 36, FALSE }, { kCGLRGB161616Bit, 64, 48, 16, 48, 16, 32, 16, 16, 0, 0, FALSE }, { kCGLRGBA16161616Bit, 64, 64, 16, 48, 16, 32, 16, 16, 16, 0, FALSE }, { kCGLRGBFloat64Bit, 64, 48, 16, 32, 16, 16, 16, 0, 0, 0, TRUE }, { kCGLRGBAFloat64Bit, 64, 64, 16, 48, 16, 32, 16, 16, 16, 0, TRUE }, { kCGLRGBFloat128Bit, 128, 96, 32, 96, 32, 64, 32, 32, 0, 0, TRUE }, { kCGLRGBAFloat128Bit, 128, 128, 32, 96, 32, 64, 32, 32, 32, 0, TRUE }, { kCGLRGBFloat256Bit, 256, 192, 64, 192, 64, 128, 64, 64, 0, 0, TRUE }, { kCGLRGBAFloat256Bit, 256, 256, 64, 192, 64, 128, 64, 64, 64, 0, TRUE }, }; static const struct { GLint mode; int bits; } depth_stencil_modes[] = { { kCGL0Bit, 0 }, { kCGL1Bit, 1 }, { kCGL2Bit, 2 }, { kCGL3Bit, 3 }, { kCGL4Bit, 4 }, { kCGL5Bit, 5 }, { kCGL6Bit, 6 }, { kCGL8Bit, 8 }, { kCGL10Bit, 10 }, { kCGL12Bit, 12 }, { kCGL16Bit, 16 }, { kCGL24Bit, 24 }, { kCGL32Bit, 32 }, { kCGL48Bit, 48 }, { kCGL64Bit, 64 }, { kCGL96Bit, 96 }, { kCGL128Bit, 128 }, }; typedef struct { GLint renderer_id; GLint buffer_modes; GLint color_modes; GLint accum_modes; GLint depth_modes; GLint stencil_modes; GLint max_aux_buffers; GLint max_sample_buffers; GLint max_samples; BOOL offscreen; BOOL accelerated; BOOL backing_store; BOOL window; BOOL online; } renderer_properties; typedef struct { unsigned int window:1; unsigned int pbuffer:1; unsigned int accelerated:1; unsigned int color_mode:5; /* index into color_modes table */ unsigned int aux_buffers:3; unsigned int depth_bits:8; unsigned int stencil_bits:8; unsigned int accum_mode:5; /* 1 + index into color_modes table (0 means no accum buffer) */ unsigned int double_buffer:1; unsigned int stereo:1; unsigned int sample_buffers:1; unsigned int samples:5; unsigned int backing_store:1; } pixel_format; typedef union { pixel_format format; UInt64 code; } pixel_format_or_code; static pixel_format *pixel_formats; static int nb_formats, nb_displayable_formats; static void *opengl_handle; static BOOL get_renderer_property(CGLRendererInfoObj renderer_info, GLint renderer_index, CGLRendererProperty property, GLint *value) { CGLError err = CGLDescribeRenderer(renderer_info, renderer_index, property, value); if (err != kCGLNoError) WARN("CGLDescribeRenderer failed for property %d: %d %s\n", property, err, CGLErrorString(err)); return (err == kCGLNoError); } static void get_renderer_properties(CGLRendererInfoObj renderer_info, int renderer_index, renderer_properties* properties) { GLint value; memset(properties, 0, sizeof(*properties)); if (get_renderer_property(renderer_info, renderer_index, kCGLRPRendererID, &value)) properties->renderer_id = value & kCGLRendererIDMatchingMask; if (get_renderer_property(renderer_info, renderer_index, kCGLRPBufferModes, &value)) properties->buffer_modes = value; if (get_renderer_property(renderer_info, renderer_index, kCGLRPColorModes, &value)) properties->color_modes = value; if (get_renderer_property(renderer_info, renderer_index, kCGLRPAccumModes, &value)) properties->accum_modes = value; if (get_renderer_property(renderer_info, renderer_index, kCGLRPDepthModes, &value)) properties->depth_modes = value; if (get_renderer_property(renderer_info, renderer_index, kCGLRPStencilModes, &value)) properties->stencil_modes = value; if (get_renderer_property(renderer_info, renderer_index, kCGLRPMaxAuxBuffers, &value)) properties->max_aux_buffers = value; if (get_renderer_property(renderer_info, renderer_index, kCGLRPMaxSampleBuffers, &value)) properties->max_sample_buffers = value; if (get_renderer_property(renderer_info, renderer_index, kCGLRPMaxSamples, &value)) properties->max_samples = value; if (get_renderer_property(renderer_info, renderer_index, kCGLRPOffScreen, &value)) properties->offscreen = (value != 0); if (get_renderer_property(renderer_info, renderer_index, kCGLRPAccelerated, &value)) properties->accelerated = (value != 0); if (get_renderer_property(renderer_info, renderer_index, kCGLRPBackingStore, &value)) properties->backing_store = (value != 0); if (get_renderer_property(renderer_info, renderer_index, kCGLRPWindow, &value)) properties->window = (value != 0); if (get_renderer_property(renderer_info, renderer_index, kCGLRPOnline, &value)) properties->online = (value != 0); } static void dump_renderer(const renderer_properties* renderer) { int i; TRACE("Renderer ID: 0x%08x\n", renderer->renderer_id); TRACE("Buffer modes:\n"); TRACE(" Monoscopic: %s\n", (renderer->buffer_modes & kCGLMonoscopicBit) ? "YES" : "NO"); TRACE(" Stereoscopic: %s\n", (renderer->buffer_modes & kCGLStereoscopicBit) ? "YES" : "NO"); TRACE(" Single buffer: %s\n", (renderer->buffer_modes & kCGLSingleBufferBit) ? "YES" : "NO"); TRACE(" Double buffer: %s\n", (renderer->buffer_modes & kCGLDoubleBufferBit) ? "YES" : "NO"); TRACE("Color buffer modes:\n"); for (i = 0; i < sizeof(color_modes)/sizeof(color_modes[0]); i++) { if (renderer->color_modes & color_modes[i].mode) { TRACE(" Color size %d, Alpha size %d", color_modes[i].color_bits, color_modes[i].alpha_bits); if (color_modes[i].is_float) TRACE(", Float"); TRACE("\n"); } } TRACE("Accumulation buffer sizes: { "); for (i = 0; i < sizeof(color_modes)/sizeof(color_modes[0]); i++) { if (renderer->accum_modes & color_modes[i].mode) TRACE("%d, ", color_modes[i].color_bits); } TRACE("}\n"); TRACE("Depth buffer sizes: { "); for (i = 0; i < sizeof(depth_stencil_modes)/sizeof(depth_stencil_modes[0]); i++) { if (renderer->depth_modes & depth_stencil_modes[i].mode) TRACE("%d, ", depth_stencil_modes[i].bits); } TRACE("}\n"); TRACE("Stencil buffer sizes: { "); for (i = 0; i < sizeof(depth_stencil_modes)/sizeof(depth_stencil_modes[0]); i++) { if (renderer->stencil_modes & depth_stencil_modes[i].mode) TRACE("%d, ", depth_stencil_modes[i].bits); } TRACE("}\n"); TRACE("Max. Auxiliary Buffers: %d\n", renderer->max_aux_buffers); TRACE("Max. Sample Buffers: %d\n", renderer->max_sample_buffers); TRACE("Max. Samples: %d\n", renderer->max_samples); TRACE("Offscreen: %s\n", renderer->offscreen ? "YES" : "NO"); TRACE("Accelerated: %s\n", renderer->accelerated ? "YES" : "NO"); TRACE("Backing store: %s\n", renderer->backing_store ? "YES" : "NO"); TRACE("Window: %s\n", renderer->window ? "YES" : "NO"); TRACE("Online: %s\n", renderer->online ? "YES" : "NO"); } static inline UInt64 code_for_pixel_format(const pixel_format* format) { pixel_format_or_code pfc; pfc.code = 0; pfc.format = *format; return pfc.code; } static inline pixel_format pixel_format_for_code(UInt64 code) { pixel_format_or_code pfc; pfc.code = code; return pfc.format; } static const char *debugstr_pf(const pixel_format *pf) { return wine_dbg_sprintf("w/p/a %u/%u/%u col %u%s/%u dp/stn/ac/ax/b/db/str %u/%u/%u/%u/%u/%u/%u samp %u/%u %017llx", pf->window, pf->pbuffer, pf->accelerated, color_modes[pf->color_mode].color_bits, (color_modes[pf->color_mode].is_float ? "f" : ""), color_modes[pf->color_mode].alpha_bits, pf->depth_bits, pf->stencil_bits, color_modes[pf->accum_mode - 1].color_bits, pf->aux_buffers, pf->backing_store, pf->double_buffer, pf->stereo, pf->sample_buffers, pf->samples, code_for_pixel_format(pf)); } static unsigned int best_color_mode(GLint modes, GLint color_size, GLint alpha_size, GLint color_float) { int best = -1; int i; for (i = 0; i < sizeof(color_modes)/sizeof(color_modes[0]); i++) { if ((modes & color_modes[i].mode) && color_modes[i].color_bits >= color_size && color_modes[i].alpha_bits >= alpha_size && !color_modes[i].is_float == !color_float) { if (best < 0) /* no existing best choice */ best = i; else if (color_modes[i].color_bits == color_size && color_modes[i].alpha_bits == alpha_size) /* candidate is exact match */ { /* prefer it over a best which isn't exact or which has a higher bpp */ if (color_modes[best].color_bits != color_size || color_modes[best].alpha_bits != alpha_size || color_modes[i].bits_per_pixel < color_modes[best].bits_per_pixel) best = i; } else if (color_modes[i].color_bits < color_modes[best].color_bits || (color_modes[i].color_bits == color_modes[best].color_bits && color_modes[i].alpha_bits < color_modes[best].alpha_bits)) /* prefer closer */ best = i; } } if (best < 0) { /* Couldn't find a match. Return first one that renderer supports. */ for (i = 0; i < sizeof(color_modes)/sizeof(color_modes[0]); i++) { if (modes & color_modes[i].mode) return i; } } return best; } static unsigned int best_accum_mode(GLint modes, GLint accum_size) { int best = -1; int i; for (i = 0; i < sizeof(color_modes)/sizeof(color_modes[0]); i++) { if ((modes & color_modes[i].mode) && color_modes[i].color_bits >= accum_size) { /* Prefer the fewest color bits, then prefer more alpha bits, then prefer more bits per pixel. */ if (best < 0) best = i; else if (color_modes[i].color_bits < color_modes[best].color_bits) best = i; else if (color_modes[i].color_bits == color_modes[best].color_bits) { if (color_modes[i].alpha_bits > color_modes[best].alpha_bits) best = i; else if (color_modes[i].alpha_bits == color_modes[best].alpha_bits && color_modes[i].bits_per_pixel > color_modes[best].bits_per_pixel) best = i; } } } if (best < 0) { /* Couldn't find a match. Return last one that renderer supports. */ for (i = sizeof(color_modes)/sizeof(color_modes[0]) - 1; i >= 0; i--) { if (modes & color_modes[i].mode) return i; } } return best; } static void enum_renderer_pixel_formats(renderer_properties renderer, CFMutableArrayRef pixel_format_array, CFMutableSetRef pixel_format_set) { CGLPixelFormatAttribute attribs[64] = { kCGLPFAMinimumPolicy, kCGLPFAClosestPolicy, kCGLPFARendererID, renderer.renderer_id, kCGLPFASingleRenderer, }; int n = 5, n_stack[16], n_stack_idx = -1; unsigned int tried_pixel_formats = 0, failed_pixel_formats = 0, dupe_pixel_formats = 0, new_pixel_formats = 0; pixel_format request; unsigned int double_buffer; unsigned int accelerated = renderer.accelerated; if (accelerated) { attribs[n++] = kCGLPFAAccelerated; attribs[n++] = kCGLPFANoRecovery; } n_stack[++n_stack_idx] = n; for (double_buffer = 0; double_buffer <= 1; double_buffer++) { unsigned int aux; n = n_stack[n_stack_idx]; if ((!double_buffer && !(renderer.buffer_modes & kCGLSingleBufferBit)) || (double_buffer && !(renderer.buffer_modes & kCGLDoubleBufferBit))) continue; if (double_buffer) attribs[n++] = kCGLPFADoubleBuffer; memset(&request, 0, sizeof(request)); request.accelerated = accelerated; request.double_buffer = double_buffer; /* Don't bother with in-between aux buffers values: either 0 or max. */ n_stack[++n_stack_idx] = n; for (aux = 0; aux <= renderer.max_aux_buffers; aux += renderer.max_aux_buffers) { unsigned int color_mode; n = n_stack[n_stack_idx]; attribs[n++] = kCGLPFAAuxBuffers; attribs[n++] = aux; request.aux_buffers = aux; n_stack[++n_stack_idx] = n; for (color_mode = 0; color_mode < sizeof(color_modes)/sizeof(color_modes[0]); color_mode++) { unsigned int depth_mode; n = n_stack[n_stack_idx]; if (!(renderer.color_modes & color_modes[color_mode].mode)) continue; attribs[n++] = kCGLPFAColorSize; attribs[n++] = color_modes[color_mode].color_bits; attribs[n++] = kCGLPFAAlphaSize; attribs[n++] = color_modes[color_mode].alpha_bits; if (color_modes[color_mode].is_float) attribs[n++] = kCGLPFAColorFloat; request.color_mode = color_mode; n_stack[++n_stack_idx] = n; for (depth_mode = 0; depth_mode < sizeof(depth_stencil_modes)/sizeof(depth_stencil_modes[0]); depth_mode++) { unsigned int stencil_mode; n = n_stack[n_stack_idx]; if (!(renderer.depth_modes & depth_stencil_modes[depth_mode].mode)) continue; attribs[n++] = kCGLPFADepthSize; attribs[n++] = depth_stencil_modes[depth_mode].bits; request.depth_bits = depth_stencil_modes[depth_mode].bits; n_stack[++n_stack_idx] = n; for (stencil_mode = 0; stencil_mode < sizeof(depth_stencil_modes)/sizeof(depth_stencil_modes[0]); stencil_mode++) { unsigned int stereo; n = n_stack[n_stack_idx]; if (!(renderer.stencil_modes & depth_stencil_modes[stencil_mode].mode)) continue; if (accelerated && depth_stencil_modes[depth_mode].bits != 24 && stencil_mode > 0) continue; attribs[n++] = kCGLPFAStencilSize; attribs[n++] = depth_stencil_modes[stencil_mode].bits; request.stencil_bits = depth_stencil_modes[stencil_mode].bits; /* FIXME: Could trim search space a bit here depending on GPU. For ATI Radeon HD 4850, kCGLRGBA16161616Bit implies stereo-capable. */ n_stack[++n_stack_idx] = n; for (stereo = 0; stereo <= 1; stereo++) { int accum_mode; n = n_stack[n_stack_idx]; if ((!stereo && !(renderer.buffer_modes & kCGLMonoscopicBit)) || (stereo && !(renderer.buffer_modes & kCGLStereoscopicBit))) continue; if (stereo) attribs[n++] = kCGLPFAStereo; request.stereo = stereo; /* Starts at -1 for a 0 accum size */ n_stack[++n_stack_idx] = n; for (accum_mode = -1; accum_mode < (int)(sizeof(color_modes)/sizeof(color_modes[0])); accum_mode++) { unsigned int target_pass; n = n_stack[n_stack_idx]; if (accum_mode >= 0) { if (!(renderer.accum_modes & color_modes[accum_mode].mode)) continue; attribs[n++] = kCGLPFAAccumSize; attribs[n++] = color_modes[accum_mode].color_bits; request.accum_mode = accum_mode + 1; } else request.accum_mode = 0; /* Targets to request are: accelerated: window OR window + pbuffer software: window + pbuffer */ n_stack[++n_stack_idx] = n; for (target_pass = 0; target_pass <= accelerated; target_pass++) { unsigned int samples, max_samples; n = n_stack[n_stack_idx]; attribs[n++] = kCGLPFAWindow; request.window = 1; if (!accelerated || target_pass > 0) { attribs[n++] = kCGLPFAPBuffer; request.pbuffer = 1; } else request.pbuffer = 0; /* FIXME: Could trim search space a bit here depending on GPU. For Nvidia GeForce 8800 GT, limited to 4 samples for color_bits >= 128. For ATI Radeon HD 4850, can't multi-sample for color_bits >= 64 or pbuffer. */ n_stack[++n_stack_idx] = n; max_samples = renderer.max_sample_buffers ? max(1, renderer.max_samples) : 1; for (samples = 1; samples <= max_samples; samples *= 2) { unsigned int backing_store, min_backing_store, max_backing_store; n = n_stack[n_stack_idx]; if (samples > 1) { attribs[n++] = kCGLPFASampleBuffers; attribs[n++] = renderer.max_sample_buffers; attribs[n++] = kCGLPFASamples; attribs[n++] = samples; request.sample_buffers = renderer.max_sample_buffers; request.samples = samples; } else request.sample_buffers = request.samples = 0; if (renderer.backing_store && double_buffer) { /* The software renderer seems to always preserve the backing store, whether we ask for it or not. So don't bother not asking for it. */ min_backing_store = accelerated ? 0 : 1; max_backing_store = 1; } else min_backing_store = max_backing_store = 0; n_stack[++n_stack_idx] = n; for (backing_store = min_backing_store; backing_store <= max_backing_store; backing_store++) { CGLPixelFormatObj pix; GLint virtualScreens; CGLError err; n = n_stack[n_stack_idx]; if (backing_store) attribs[n++] = kCGLPFABackingStore; request.backing_store = backing_store; attribs[n] = 0; err = CGLChoosePixelFormat(attribs, &pix, &virtualScreens); if (err == kCGLNoError && pix) { pixel_format pf; GLint value, color_size, alpha_size, color_float; UInt64 pf_code; CFNumberRef code_object; BOOL dupe; memset(&pf, 0, sizeof(pf)); if (CGLDescribePixelFormat(pix, 0, kCGLPFAAccelerated, &value) == kCGLNoError) pf.accelerated = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFAAuxBuffers, &value) == kCGLNoError) pf.aux_buffers = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFADepthSize, &value) == kCGLNoError) pf.depth_bits = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFADoubleBuffer, &value) == kCGLNoError) pf.double_buffer = value; if (pf.double_buffer && CGLDescribePixelFormat(pix, 0, kCGLPFABackingStore, &value) == kCGLNoError) pf.backing_store = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFAPBuffer, &value) == kCGLNoError) pf.pbuffer = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFASampleBuffers, &value) == kCGLNoError) pf.sample_buffers = value; if (pf.sample_buffers && CGLDescribePixelFormat(pix, 0, kCGLPFASamples, &value) == kCGLNoError) pf.samples = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFAStencilSize, &value) == kCGLNoError) pf.stencil_bits = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFAStereo, &value) == kCGLNoError) pf.stereo = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFAWindow, &value) == kCGLNoError) pf.window = value; if (CGLDescribePixelFormat(pix, 0, kCGLPFAColorSize, &color_size) != kCGLNoError) color_size = 0; if (CGLDescribePixelFormat(pix, 0, kCGLPFAAlphaSize, &alpha_size) != kCGLNoError) alpha_size = 0; if (CGLDescribePixelFormat(pix, 0, kCGLPFAColorFloat, &color_float) != kCGLNoError) color_float = 0; pf.color_mode = best_color_mode(renderer.color_modes, color_size, alpha_size, color_float); if (CGLDescribePixelFormat(pix, 0, kCGLPFAAccumSize, &value) == kCGLNoError && value) pf.accum_mode = best_accum_mode(renderer.accum_modes, value) + 1; CGLReleasePixelFormat(pix); pf_code = code_for_pixel_format(&pf); code_object = CFNumberCreate(NULL, kCFNumberSInt64Type, &pf_code); if ((dupe = CFSetContainsValue(pixel_format_set, code_object))) dupe_pixel_formats++; else { CFSetAddValue(pixel_format_set, code_object); CFArrayAppendValue(pixel_format_array, code_object); new_pixel_formats++; } CFRelease(code_object); if (pf_code == code_for_pixel_format(&request)) TRACE("%s%s\n", debugstr_pf(&pf), dupe ? " (duplicate)" : ""); else { TRACE("%s remapped from %s%s\n", debugstr_pf(&pf), debugstr_pf(&request), dupe ? " (duplicate)" : ""); } } else { failed_pixel_formats++; TRACE("%s failed request err %d %s\n", debugstr_pf(&request), err, err ? CGLErrorString(err) : ""); } tried_pixel_formats++; } n_stack_idx--; } n_stack_idx--; } n_stack_idx--; } n_stack_idx--; } n_stack_idx--; } n_stack_idx--; } n_stack_idx--; } n_stack_idx--; } n_stack_idx--; } n_stack_idx--; TRACE("Number of pixel format attribute combinations: %u\n", tried_pixel_formats); TRACE(" Number which failed to choose a pixel format: %u\n", failed_pixel_formats); TRACE(" Number which chose redundant pixel formats: %u\n", dupe_pixel_formats); TRACE("Number of new pixel formats for this renderer: %u\n", new_pixel_formats); } /* The docs for WGL_ARB_pixel_format say: Indices are assigned to pixel formats in the following order: 1. Accelerated pixel formats that are displayable 2. Accelerated pixel formats that are displayable and which have extended attributes 3. Generic pixel formats 4. Accelerated pixel formats that are non displayable */ static int pixel_format_category(pixel_format pf) { /* non-displayable */ if (!pf.window) return 4; /* non-accelerated a.k.a. software a.k.a. generic */ if (!pf.accelerated) return 3; /* extended attributes that can't be represented in PIXELFORMATDESCRIPTOR */ if (color_modes[pf.color_mode].is_float) return 2; /* accelerated, displayable, no extended attributes */ return 1; } static CFComparisonResult pixel_format_comparator(const void *val1, const void *val2, void *context) { CFNumberRef number1 = val1; CFNumberRef number2 = val2; UInt64 code1, code2; pixel_format pf1, pf2; int category1, category2; CFNumberGetValue(number1, kCFNumberLongLongType, &code1); CFNumberGetValue(number2, kCFNumberLongLongType, &code2); pf1 = pixel_format_for_code(code1); pf2 = pixel_format_for_code(code2); category1 = pixel_format_category(pf1); category2 = pixel_format_category(pf2); if (category1 < category2) return kCFCompareLessThan; if (category1 > category2) return kCFCompareGreaterThan; /* Within a category, sort the "best" formats toward the front since that's what wglChoosePixelFormatARB() has to do. The ordering implemented here matches at least one Windows 7 machine's behavior. */ /* Accelerated before unaccelerated. */ if (pf1.accelerated && !pf2.accelerated) return kCFCompareLessThan; if (!pf1.accelerated && pf2.accelerated) return kCFCompareGreaterThan; /* Integer color modes before floating-point. */ if (!color_modes[pf1.color_mode].is_float && color_modes[pf2.color_mode].is_float) return kCFCompareLessThan; if (color_modes[pf1.color_mode].is_float && !color_modes[pf2.color_mode].is_float) return kCFCompareGreaterThan; /* For integer color modes, higher color bits before lower. For floating-point mode, the reverse. */ if (color_modes[pf1.color_mode].color_bits - color_modes[pf1.color_mode].alpha_bits > color_modes[pf2.color_mode].color_bits - color_modes[pf2.color_mode].alpha_bits) return color_modes[pf1.color_mode].is_float ? kCFCompareGreaterThan : kCFCompareLessThan; if (color_modes[pf1.color_mode].color_bits - color_modes[pf1.color_mode].alpha_bits < color_modes[pf2.color_mode].color_bits - color_modes[pf2.color_mode].alpha_bits) return color_modes[pf1.color_mode].is_float ? kCFCompareLessThan : kCFCompareGreaterThan; /* Mac-ism: in the rare case that color bits are equal but bpp are not, prefer fewer bpp. */ if (color_modes[pf1.color_mode].bits_per_pixel < color_modes[pf2.color_mode].bits_per_pixel) return kCFCompareLessThan; if (color_modes[pf1.color_mode].bits_per_pixel > color_modes[pf2.color_mode].bits_per_pixel) return kCFCompareGreaterThan; /* Non-pbuffer-capable before pbuffer-capable. */ if (!pf1.pbuffer && pf2.pbuffer) return kCFCompareLessThan; if (pf1.pbuffer && !pf2.pbuffer) return kCFCompareGreaterThan; /* Fewer samples before more samples. */ if (pf1.samples < pf2.samples) return kCFCompareLessThan; if (pf1.samples > pf2.samples) return kCFCompareGreaterThan; /* Monoscopic before stereoscopic. (This is a guess.) */ if (!pf1.stereo && pf2.stereo) return kCFCompareLessThan; if (pf1.stereo && !pf2.stereo) return kCFCompareGreaterThan; /* Single buffered before double buffered. */ if (!pf1.double_buffer && pf2.double_buffer) return kCFCompareLessThan; if (pf1.double_buffer && !pf2.double_buffer) return kCFCompareGreaterThan; /* Possibly-optimized double buffering before backing-store-preserving double buffering. */ if (!pf1.backing_store && pf2.backing_store) return kCFCompareLessThan; if (pf1.backing_store && !pf2.backing_store) return kCFCompareGreaterThan; /* Bigger depth buffer before smaller depth buffer. */ if (pf1.depth_bits > pf2.depth_bits) return kCFCompareLessThan; if (pf1.depth_bits < pf2.depth_bits) return kCFCompareGreaterThan; /* Smaller stencil buffer before bigger stencil buffer. */ if (pf1.stencil_bits < pf2.stencil_bits) return kCFCompareLessThan; if (pf1.stencil_bits > pf2.stencil_bits) return kCFCompareGreaterThan; /* Smaller alpha bits before larger alpha bits. */ if (color_modes[pf1.color_mode].alpha_bits < color_modes[pf2.color_mode].alpha_bits) return kCFCompareLessThan; if (color_modes[pf1.color_mode].alpha_bits > color_modes[pf2.color_mode].alpha_bits) return kCFCompareGreaterThan; /* Smaller accum buffer before larger accum buffer. (This is a guess.) */ if (pf1.accum_mode) { if (pf2.accum_mode) { if (color_modes[pf1.accum_mode - 1].color_bits - color_modes[pf1.accum_mode - 1].alpha_bits < color_modes[pf2.accum_mode - 1].color_bits - color_modes[pf2.accum_mode - 1].alpha_bits) return kCFCompareLessThan; if (color_modes[pf1.accum_mode - 1].color_bits - color_modes[pf1.accum_mode - 1].alpha_bits > color_modes[pf2.accum_mode - 1].color_bits - color_modes[pf2.accum_mode - 1].alpha_bits) return kCFCompareGreaterThan; if (color_modes[pf1.accum_mode - 1].bits_per_pixel < color_modes[pf2.accum_mode - 1].bits_per_pixel) return kCFCompareLessThan; if (color_modes[pf1.accum_mode - 1].bits_per_pixel > color_modes[pf2.accum_mode - 1].bits_per_pixel) return kCFCompareGreaterThan; if (color_modes[pf1.accum_mode - 1].alpha_bits < color_modes[pf2.accum_mode - 1].alpha_bits) return kCFCompareLessThan; if (color_modes[pf1.accum_mode - 1].alpha_bits > color_modes[pf2.accum_mode - 1].alpha_bits) return kCFCompareGreaterThan; } else return kCFCompareGreaterThan; } else if (pf2.accum_mode) return kCFCompareLessThan; /* Fewer auxiliary buffers before more auxiliary buffers. (This is a guess.) */ if (pf1.aux_buffers < pf2.aux_buffers) return kCFCompareLessThan; if (pf1.aux_buffers > pf2.aux_buffers) return kCFCompareGreaterThan; /* If we get here, arbitrarily sort based on code. */ if (code1 < code2) return kCFCompareLessThan; if (code1 > code2) return kCFCompareGreaterThan; return kCFCompareEqualTo; } static BOOL init_pixel_formats(void) { BOOL ret = FALSE; CGLRendererInfoObj renderer_info; GLint rendererCount; CGLError err; CFMutableSetRef pixel_format_set; CFMutableArrayRef pixel_format_array; int i; CFRange range; TRACE("()\n"); assert(sizeof(((pixel_format_or_code*)0)->format) <= sizeof(((pixel_format_or_code*)0)->code)); err = CGLQueryRendererInfo(CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID()), &renderer_info, &rendererCount); if (err) { WARN("CGLQueryRendererInfo failed (%d) %s\n", err, CGLErrorString(err)); return FALSE; } pixel_format_set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); if (!pixel_format_set) { WARN("CFSetCreateMutable failed\n"); CGLDestroyRendererInfo(renderer_info); return FALSE; } pixel_format_array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (!pixel_format_array) { WARN("CFArrayCreateMutable failed\n"); CFRelease(pixel_format_set); CGLDestroyRendererInfo(renderer_info); return FALSE; } for (i = 0; i < rendererCount; i++) { renderer_properties renderer; get_renderer_properties(renderer_info, i, &renderer); if (TRACE_ON(wgl)) { TRACE("renderer_properties %d:\n", i); dump_renderer(&renderer); } enum_renderer_pixel_formats(renderer, pixel_format_array, pixel_format_set); } CFRelease(pixel_format_set); CGLDestroyRendererInfo(renderer_info); range = CFRangeMake(0, CFArrayGetCount(pixel_format_array)); if (range.length) { pixel_formats = HeapAlloc(GetProcessHeap(), 0, range.length * sizeof(*pixel_formats)); if (pixel_formats) { CFArraySortValues(pixel_format_array, range, pixel_format_comparator, NULL); for (i = 0; i < range.length; i++) { CFNumberRef number = CFArrayGetValueAtIndex(pixel_format_array, i); UInt64 code; CFNumberGetValue(number, kCFNumberLongLongType, &code); pixel_formats[i] = pixel_format_for_code(code); if (pixel_formats[i].window) nb_displayable_formats++; } nb_formats = range.length; TRACE("Total number of unique pixel formats: %d\n", nb_formats); ret = TRUE; } else WARN("failed to allocate pixel format list\n"); } else WARN("got no pixel formats\n"); CFRelease(pixel_format_array); return ret; } static inline BOOL is_valid_pixel_format(int format) { return format > 0 && format <= nb_formats; } static inline BOOL is_displayable_pixel_format(int format) { return format > 0 && format <= nb_displayable_formats; } static const pixel_format *get_pixel_format(int format, BOOL allow_nondisplayable) { /* Check if the pixel format is valid. Note that it is legal to pass an invalid * format in case of probing the number of pixel formats. */ if (is_valid_pixel_format(format) && (is_displayable_pixel_format(format) || allow_nondisplayable)) { TRACE("Returning format %d\n", format); return &pixel_formats[format - 1]; } return NULL; } static BOOL init_gl_info(void) { CGDirectDisplayID display = CGMainDisplayID(); CGOpenGLDisplayMask displayMask = CGDisplayIDToOpenGLDisplayMask(display); CGLPixelFormatAttribute attribs[] = { kCGLPFADisplayMask, displayMask, 0 }; CGLPixelFormatObj pix; GLint virtualScreens; CGLError err; CGLContextObj context; CGLContextObj old_context = CGLGetCurrentContext(); const char *str; err = CGLChoosePixelFormat(attribs, &pix, &virtualScreens); if (err != kCGLNoError || !pix) { WARN("CGLChoosePixelFormat() failed with error %d %s\n", err, CGLErrorString(err)); return FALSE; } err = CGLCreateContext(pix, NULL, &context); CGLReleasePixelFormat(pix); if (err != kCGLNoError || !context) { WARN("CGLCreateContext() failed with error %d %s\n", err, CGLErrorString(err)); return FALSE; } err = CGLSetCurrentContext(context); if (err != kCGLNoError) { WARN("CGLSetCurrentContext() failed with error %d %s\n", err, CGLErrorString(err)); CGLReleaseContext(context); return FALSE; } str = (const char*)opengl_funcs.gl.p_glGetString(GL_VERSION); gl_info.glVersion = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); strcpy(gl_info.glVersion, str); str = (const char*)opengl_funcs.gl.p_glGetString(GL_EXTENSIONS); gl_info.glExtensions = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); strcpy(gl_info.glExtensions, str); opengl_funcs.gl.p_glGetIntegerv(GL_MAX_VIEWPORT_DIMS, gl_info.max_viewport_dims); TRACE("GL version : %s\n", gl_info.glVersion); TRACE("GL renderer : %s\n", opengl_funcs.gl.p_glGetString(GL_RENDERER)); CGLSetCurrentContext(old_context); CGLReleaseContext(context); return TRUE; } static BOOL get_gl_view_window_rect(struct macdrv_win_data *data, macdrv_window *window, RECT *rect) { BOOL ret = TRUE; *rect = data->client_rect; if (data->cocoa_window) { if (window) *window = data->cocoa_window; OffsetRect(rect, -data->whole_rect.left, -data->whole_rect.top); } else { HWND top = GetAncestor(data->hwnd, GA_ROOT); HWND parent = GetAncestor(data->hwnd, GA_PARENT); struct macdrv_win_data *top_data = get_win_data(top); if (top_data && top_data->cocoa_window) { if (window) *window = top_data->cocoa_window; MapWindowPoints(parent, 0, (POINT*)rect, 2); OffsetRect(rect, -top_data->whole_rect.left, -top_data->whole_rect.top); } else ret = FALSE; release_win_data(top_data); } return ret; } /*********************************************************************** * set_win_format */ static BOOL set_win_format(struct macdrv_win_data *data, int format) { macdrv_window cocoa_window; TRACE("hwnd %p format %d\n", data->hwnd, format); if (!get_gl_view_window_rect(data, &cocoa_window, &data->gl_rect)) { ERR("no top-level parent with Cocoa window in this process\n"); return FALSE; } if (data->gl_view) macdrv_dispose_view(data->gl_view); data->gl_view = macdrv_create_view(cocoa_window, cgrect_from_rect(data->gl_rect)); if (!data->gl_view) { WARN("failed to create GL view for window %p rect %s\n", cocoa_window, wine_dbgstr_rect(&data->gl_rect)); return FALSE; } TRACE("created GL view %p in window %p at %s\n", data->gl_view, cocoa_window, wine_dbgstr_rect(&data->gl_rect)); data->pixel_format = format; return TRUE; } /********************************************************************** * set_pixel_format * * Implementation of wglSetPixelFormat and wglSetPixelFormatWINE. */ static BOOL set_pixel_format(HDC hdc, int fmt, BOOL allow_reset) { struct macdrv_win_data *data; const pixel_format *pf; HWND hwnd = WindowFromDC(hdc); BOOL ret = FALSE; TRACE("hdc %p format %d\n", hdc, fmt); if (!hwnd || hwnd == GetDesktopWindow()) { WARN("not a proper window DC %p/%p\n", hdc, hwnd); return FALSE; } if (!(data = get_win_data(hwnd))) { FIXME("DC for window %p of other process: not implemented\n", hwnd); return FALSE; } if (!allow_reset && data->pixel_format) /* cannot change it if already set */ { ret = (data->pixel_format == fmt); goto done; } /* Check if fmt is in our list of supported formats to see if it is supported. */ pf = get_pixel_format(fmt, FALSE /* non-displayable */); if (!pf) { ERR("Invalid pixel format: %d\n", fmt); goto done; } if (!pf->window) { WARN("Pixel format %d is not compatible for window rendering\n", fmt); goto done; } if (!set_win_format(data, fmt)) { WARN("Couldn't set format of the window, returning failure\n"); goto done; } TRACE("pixel format:\n"); TRACE(" window: %u\n", (unsigned int)pf->window); TRACE(" pBuffer: %u\n", (unsigned int)pf->pbuffer); TRACE(" accelerated: %u\n", (unsigned int)pf->accelerated); TRACE(" color bits: %u%s\n", (unsigned int)color_modes[pf->color_mode].color_bits, (color_modes[pf->color_mode].is_float ? " float" : "")); TRACE(" alpha bits: %u\n", (unsigned int)color_modes[pf->color_mode].alpha_bits); TRACE(" aux buffers: %u\n", (unsigned int)pf->aux_buffers); TRACE(" depth bits: %u\n", (unsigned int)pf->depth_bits); TRACE(" stencil bits: %u\n", (unsigned int)pf->stencil_bits); TRACE(" accum bits: %u\n", (unsigned int)pf->accum_mode ? color_modes[pf->accum_mode - 1].color_bits : 0); TRACE(" double_buffer: %u\n", (unsigned int)pf->double_buffer); TRACE(" stereo: %u\n", (unsigned int)pf->stereo); TRACE(" sample_buffers: %u\n", (unsigned int)pf->sample_buffers); TRACE(" samples: %u\n", (unsigned int)pf->samples); TRACE(" backing_store: %u\n", (unsigned int)pf->backing_store); ret = TRUE; done: release_win_data(data); if (ret) __wine_set_pixel_format(hwnd, fmt); return ret; } /********************************************************************** * set_gl_view_parent */ void set_gl_view_parent(HWND hwnd, HWND parent) { struct macdrv_win_data *data; if (!(data = get_win_data(hwnd))) return; if (data->gl_view) { macdrv_window cocoa_window; TRACE("moving GL view %p to parent %p\n", data->gl_view, parent); if (!get_gl_view_window_rect(data, &cocoa_window, &data->gl_rect)) { ERR("no top-level parent with Cocoa window in this process\n"); macdrv_dispose_view(data->gl_view); data->gl_view = NULL; release_win_data(data); __wine_set_pixel_format( hwnd, 0 ); return; } macdrv_set_view_window_and_frame(data->gl_view, cocoa_window, cgrect_from_rect(data->gl_rect)); } release_win_data(data); } /********************************************************************** * make_context_current */ static void make_context_current(struct wgl_context *context, BOOL read) { macdrv_view view; struct wgl_pbuffer *pbuffer; if (read) { view = context->read_view; pbuffer = context->read_pbuffer; } else { view = context->draw_view; pbuffer = context->draw_pbuffer; } if (view || !pbuffer) macdrv_make_context_current(context->context, view); else { CGLSetPBuffer(context->cglcontext, pbuffer->pbuffer, pbuffer->face, pbuffer->level, 0); CGLSetCurrentContext(context->cglcontext); } } /********************************************************************** * macdrv_glCopyColorTable * * Hook into glCopyColorTable as part of the implementation of * wglMakeContextCurrentARB. If the context has a separate readable, * temporarily make that current, do glCopyColorTable, and then set it * back to the drawable. This is modeled after what Mesa GLX's Apple * implementation does. */ static void macdrv_glCopyColorTable(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) { struct wgl_context *context = NtCurrentTeb()->glContext; if (context->read_view || context->read_pbuffer) make_context_current(context, TRUE); pglCopyColorTable(target, internalformat, x, y, width); if (context->read_view || context->read_pbuffer) make_context_current(context, FALSE); } /********************************************************************** * macdrv_glCopyPixels * * Hook into glCopyPixels as part of the implementation of * wglMakeContextCurrentARB. If the context has a separate readable, * temporarily make that current, do glCopyPixels, and then set it back * to the drawable. This is modeled after what Mesa GLX's Apple * implementation does. */ static void macdrv_glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) { struct wgl_context *context = NtCurrentTeb()->glContext; if (context->read_view || context->read_pbuffer) make_context_current(context, TRUE); pglCopyPixels(x, y, width, height, type); if (context->read_view || context->read_pbuffer) make_context_current(context, FALSE); } /********************************************************************** * macdrv_glReadPixels * * Hook into glReadPixels as part of the implementation of * wglMakeContextCurrentARB. If the context has a separate readable, * temporarily make that current, do glReadPixels, and then set it back * to the drawable. This is modeled after what Mesa GLX's Apple * implementation does. */ static void macdrv_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) { struct wgl_context *context = NtCurrentTeb()->glContext; if (context->read_view || context->read_pbuffer) make_context_current(context, TRUE); pglReadPixels(x, y, width, height, format, type, pixels); if (context->read_view || context->read_pbuffer) make_context_current(context, FALSE); } /********************************************************************** * macdrv_glViewport * * Hook into glViewport as an opportunity to update the OpenGL context * if necessary. This is modeled after what Mesa GLX's Apple * implementation does. */ static void macdrv_glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { struct wgl_context *context = NtCurrentTeb()->glContext; macdrv_update_opengl_context(context->context); pglViewport(x, y, width, height); } /*********************************************************************** * macdrv_wglBindTexImageARB * * WGL_ARB_render_texture: wglBindTexImageARB */ static BOOL macdrv_wglBindTexImageARB(struct wgl_pbuffer *pbuffer, int iBuffer) { struct wgl_context *context = NtCurrentTeb()->glContext; GLenum source; CGLError err; TRACE("pbuffer %p iBuffer 0x%x\n", pbuffer, iBuffer); if (pbuffer->no_texture) { SetLastError(ERROR_INVALID_OPERATION); return GL_FALSE; } if (!context->draw_view && context->draw_pbuffer == pbuffer) opengl_funcs.gl.p_glFlush(); switch (iBuffer) { case WGL_FRONT_LEFT_ARB: if (pixel_formats[pbuffer->format].stereo) source = GL_FRONT_LEFT; else source = GL_FRONT; break; case WGL_FRONT_RIGHT_ARB: source = GL_FRONT_RIGHT; break; case WGL_BACK_LEFT_ARB: if (pixel_formats[pbuffer->format].stereo) source = GL_BACK_LEFT; else source = GL_BACK; break; case WGL_BACK_RIGHT_ARB: source = GL_BACK_RIGHT; break; case WGL_AUX0_ARB: source = GL_AUX0; break; case WGL_AUX1_ARB: source = GL_AUX1; break; case WGL_AUX2_ARB: source = GL_AUX2; break; case WGL_AUX3_ARB: source = GL_AUX3; break; case WGL_AUX4_ARB: case WGL_AUX5_ARB: case WGL_AUX6_ARB: case WGL_AUX7_ARB: case WGL_AUX8_ARB: case WGL_AUX9_ARB: FIXME("unsupported source buffer 0x%x\n", iBuffer); SetLastError(ERROR_INVALID_DATA); return GL_FALSE; default: WARN("unknown source buffer 0x%x\n", iBuffer); SetLastError(ERROR_INVALID_DATA); return GL_FALSE; } err = CGLTexImagePBuffer(context->cglcontext, pbuffer->pbuffer, source); if (err != kCGLNoError) { WARN("CGLTexImagePBuffer failed with err %d %s\n", err, CGLErrorString(err)); SetLastError(ERROR_INVALID_OPERATION); return GL_FALSE; } return GL_TRUE; } /*********************************************************************** * macdrv_wglChoosePixelFormatARB * * WGL_ARB_pixel_format: wglChoosePixelFormatARB */ static BOOL macdrv_wglChoosePixelFormatARB(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) { pixel_format pf, valid; const int *iptr; int color_bits, red_bits, green_bits, blue_bits, alpha_bits; int accum_bits, accum_red_bits, accum_green_bits, accum_blue_bits, accum_alpha_bits; int float_color; BOOL srgb; int i, found = 0; TRACE("hdc %p piAttribIList %p pfAttribFList %p nMaxFormats %u piFormats %p nNumFormats %p\n", hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); if (pfAttribFList) FIXME("unused pfAttribFList\n"); memset(&pf, 0, sizeof(pf)); memset(&valid, 0, sizeof(valid)); color_bits = red_bits = green_bits = blue_bits = alpha_bits = 0; accum_bits = accum_red_bits = accum_green_bits = accum_blue_bits = accum_alpha_bits = 0; float_color = -1; srgb = FALSE; for (iptr = piAttribIList; iptr && *iptr; iptr += 2) { int attr = iptr[0]; int value = iptr[1]; switch (attr) { case WGL_DRAW_TO_WINDOW_ARB: if (valid.window && (!pf.window != !value)) goto cant_match; pf.window = (value != 0); valid.window = 1; break; case WGL_DRAW_TO_BITMAP_ARB: goto cant_match; case WGL_ACCELERATION_ARB: if (value == WGL_FULL_ACCELERATION_ARB) value = 1; else if (value == WGL_NO_ACCELERATION_ARB) value = 0; else goto cant_match; if (valid.accelerated && pf.accelerated != value) goto cant_match; pf.accelerated = value; valid.accelerated = 1; break; case WGL_NEED_PALETTE_ARB: case WGL_NEED_SYSTEM_PALETTE_ARB: case WGL_SWAP_LAYER_BUFFERS_ARB: if (value) goto cant_match; break; case WGL_SWAP_METHOD_ARB: if (value == WGL_SWAP_COPY_ARB) value = 1; else if (value == WGL_SWAP_UNDEFINED_ARB) value = 0; else goto cant_match; if (valid.backing_store && pf.backing_store != value) goto cant_match; if (valid.double_buffer && !pf.double_buffer && value) goto cant_match; pf.backing_store = value; valid.backing_store = 1; break; case WGL_NUMBER_OVERLAYS_ARB: case WGL_NUMBER_UNDERLAYS_ARB: if (value) goto cant_match; break; case WGL_SHARE_DEPTH_ARB: case WGL_SHARE_STENCIL_ARB: case WGL_SHARE_ACCUM_ARB: /* no effect */ break; case WGL_SUPPORT_GDI_ARB: if (value) goto cant_match; break; case WGL_SUPPORT_OPENGL_ARB: if (!value) goto cant_match; break; case WGL_DOUBLE_BUFFER_ARB: if (valid.double_buffer && (!pf.double_buffer != !value)) goto cant_match; pf.double_buffer = (value != 0); valid.double_buffer = 1; if (valid.backing_store && pf.backing_store && !pf.double_buffer) goto cant_match; break; case WGL_STEREO_ARB: if (valid.stereo && (!pf.stereo != !value)) goto cant_match; pf.stereo = (value != 0); valid.stereo = 1; break; case WGL_PIXEL_TYPE_ARB: if (value == WGL_TYPE_RGBA_FLOAT_ARB) value = 1; else if (value == WGL_TYPE_RGBA_ARB) value = 0; else { /* Mac contexts don't support rendering to unsigned floating point formats, even if GL_EXT_packed_float is supported. So, WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT is not supported. */ goto cant_match; } if (float_color != -1 && float_color != value) goto cant_match; if (srgb && value) goto cant_match; float_color = value; break; case WGL_COLOR_BITS_ARB: if (color_bits < value) color_bits = value; break; case WGL_RED_BITS_ARB: if (srgb && value > 8) goto cant_match; if (red_bits < value) red_bits = value; break; case WGL_GREEN_BITS_ARB: if (srgb && value > 8) goto cant_match; if (green_bits < value) green_bits = value; break; case WGL_BLUE_BITS_ARB: if (srgb && value > 8) goto cant_match; if (blue_bits < value) blue_bits = value; break; case WGL_ALPHA_BITS_ARB: if (alpha_bits < value) alpha_bits = value; break; case WGL_ACCUM_BITS_ARB: if (accum_bits < value) accum_bits = value; break; case WGL_ACCUM_RED_BITS_ARB: if (accum_red_bits < value) accum_red_bits = value; break; case WGL_ACCUM_GREEN_BITS_ARB: if (accum_green_bits < value) accum_green_bits = value; break; case WGL_ACCUM_BLUE_BITS_ARB: if (accum_blue_bits < value) accum_blue_bits = value; break; case WGL_ACCUM_ALPHA_BITS_ARB: if (accum_alpha_bits < value) accum_alpha_bits = value; break; case WGL_DEPTH_BITS_ARB: if (value > 255) goto cant_match; if (pf.depth_bits < value) pf.depth_bits = value; break; case WGL_STENCIL_BITS_ARB: if (value > 255) goto cant_match; if (pf.stencil_bits < value) pf.stencil_bits = value; break; case WGL_AUX_BUFFERS_ARB: if (value > 7) goto cant_match; if (pf.aux_buffers < value) pf.aux_buffers = value; break; case WGL_SAMPLE_BUFFERS_ARB: if (value > 1) goto cant_match; if (pf.sample_buffers < value) pf.sample_buffers = value; break; case WGL_SAMPLES_ARB: if (value > 31) goto cant_match; if (pf.samples < value) pf.samples = value; break; case WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB: /* a.k.a. WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT */ /* sRGB is only supported for 8-bit integer color components */ if (float_color >= 1 || red_bits > 8 || green_bits > 8 || blue_bits > 8) goto cant_match; srgb = TRUE; break; case WGL_NUMBER_PIXEL_FORMATS_ARB: case WGL_RED_SHIFT_ARB: case WGL_GREEN_SHIFT_ARB: case WGL_BLUE_SHIFT_ARB: case WGL_ALPHA_SHIFT_ARB: case WGL_TRANSPARENT_ARB: case WGL_TRANSPARENT_RED_VALUE_ARB: case WGL_TRANSPARENT_GREEN_VALUE_ARB: case WGL_TRANSPARENT_BLUE_VALUE_ARB: case WGL_TRANSPARENT_ALPHA_VALUE_ARB: case WGL_TRANSPARENT_INDEX_VALUE_ARB: /* ignored */ break; case WGL_DRAW_TO_PBUFFER_ARB: case WGL_BIND_TO_TEXTURE_RGB_ARB: case WGL_BIND_TO_TEXTURE_RGBA_ARB: case WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV: case WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV: if (valid.pbuffer && (!pf.pbuffer != !value)) goto cant_match; pf.pbuffer = (value != 0); valid.pbuffer = 1; if ((attr == WGL_BIND_TO_TEXTURE_RGBA_ARB || attr == WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV) && !alpha_bits) alpha_bits = 1; break; default: WARN("invalid attribute %x\n", iptr[0]); return GL_FALSE; } } for (i = 0; i < nb_formats && found < nMaxFormats; i++) { const struct color_mode *mode; if (valid.window && pixel_formats[i].window != pf.window) continue; if (valid.pbuffer && pixel_formats[i].pbuffer != pf.pbuffer) continue; if (valid.accelerated && pixel_formats[i].accelerated != pf.accelerated) continue; if (valid.double_buffer && pixel_formats[i].double_buffer != pf.double_buffer) continue; if (valid.stereo && pixel_formats[i].stereo != pf.stereo) continue; if (valid.backing_store && pixel_formats[i].backing_store != pf.backing_store) continue; if (pixel_formats[i].aux_buffers < pf.aux_buffers) continue; if (pixel_formats[i].depth_bits < pf.depth_bits) continue; if (pixel_formats[i].stencil_bits < pf.stencil_bits) continue; if (pixel_formats[i].sample_buffers < pf.sample_buffers) continue; if (pixel_formats[i].samples < pf.samples) continue; mode = &color_modes[pixel_formats[i].color_mode]; /* If the mode doesn't have alpha, check requested color bits against bits per pixel instead of the mode's color bits. On Windows, color bits sometimes exceeds r+g+b (e.g. it's 32 for an R8G8B8A0 pixel format). If an app depends on that and requests WGL_COLOR_BITS_ARB == 32 and expects that to match such a pixel format, we need to accomodate that. */ if (mode->alpha_bits) { if (mode->color_bits < color_bits) continue; } else { if (mode->bits_per_pixel < color_bits) continue; } if (mode->red_bits < red_bits || mode->green_bits < green_bits || mode->blue_bits < blue_bits || mode->alpha_bits < alpha_bits) continue; if (float_color != -1 && (!mode->is_float != !float_color)) continue; if (srgb && (mode->red_bits != 8 || mode->green_bits != 8 || mode->blue_bits != 8 || mode->is_float)) continue; if (pixel_formats[i].accum_mode) { mode = &color_modes[pixel_formats[i].accum_mode - 1]; if (mode->color_bits < accum_bits || mode->red_bits < accum_red_bits || mode->green_bits < accum_green_bits || mode->blue_bits < accum_blue_bits || mode->alpha_bits < accum_alpha_bits) continue; } else if (accum_bits || accum_red_bits || accum_green_bits || accum_blue_bits || accum_alpha_bits) continue; piFormats[found++] = i; } cant_match: *nNumFormats = found; return TRUE; } /********************************************************************** * macdrv_wglCreatePbufferARB * * WGL_ARB_pbuffer: wglCreatePbufferARB */ static struct wgl_pbuffer *macdrv_wglCreatePbufferARB(HDC hdc, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) { struct wgl_pbuffer* pbuffer; GLenum target = 0; GLenum internalFormat = 0; CGLError err; TRACE("hdc %p iPixelFormat %d iWidth %d iHeight %d piAttribList %p\n", hdc, iPixelFormat, iWidth, iHeight, piAttribList); if (!is_valid_pixel_format(iPixelFormat) || !pixel_formats[iPixelFormat].pbuffer) { WARN("invalid pixel format %d\n", iPixelFormat); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return NULL; } pbuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pbuffer)); pbuffer->format = iPixelFormat; for ( ; piAttribList && *piAttribList; piAttribList += 2) { int attr = piAttribList[0]; int value = piAttribList[1]; switch (attr) { case WGL_PBUFFER_LARGEST_ARB: FIXME("WGL_PBUFFER_LARGEST_ARB: %d; ignoring\n", value); break; case WGL_TEXTURE_FORMAT_ARB: switch (value) { case WGL_TEXTURE_RGBA_ARB: TRACE("WGL_TEXTURE_FORMAT_ARB: WGL_TEXTURE_RGBA_ARB\n"); internalFormat = GL_RGBA; break; case WGL_TEXTURE_RGB_ARB: TRACE("WGL_TEXTURE_FORMAT_ARB: WGL_TEXTURE_RGB_ARB\n"); internalFormat = GL_RGB; break; case WGL_NO_TEXTURE_ARB: TRACE("WGL_TEXTURE_FORMAT_ARB: WGL_NO_TEXTURE_ARB\n"); internalFormat = 0; break; default: WARN("unknown WGL_TEXTURE_FORMAT_ARB value 0x%x\n", value); SetLastError(ERROR_INVALID_DATA); goto done; } break; case WGL_TEXTURE_TARGET_ARB: pbuffer->face = 0; switch (value) { case WGL_NO_TEXTURE_ARB: TRACE("WGL_TEXTURE_TARGET_ARB: WGL_NO_TEXTURE_ARB\n"); target = 0; break; case WGL_TEXTURE_CUBE_MAP_ARB: TRACE("WGL_TEXTURE_TARGET_ARB: WGL_TEXTURE_CUBE_MAP_ARB\n"); target = GL_TEXTURE_CUBE_MAP; pbuffer->face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; break; case WGL_TEXTURE_1D_ARB: FIXME("WGL_TEXTURE_TARGET_ARB: WGL_TEXTURE_1D_ARB; not supported\n"); SetLastError(ERROR_NO_SYSTEM_RESOURCES); goto done; case WGL_TEXTURE_2D_ARB: TRACE("WGL_TEXTURE_TARGET_ARB: WGL_TEXTURE_2D_ARB\n"); target = GL_TEXTURE_2D; break; case WGL_TEXTURE_RECTANGLE_NV: TRACE("WGL_TEXTURE_TARGET_ARB: WGL_TEXTURE_RECTANGLE_NV\n"); target = GL_TEXTURE_RECTANGLE; break; default: WARN("unknown WGL_TEXTURE_TARGET_ARB value 0x%x\n", value); SetLastError(ERROR_INVALID_DATA); goto done; } break; case WGL_MIPMAP_TEXTURE_ARB: TRACE("WGL_MIPMAP_TEXTURE_ARB: %d\n", value); pbuffer->max_level = 0; if (value) { int size = min(iWidth, iHeight) / 2; while (size) { pbuffer->max_level++; size /= 2; } } break; default: WARN("unknown attribute 0x%x\n", attr); SetLastError(ERROR_INVALID_DATA); goto done; } } if (!target || !internalFormat) { pbuffer->no_texture = TRUE; /* no actual way to turn off ability to texture; use most permissive target */ target = GL_TEXTURE_RECTANGLE; internalFormat = GL_RGB; } err = CGLCreatePBuffer(iWidth, iHeight, target, internalFormat, pbuffer->max_level, &pbuffer->pbuffer); if (err != kCGLNoError) { WARN("CGLCreatePBuffer failed; err %d %s\n", err, CGLErrorString(err)); pbuffer->pbuffer = NULL; if (err == kCGLBadAlloc) SetLastError(ERROR_NO_SYSTEM_RESOURCES); else SetLastError(ERROR_INVALID_DATA); } done: if (!pbuffer->pbuffer) { HeapFree(GetProcessHeap(), 0, pbuffer); return NULL; } TRACE(" -> %p\n", pbuffer); return pbuffer; } /********************************************************************** * macdrv_wglDestroyPbufferARB * * WGL_ARB_pbuffer: wglDestroyPbufferARB */ static BOOL macdrv_wglDestroyPbufferARB(struct wgl_pbuffer *pbuffer) { TRACE("pbuffer %p\n", pbuffer); if (pbuffer && pbuffer->pbuffer) CGLReleasePBuffer(pbuffer->pbuffer); HeapFree(GetProcessHeap(), 0, pbuffer); return GL_TRUE; } /********************************************************************** * macdrv_wglGetExtensionsStringARB * * WGL_ARB_extensions_string: wglGetExtensionsStringARB */ static const GLubyte *macdrv_wglGetExtensionsStringARB(HDC hdc) { /* FIXME: Since we're given an HDC, this should be device-specific. I.e. this can be specific to the CGL renderer like we're supposed to do. */ TRACE("returning \"%s\"\n", gl_info.wglExtensions); return (const GLubyte*)gl_info.wglExtensions; } /********************************************************************** * macdrv_wglGetExtensionsStringEXT * * WGL_EXT_extensions_string: wglGetExtensionsStringEXT */ static const GLubyte *macdrv_wglGetExtensionsStringEXT(void) { TRACE("returning \"%s\"\n", gl_info.wglExtensions); return (const GLubyte*)gl_info.wglExtensions; } /********************************************************************** * macdrv_wglGetPbufferDCARB * * WGL_ARB_pbuffer: wglGetPbufferDCARB */ static HDC macdrv_wglGetPbufferDCARB(struct wgl_pbuffer *pbuffer) { HDC hdc; struct wgl_pbuffer *prev; hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); if (!hdc) return 0; EnterCriticalSection(&dc_pbuffers_section); prev = (struct wgl_pbuffer*)CFDictionaryGetValue(dc_pbuffers, hdc); if (prev) { CGLReleasePBuffer(prev->pbuffer); HeapFree(GetProcessHeap(), 0, prev); } CFDictionarySetValue(dc_pbuffers, hdc, pbuffer); LeaveCriticalSection(&dc_pbuffers_section); TRACE("pbuffer %p -> hdc %p\n", pbuffer, hdc); return hdc; } /********************************************************************** * macdrv_wglGetPixelFormatAttribivARB * * WGL_ARB_pixel_format: wglGetPixelFormatAttribivARB */ static BOOL macdrv_wglGetPixelFormatAttribivARB(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues) { const pixel_format *pf; UINT i; TRACE("hdc %p iPixelFormat %d iLayerPlane %d nAttributes %u piAttributes %p piValues %p\n", hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); if (!nAttributes) return GL_TRUE; if (nAttributes == 1 && piAttributes[0] == WGL_NUMBER_PIXEL_FORMATS_ARB) { piValues[0] = nb_formats; return GL_TRUE; } pf = get_pixel_format(iPixelFormat, TRUE /* non-displayable */); if (!pf) { WARN("invalid pixel format %d\n", iPixelFormat); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return GL_FALSE; } for (i = 0; i < nAttributes; ++i) { switch (piAttributes[i]) { case WGL_NUMBER_PIXEL_FORMATS_ARB: piValues[i] = nb_formats; break; case WGL_DRAW_TO_WINDOW_ARB: piValues[i] = pf->window ? GL_TRUE : GL_FALSE; break; case WGL_DRAW_TO_BITMAP_ARB: piValues[i] = GL_FALSE; break; case WGL_ACCELERATION_ARB: if (iLayerPlane) goto invalid_layer; if (pf->accelerated) piValues[i] = WGL_FULL_ACCELERATION_ARB; else piValues[i] = WGL_NO_ACCELERATION_ARB; break; case WGL_NEED_PALETTE_ARB: case WGL_NEED_SYSTEM_PALETTE_ARB: case WGL_SWAP_LAYER_BUFFERS_ARB: piValues[i] = GL_FALSE; break; case WGL_SWAP_METHOD_ARB: if (pf->double_buffer && pf->backing_store) piValues[i] = WGL_SWAP_COPY_ARB; else piValues[i] = WGL_SWAP_UNDEFINED_ARB; break; case WGL_NUMBER_OVERLAYS_ARB: case WGL_NUMBER_UNDERLAYS_ARB: piValues[i] = 0; break; case WGL_TRANSPARENT_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = GL_FALSE; break; case WGL_TRANSPARENT_RED_VALUE_ARB: case WGL_TRANSPARENT_GREEN_VALUE_ARB: case WGL_TRANSPARENT_BLUE_VALUE_ARB: case WGL_TRANSPARENT_ALPHA_VALUE_ARB: case WGL_TRANSPARENT_INDEX_VALUE_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = 0; break; case WGL_SHARE_DEPTH_ARB: case WGL_SHARE_STENCIL_ARB: case WGL_SHARE_ACCUM_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = GL_TRUE; break; case WGL_SUPPORT_GDI_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = GL_FALSE; break; case WGL_SUPPORT_OPENGL_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = GL_TRUE; break; case WGL_DOUBLE_BUFFER_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = pf->double_buffer ? GL_TRUE : GL_FALSE; break; case WGL_STEREO_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = pf->stereo ? GL_TRUE : GL_FALSE; break; case WGL_PIXEL_TYPE_ARB: if (iLayerPlane) goto invalid_layer; if (color_modes[pf->color_mode].is_float) piValues[i] = WGL_TYPE_RGBA_FLOAT_ARB; else piValues[i] = WGL_TYPE_RGBA_ARB; /* WGL_EXT_pixel_format_packed_float may be supported, which should in theory make another pixel type available: WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT. However, Mac contexts don't support rendering to unsigned floating-point formats, even when GL_EXT_packed_float is supported. */ break; case WGL_COLOR_BITS_ARB: if (iLayerPlane) goto invalid_layer; /* If the mode doesn't have alpha, return bits per pixel instead of color bits. On Windows, color bits sometimes exceeds r+g+b (e.g. it's 32 for an R8G8B8A0 pixel format). If an app depends on that and expects that WGL_COLOR_BITS_ARB >= 32 for such a pixel format, we need to accomodate that. */ if (color_modes[pf->color_mode].alpha_bits) piValues[i] = color_modes[pf->color_mode].color_bits; else piValues[i] = color_modes[pf->color_mode].bits_per_pixel; break; case WGL_RED_BITS_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = color_modes[pf->color_mode].red_bits; break; case WGL_RED_SHIFT_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = color_modes[pf->color_mode].red_shift; break; case WGL_GREEN_BITS_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = color_modes[pf->color_mode].green_bits; break; case WGL_GREEN_SHIFT_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = color_modes[pf->color_mode].green_shift; break; case WGL_BLUE_BITS_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = color_modes[pf->color_mode].blue_bits; break; case WGL_BLUE_SHIFT_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = color_modes[pf->color_mode].blue_shift; break; case WGL_ALPHA_BITS_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = color_modes[pf->color_mode].alpha_bits; break; case WGL_ALPHA_SHIFT_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = color_modes[pf->color_mode].alpha_shift; break; case WGL_ACCUM_BITS_ARB: if (iLayerPlane) goto invalid_layer; if (pf->accum_mode) piValues[i] = color_modes[pf->accum_mode - 1].color_bits; else piValues[i] = 0; break; case WGL_ACCUM_RED_BITS_ARB: if (iLayerPlane) goto invalid_layer; if (pf->accum_mode) piValues[i] = color_modes[pf->accum_mode - 1].red_bits; else piValues[i] = 0; break; case WGL_ACCUM_GREEN_BITS_ARB: if (iLayerPlane) goto invalid_layer; if (pf->accum_mode) piValues[i] = color_modes[pf->accum_mode - 1].green_bits; else piValues[i] = 0; break; case WGL_ACCUM_BLUE_BITS_ARB: if (iLayerPlane) goto invalid_layer; if (pf->accum_mode) piValues[i] = color_modes[pf->accum_mode - 1].blue_bits; else piValues[i] = 0; break; case WGL_ACCUM_ALPHA_BITS_ARB: if (iLayerPlane) goto invalid_layer; if (pf->accum_mode) piValues[i] = color_modes[pf->accum_mode - 1].alpha_bits; else piValues[i] = 0; break; case WGL_DEPTH_BITS_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = pf->depth_bits; break; case WGL_STENCIL_BITS_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = pf->stencil_bits; break; case WGL_AUX_BUFFERS_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = pf->aux_buffers; break; case WGL_SAMPLE_BUFFERS_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = pf->sample_buffers; break; case WGL_SAMPLES_ARB: if (iLayerPlane) goto invalid_layer; piValues[i] = pf->samples; break; case WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB: /* a.k.a. WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT */ if (iLayerPlane) goto invalid_layer; /* sRGB is only supported for 8-bit integer color components */ if (color_modes[pf->color_mode].red_bits == 8 && color_modes[pf->color_mode].green_bits == 8 && color_modes[pf->color_mode].blue_bits == 8 && !color_modes[pf->color_mode].is_float) piValues[i] = GL_TRUE; else piValues[i] = GL_FALSE; break; case WGL_DRAW_TO_PBUFFER_ARB: case WGL_BIND_TO_TEXTURE_RGB_ARB: case WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV: piValues[i] = pf->pbuffer ? GL_TRUE : GL_FALSE; break; case WGL_BIND_TO_TEXTURE_RGBA_ARB: case WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV: piValues[i] = (pf->pbuffer && color_modes[pf->color_mode].alpha_bits) ? GL_TRUE : GL_FALSE; break; case WGL_MAX_PBUFFER_WIDTH_ARB: piValues[i] = gl_info.max_viewport_dims[0]; break; case WGL_MAX_PBUFFER_HEIGHT_ARB: piValues[i] = gl_info.max_viewport_dims[1]; break; case WGL_MAX_PBUFFER_PIXELS_ARB: piValues[i] = gl_info.max_viewport_dims[0] * gl_info.max_viewport_dims[1]; break; default: WARN("invalid attribute %x\n", piAttributes[i]); return GL_FALSE; } TRACE("piAttributes[%d] (%x) -> %x\n", i, piAttributes[i], piValues[i]); } return GL_TRUE; invalid_layer: FIXME("unsupported iLayerPlane %d\n", iLayerPlane); return GL_FALSE; } /********************************************************************** * macdrv_wglGetPixelFormatAttribfvARB * * WGL_ARB_pixel_format: wglGetPixelFormatAttribfvARB */ static BOOL macdrv_wglGetPixelFormatAttribfvARB(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues) { int *attr; int ret; TRACE("hdc %p iPixelFormat %d iLayerPlane %d nAttributes %u piAttributes %p pfValues %p\n", hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); /* Allocate a temporary array to store integer values */ attr = HeapAlloc(GetProcessHeap(), 0, nAttributes * sizeof(int)); if (!attr) { ERR("couldn't allocate %d array\n", nAttributes); return GL_FALSE; } /* Piggy-back on wglGetPixelFormatAttribivARB */ ret = macdrv_wglGetPixelFormatAttribivARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, attr); if (ret) { UINT i; /* Convert integer values to float. Should also check for attributes that can give decimal values here */ for (i = 0; i < nAttributes; i++) pfValues[i] = attr[i]; } HeapFree(GetProcessHeap(), 0, attr); return ret; } /********************************************************************** * macdrv_wglGetSwapIntervalEXT * * WGL_EXT_swap_control: wglGetSwapIntervalEXT */ static int macdrv_wglGetSwapIntervalEXT(void) { struct wgl_context *context = NtCurrentTeb()->glContext; long value; CGLError err; TRACE("\n"); err = CGLGetParameter(context->cglcontext, kCGLCPSwapInterval, (GLint*)&value); if (err != kCGLNoError) { WARN("CGLGetParameter(kCGLCPSwapInterval) failed; error %d %s\n", err, CGLErrorString(err)); value = 1; } return value; } /*********************************************************************** * macdrv_wglMakeContextCurrentARB * * WGL_ARB_make_current_read: wglMakeContextCurrentARB * * This is not supported directly by OpenGL on the Mac. We emulate it * by hooking into glReadPixels, glCopyPixels, and glCopyColorTable to * temporarily swap the drawable. This follows the technique used in * the implementation of Mesa GLX for Apple. */ static BOOL macdrv_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, struct wgl_context *context) { struct macdrv_win_data *data; HWND hwnd; TRACE("draw_hdc %p read_hdc %p context %p/%p/%p\n", draw_hdc, read_hdc, context, (context ? context->context : NULL), (context ? context->cglcontext : NULL)); if (!context) { macdrv_make_context_current(NULL, NULL); NtCurrentTeb()->glContext = NULL; return TRUE; } if ((hwnd = WindowFromDC(draw_hdc))) { if (!(data = get_win_data(hwnd))) { FIXME("draw DC for window %p of other process: not implemented\n", hwnd); return FALSE; } if (!data->pixel_format) { WARN("no pixel format set\n"); release_win_data(data); SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (context->format != data->pixel_format) { WARN("mismatched pixel format draw_hdc %p %u context %p %u\n", draw_hdc, data->pixel_format, context, context->format); release_win_data(data); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return FALSE; } context->draw_view = data->gl_view; context->draw_pbuffer = NULL; release_win_data(data); } else { struct wgl_pbuffer *pbuffer; EnterCriticalSection(&dc_pbuffers_section); pbuffer = (struct wgl_pbuffer*)CFDictionaryGetValue(dc_pbuffers, draw_hdc); if (pbuffer) { if (context->format != pbuffer->format) { WARN("mismatched pixel format draw_hdc %p %u context %p %u\n", draw_hdc, pbuffer->format, context, context->format); LeaveCriticalSection(&dc_pbuffers_section); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return FALSE; } } else { WARN("no window or pbuffer for DC\n"); LeaveCriticalSection(&dc_pbuffers_section); SetLastError(ERROR_INVALID_HANDLE); return FALSE; } context->draw_view = NULL; context->draw_pbuffer = pbuffer; LeaveCriticalSection(&dc_pbuffers_section); } context->read_view = NULL; context->read_pbuffer = NULL; if (read_hdc && read_hdc != draw_hdc) { if ((hwnd = WindowFromDC(read_hdc))) { if ((data = get_win_data(hwnd))) { if (data->gl_view != context->draw_view) context->read_view = data->gl_view; release_win_data(data); } } else { EnterCriticalSection(&dc_pbuffers_section); context->read_pbuffer = (struct wgl_pbuffer*)CFDictionaryGetValue(dc_pbuffers, read_hdc); LeaveCriticalSection(&dc_pbuffers_section); } } TRACE("making context current with draw_view %p draw_pbuffer %p read_view %p read_pbuffer %p format %u\n", context->draw_view, context->draw_pbuffer, context->read_view, context->read_pbuffer, context->format); make_context_current(context, FALSE); context->has_been_current = TRUE; NtCurrentTeb()->glContext = context; return TRUE; } /********************************************************************** * macdrv_wglQueryPbufferARB * * WGL_ARB_pbuffer: wglQueryPbufferARB */ static BOOL macdrv_wglQueryPbufferARB(struct wgl_pbuffer *pbuffer, int iAttribute, int *piValue) { CGLError err; GLsizei width; GLsizei height; GLenum target; GLenum internalFormat; GLint mipmap; TRACE("pbuffer %p iAttribute 0x%x piValue %p\n", pbuffer, iAttribute, piValue); err = CGLDescribePBuffer(pbuffer->pbuffer, &width, &height, &target, &internalFormat, &mipmap); if (err != kCGLNoError) { WARN("CGLDescribePBuffer failed; error %d %s\n", err, CGLErrorString(err)); SetLastError(ERROR_INVALID_HANDLE); return GL_FALSE; } switch (iAttribute) { case WGL_PBUFFER_WIDTH_ARB: *piValue = width; break; case WGL_PBUFFER_HEIGHT_ARB: *piValue = height; break; case WGL_PBUFFER_LOST_ARB: /* Mac PBuffers can't be lost */ *piValue = GL_FALSE; break; case WGL_TEXTURE_FORMAT_ARB: if (pbuffer->no_texture) *piValue = WGL_NO_TEXTURE_ARB; else switch (internalFormat) { case GL_RGBA: *piValue = WGL_TEXTURE_RGBA_ARB; break; case GL_RGB: default: *piValue = WGL_TEXTURE_RGB_ARB; break; } break; case WGL_TEXTURE_TARGET_ARB: if (pbuffer->no_texture) *piValue = WGL_NO_TEXTURE_ARB; else switch (target) { case GL_TEXTURE_CUBE_MAP: *piValue = WGL_TEXTURE_CUBE_MAP_ARB; break; case GL_TEXTURE_2D: *piValue = WGL_TEXTURE_2D_ARB; break; case GL_TEXTURE_RECTANGLE: default: *piValue = WGL_TEXTURE_RECTANGLE_NV; break; } break; case WGL_MIPMAP_TEXTURE_ARB: *piValue = (pbuffer->max_level > 0); break; case WGL_MIPMAP_LEVEL_ARB: *piValue = pbuffer->level; break; case WGL_CUBE_MAP_FACE_ARB: switch (pbuffer->face) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: default: *piValue = WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: *piValue = WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB; break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: *piValue = WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: *piValue = WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB; break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: *piValue = WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: *piValue = WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB; break; } break; default: WARN("invalid attribute 0x%x\n", iAttribute); SetLastError(ERROR_INVALID_DATA); return GL_FALSE; } return GL_TRUE; } /********************************************************************** * macdrv_wglReleasePbufferDCARB * * WGL_ARB_pbuffer: wglReleasePbufferDCARB */ static int macdrv_wglReleasePbufferDCARB(struct wgl_pbuffer *pbuffer, HDC hdc) { struct wgl_pbuffer *prev; TRACE("pbuffer %p hdc %p\n", pbuffer, hdc); EnterCriticalSection(&dc_pbuffers_section); prev = (struct wgl_pbuffer*)CFDictionaryGetValue(dc_pbuffers, hdc); if (prev) { if (prev != pbuffer) FIXME("hdc %p isn't associated with pbuffer %p\n", hdc, pbuffer); CGLReleasePBuffer(prev->pbuffer); HeapFree(GetProcessHeap(), 0, prev); CFDictionaryRemoveValue(dc_pbuffers, hdc); } else hdc = 0; LeaveCriticalSection(&dc_pbuffers_section); return hdc && DeleteDC(hdc); } /********************************************************************** * macdrv_wglReleaseTexImageARB * * WGL_ARB_render_texture: wglReleaseTexImageARB */ static BOOL macdrv_wglReleaseTexImageARB(struct wgl_pbuffer *pbuffer, int iBuffer) { struct wgl_context *context = NtCurrentTeb()->glContext; CGLError err; TRACE("pbuffer %p iBuffer 0x%x; stub!\n", pbuffer, iBuffer); if (pbuffer->no_texture) { SetLastError(ERROR_INVALID_OPERATION); return GL_FALSE; } err = CGLTexImagePBuffer(context->cglcontext, pbuffer->pbuffer, GL_NONE); if (err != kCGLNoError) { WARN("CGLTexImagePBuffer failed with err %d %s\n", err, CGLErrorString(err)); SetLastError(ERROR_INVALID_OPERATION); return GL_FALSE; } return GL_TRUE; } /********************************************************************** * macdrv_wglSetPbufferAttribARB * * WGL_ARB_render_texture: wglSetPbufferAttribARB */ static BOOL macdrv_wglSetPbufferAttribARB(struct wgl_pbuffer *pbuffer, const int *piAttribList) { struct wgl_context *context = NtCurrentTeb()->glContext; TRACE("pbuffer %p piAttribList %p\n", pbuffer, piAttribList); for ( ; piAttribList && *piAttribList; piAttribList += 2) { int attr = piAttribList[0]; int value = piAttribList[1]; switch (attr) { case WGL_MIPMAP_LEVEL_ARB: TRACE("WGL_MIPMAP_LEVEL_ARB: %d\n", value); pbuffer->level = value; break; case WGL_CUBE_MAP_FACE_ARB: switch (value) { case WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: TRACE("WGL_CUBE_MAP_FACE_ARB: WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB\n"); pbuffer->face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; break; case WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: TRACE("WGL_CUBE_MAP_FACE_ARB: WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB\n"); pbuffer->face = GL_TEXTURE_CUBE_MAP_NEGATIVE_X; break; case WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: TRACE("WGL_CUBE_MAP_FACE_ARB: WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB\n"); pbuffer->face = GL_TEXTURE_CUBE_MAP_POSITIVE_Y; break; case WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: TRACE("WGL_CUBE_MAP_FACE_ARB: WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB\n"); pbuffer->face = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; break; case WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: TRACE("WGL_CUBE_MAP_FACE_ARB: WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB\n"); pbuffer->face = GL_TEXTURE_CUBE_MAP_POSITIVE_Z; break; case WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: TRACE("WGL_CUBE_MAP_FACE_ARB: WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB\n"); pbuffer->face = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; break; default: WARN("unknown WGL_CUBE_MAP_FACE_ARB value 0x%x\n", value); SetLastError(ERROR_INVALID_DATA); return GL_FALSE; } break; default: WARN("invalide attribute 0x%x\n", attr); SetLastError(ERROR_INVALID_DATA); return GL_FALSE; } } if (context && context->draw_pbuffer == pbuffer) make_context_current(context, FALSE); return GL_TRUE; } /********************************************************************** * macdrv_wglSetPixelFormatWINE * * WGL_WINE_pixel_format_passthrough: wglSetPixelFormatWINE */ static BOOL macdrv_wglSetPixelFormatWINE(HDC hdc, int fmt) { return set_pixel_format(hdc, fmt, TRUE); } /********************************************************************** * macdrv_wglSwapIntervalEXT * * WGL_EXT_swap_control: wglSwapIntervalEXT */ static BOOL macdrv_wglSwapIntervalEXT(int interval) { struct wgl_context *context = NtCurrentTeb()->glContext; long value; CGLError err; TRACE("interval %d\n", interval); if (interval < 0) { SetLastError(ERROR_INVALID_DATA); return FALSE; } if (interval > 1) interval = 1; value = interval; err = CGLSetParameter(context->cglcontext, kCGLCPSwapInterval, (GLint*)&value); if (err != kCGLNoError) { WARN("CGLSetParameter(kCGLCPSwapInterval) failed; error %d %s\n", err, CGLErrorString(err)); SetLastError(ERROR_GEN_FAILURE); return FALSE; } return TRUE; } static void register_extension(const char *ext) { if (gl_info.wglExtensions[0]) strcat(gl_info.wglExtensions, " "); strcat(gl_info.wglExtensions, ext); TRACE("'%s'\n", ext); } static void load_extensions(void) { /* * ARB Extensions */ register_extension("WGL_ARB_extensions_string"); opengl_funcs.ext.p_wglGetExtensionsStringARB = macdrv_wglGetExtensionsStringARB; register_extension("WGL_ARB_make_current_read"); opengl_funcs.ext.p_wglGetCurrentReadDCARB = (void *)1; /* never called */ opengl_funcs.ext.p_wglMakeContextCurrentARB = macdrv_wglMakeContextCurrentARB; register_extension("WGL_ARB_pixel_format"); opengl_funcs.ext.p_wglChoosePixelFormatARB = macdrv_wglChoosePixelFormatARB; opengl_funcs.ext.p_wglGetPixelFormatAttribfvARB = macdrv_wglGetPixelFormatAttribfvARB; opengl_funcs.ext.p_wglGetPixelFormatAttribivARB = macdrv_wglGetPixelFormatAttribivARB; if (gluCheckExtension((GLubyte*)"GL_ARB_color_buffer_float", (GLubyte*)gl_info.glExtensions)) { register_extension("WGL_ARB_pixel_format_float"); register_extension("WGL_ATI_pixel_format_float"); } if (gluCheckExtension((GLubyte*)"GL_ARB_multisample", (GLubyte*)gl_info.glExtensions)) register_extension("WGL_ARB_multisample"); if (gluCheckExtension((GLubyte*)"GL_ARB_framebuffer_sRGB", (GLubyte*)gl_info.glExtensions)) register_extension("WGL_ARB_framebuffer_sRGB"); if (gluCheckExtension((GLubyte*)"GL_APPLE_pixel_buffer", (GLubyte*)gl_info.glExtensions)) { register_extension("WGL_ARB_pbuffer"); opengl_funcs.ext.p_wglCreatePbufferARB = macdrv_wglCreatePbufferARB; opengl_funcs.ext.p_wglDestroyPbufferARB = macdrv_wglDestroyPbufferARB; opengl_funcs.ext.p_wglGetPbufferDCARB = macdrv_wglGetPbufferDCARB; opengl_funcs.ext.p_wglQueryPbufferARB = macdrv_wglQueryPbufferARB; opengl_funcs.ext.p_wglReleasePbufferDCARB = macdrv_wglReleasePbufferDCARB; register_extension("WGL_ARB_render_texture"); opengl_funcs.ext.p_wglBindTexImageARB = macdrv_wglBindTexImageARB; opengl_funcs.ext.p_wglReleaseTexImageARB = macdrv_wglReleaseTexImageARB; opengl_funcs.ext.p_wglSetPbufferAttribARB = macdrv_wglSetPbufferAttribARB; if (gluCheckExtension((GLubyte*)"GL_ARB_texture_rectangle", (GLubyte*)gl_info.glExtensions) || gluCheckExtension((GLubyte*)"GL_EXT_texture_rectangle", (GLubyte*)gl_info.glExtensions)) register_extension("WGL_NV_render_texture_rectangle"); } /* TODO: WGL_ARB_create_context: wglCreateContextAttribsARB WGL_ARB_create_context_profile */ /* * EXT Extensions */ register_extension("WGL_EXT_extensions_string"); opengl_funcs.ext.p_wglGetExtensionsStringEXT = macdrv_wglGetExtensionsStringEXT; register_extension("WGL_EXT_swap_control"); opengl_funcs.ext.p_wglSwapIntervalEXT = macdrv_wglSwapIntervalEXT; opengl_funcs.ext.p_wglGetSwapIntervalEXT = macdrv_wglGetSwapIntervalEXT; /* Presumably identical to [W]GL_ARB_framebuffer_sRGB, above, but clients may check for either, so register them separately. */ if (gluCheckExtension((GLubyte*)"GL_EXT_framebuffer_sRGB", (GLubyte*)gl_info.glExtensions)) register_extension("WGL_EXT_framebuffer_sRGB"); if (gluCheckExtension((GLubyte*)"GL_EXT_packed_float", (GLubyte*)gl_info.glExtensions)) register_extension("WGL_EXT_pixel_format_packed_float"); /* * WINE-specific WGL Extensions */ /* In WineD3D we need the ability to set the pixel format more than once (e.g. after a device reset). * The default wglSetPixelFormat doesn't allow this, so add our own which allows it. */ register_extension("WGL_WINE_pixel_format_passthrough"); opengl_funcs.ext.p_wglSetPixelFormatWINE = macdrv_wglSetPixelFormatWINE; } static BOOL init_opengl(void) { static int init_done; unsigned int i; char buffer[200]; if (init_done) return (opengl_handle != NULL); init_done = 1; TRACE("()\n"); dc_pbuffers = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); if (!dc_pbuffers) { WARN("CFDictionaryCreateMutable failed\n"); return FALSE; } opengl_handle = wine_dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY|RTLD_LOCAL|RTLD_NOLOAD, buffer, sizeof(buffer)); if (!opengl_handle) { ERR("Failed to load OpenGL: %s\n", buffer); ERR("OpenGL support is disabled.\n"); return FALSE; } for (i = 0; i < sizeof(opengl_func_names)/sizeof(opengl_func_names[0]); i++) { if (!(((void **)&opengl_funcs.gl)[i] = wine_dlsym(opengl_handle, opengl_func_names[i], NULL, 0))) { ERR("%s not found in OpenGL, disabling.\n", opengl_func_names[i]); goto failed; } } /* redirect some standard OpenGL functions */ #define REDIRECT(func) \ do { p##func = opengl_funcs.gl.p_##func; opengl_funcs.gl.p_##func = macdrv_##func; } while(0) REDIRECT(glCopyPixels); REDIRECT(glReadPixels); REDIRECT(glViewport); #undef REDIRECT /* redirect some OpenGL extension functions */ #define REDIRECT(func) \ do { if (opengl_funcs.ext.p_##func) { p##func = opengl_funcs.ext.p_##func; opengl_funcs.ext.p_##func = macdrv_##func; } } while(0) REDIRECT(glCopyColorTable); #undef REDIRECT if (!init_gl_info()) goto failed; load_extensions(); if (!init_pixel_formats()) goto failed; return TRUE; failed: wine_dlclose(opengl_handle, NULL, 0); opengl_handle = NULL; return FALSE; } /*********************************************************************** * sync_gl_view * * Synchronize the Mac GL view position with the Windows child window * position. */ void sync_gl_view(struct macdrv_win_data *data) { RECT rect; TRACE("hwnd %p gl_view %p\n", data->hwnd, data->gl_view); if (!data->gl_view) return; if (get_gl_view_window_rect(data, NULL, &rect) && memcmp(&data->gl_rect, &rect, sizeof(rect))) { TRACE("Setting GL view %p frame to %s\n", data->gl_view, wine_dbgstr_rect(&rect)); macdrv_set_view_window_and_frame(data->gl_view, NULL, cgrect_from_rect(rect)); data->gl_rect = rect; } } static int get_dc_pixel_format(HDC hdc) { int format; HWND hwnd; if ((hwnd = WindowFromDC(hdc))) { struct macdrv_win_data *data; if (!(data = get_win_data(hwnd))) { FIXME("DC for window %p of other process: not implemented\n", hwnd); return 0; } format = data->pixel_format; release_win_data(data); } else { struct wgl_pbuffer *pbuffer; EnterCriticalSection(&dc_pbuffers_section); pbuffer = (struct wgl_pbuffer*)CFDictionaryGetValue(dc_pbuffers, hdc); if (pbuffer) format = pbuffer->format; else { WARN("no window or pbuffer for DC %p\n", hdc); format = 0; } LeaveCriticalSection(&dc_pbuffers_section); } return format; } /********************************************************************** * create_context */ static BOOL create_context(struct wgl_context *context, CGLContextObj share) { const pixel_format *pf; CGLPixelFormatAttribute attribs[64]; int n = 0; CGLPixelFormatObj pix; GLint virtualScreens; CGLError err; long swap_interval; pf = get_pixel_format(context->format, TRUE /* non-displayable */); if (!pf) { ERR("Invalid pixel format %d, expect problems!\n", context->format); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return FALSE; } attribs[n++] = kCGLPFAMinimumPolicy; attribs[n++] = kCGLPFAClosestPolicy; if (pf->accelerated) attribs[n++] = kCGLPFAAccelerated; else { attribs[n++] = kCGLPFARendererID; attribs[n++] = kCGLRendererGenericFloatID; } if (pf->double_buffer) attribs[n++] = kCGLPFADoubleBuffer; attribs[n++] = kCGLPFAAuxBuffers; attribs[n++] = pf->aux_buffers; attribs[n++] = kCGLPFAColorSize; attribs[n++] = color_modes[pf->color_mode].color_bits; attribs[n++] = kCGLPFAAlphaSize; attribs[n++] = color_modes[pf->color_mode].alpha_bits; if (color_modes[pf->color_mode].is_float) attribs[n++] = kCGLPFAColorFloat; attribs[n++] = kCGLPFADepthSize; attribs[n++] = pf->depth_bits; attribs[n++] = kCGLPFAStencilSize; attribs[n++] = pf->stencil_bits; if (pf->stereo) attribs[n++] = kCGLPFAStereo; if (pf->accum_mode) { attribs[n++] = kCGLPFAAccumSize; attribs[n++] = color_modes[pf->accum_mode - 1].color_bits; } if (pf->window) attribs[n++] = kCGLPFAWindow; if (pf->pbuffer) attribs[n++] = kCGLPFAPBuffer; if (pf->sample_buffers && pf->samples) { attribs[n++] = kCGLPFASampleBuffers; attribs[n++] = pf->sample_buffers; attribs[n++] = kCGLPFASamples; attribs[n++] = pf->samples; } if (pf->backing_store) attribs[n++] = kCGLPFABackingStore; attribs[n] = 0; err = CGLChoosePixelFormat(attribs, &pix, &virtualScreens); if (err != kCGLNoError || !pix) { WARN("CGLChoosePixelFormat() failed with error %d %s\n", err, CGLErrorString(err)); return FALSE; } err = CGLCreateContext(pix, share, &context->cglcontext); CGLReleasePixelFormat(pix); if (err != kCGLNoError || !context->cglcontext) { context->cglcontext = NULL; WARN("CGLCreateContext() failed with error %d %s\n", err, CGLErrorString(err)); return FALSE; } /* According to the WGL_EXT_swap_control docs, the default swap interval for a context is 1. CGL contexts default to 0, so we need to set it. */ swap_interval = 1; err = CGLSetParameter(context->cglcontext, kCGLCPSwapInterval, (GLint*)&swap_interval); if (err != kCGLNoError) WARN("CGLSetParameter(kCGLCPSwapInterval) failed with error %d %s; leaving un-vsynced\n", err, CGLErrorString(err)); context->context = macdrv_create_opengl_context(context->cglcontext); CGLReleaseContext(context->cglcontext); if (!context->context) { WARN("macdrv_create_opengl_context() failed\n"); return FALSE; } TRACE("created context %p/%p/%p\n", context, context->context, context->cglcontext); return TRUE; } /********************************************************************** * macdrv_wglDescribePixelFormat */ int macdrv_wglDescribePixelFormat(HDC hdc, int fmt, UINT size, PIXELFORMATDESCRIPTOR *descr) { int ret = nb_formats; const pixel_format *pf; const struct color_mode *mode; TRACE("hdc %p fmt %d size %u descr %p\n", hdc, fmt, size, descr); if (fmt <= 0 || fmt > ret) return ret; if (size < sizeof(*descr)) return 0; pf = &pixel_formats[fmt - 1]; memset(descr, 0, sizeof(*descr)); descr->nSize = sizeof(*descr); descr->nVersion = 1; descr->dwFlags = PFD_SUPPORT_OPENGL; if (pf->window) descr->dwFlags |= PFD_DRAW_TO_WINDOW; if (!pf->accelerated) descr->dwFlags |= PFD_GENERIC_FORMAT; if (pf->double_buffer) descr->dwFlags |= PFD_DOUBLEBUFFER; if (pf->stereo) descr->dwFlags |= PFD_STEREO; if (pf->backing_store) descr->dwFlags |= PFD_SWAP_COPY; descr->iPixelType = PFD_TYPE_RGBA; mode = &color_modes[pf->color_mode]; /* If the mode doesn't have alpha, return bits per pixel instead of color bits. On Windows, color bits sometimes exceeds r+g+b (e.g. it's 32 for an R8G8B8A0 pixel format). If an app depends on that and expects that cColorBits >= 32 for such a pixel format, we need to accomodate that. */ if (mode->alpha_bits) descr->cColorBits = mode->color_bits; else descr->cColorBits = mode->bits_per_pixel; descr->cRedBits = mode->red_bits; descr->cRedShift = mode->red_shift; descr->cGreenBits = mode->green_bits; descr->cGreenShift = mode->green_shift; descr->cBlueBits = mode->blue_bits; descr->cBlueShift = mode->blue_shift; descr->cAlphaBits = mode->alpha_bits; descr->cAlphaShift = mode->alpha_shift; if (pf->accum_mode) { mode = &color_modes[pf->accum_mode - 1]; descr->cAccumBits = mode->color_bits; descr->cAccumRedBits = mode->red_bits; descr->cAccumGreenBits = mode->green_bits; descr->cAccumBlueBits = mode->blue_bits; descr->cAccumAlphaBits = mode->alpha_bits; } descr->cDepthBits = pf->depth_bits; descr->cStencilBits = pf->stencil_bits; descr->cAuxBuffers = pf->aux_buffers; descr->iLayerType = PFD_MAIN_PLANE; return ret; } /*********************************************************************** * macdrv_wglCopyContext */ static BOOL macdrv_wglCopyContext(struct wgl_context *src, struct wgl_context *dst, UINT mask) { CGLError err; TRACE("src %p dst %p mask %x\n", src, dst, mask); err = CGLCopyContext(src->cglcontext, dst->cglcontext, mask); if (err != kCGLNoError) WARN("CGLCopyContext() failed with err %d %s\n", err, CGLErrorString(err)); return (err == kCGLNoError); } /*********************************************************************** * macdrv_wglCreateContext */ static struct wgl_context *macdrv_wglCreateContext(HDC hdc) { int format; struct wgl_context *context; TRACE("hdc %p\n", hdc); format = get_dc_pixel_format(hdc); if (!is_valid_pixel_format(format)) { ERR("Invalid pixel format %d, expect problems!\n", format); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return NULL; } if (!(context = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context)))) return NULL; context->format = format; if (!create_context(context, NULL)) { HeapFree(GetProcessHeap(), 0, context); return NULL; } return context; } /*********************************************************************** * macdrv_wglDeleteContext */ static void macdrv_wglDeleteContext(struct wgl_context *context) { TRACE("deleting context %p/%p/%p\n", context, context->context, context->cglcontext); macdrv_dispose_opengl_context(context->context); HeapFree(GetProcessHeap(), 0, context); } /*********************************************************************** * macdrv_wglGetPixelFormat */ static int macdrv_wglGetPixelFormat(HDC hdc) { int format; format = get_dc_pixel_format(hdc); if (!is_valid_pixel_format(format)) /* not set yet */ format = 0; else if (!is_displayable_pixel_format(format)) { /* Non-displayable formats can't be used with traditional WGL calls. * As has been verified on Windows GetPixelFormat doesn't fail but returns pixel format 1. */ format = 1; } TRACE(" hdc %p -> %d\n", hdc, format); return format; } /*********************************************************************** * macdrv_wglGetProcAddress */ static PROC macdrv_wglGetProcAddress(const char *proc) { void *ret; if (!strncmp(proc, "wgl", 3)) return NULL; ret = wine_dlsym(opengl_handle, proc, NULL, 0); if (ret) { if (TRACE_ON(wgl)) { Dl_info info; if (dladdr(ret, &info)) TRACE("%s -> %s from %s\n", proc, info.dli_sname, info.dli_fname); else TRACE("%s -> %p (no library info)\n", proc, ret); } } else WARN("failed to find proc %s\n", debugstr_a(proc)); return ret; } /*********************************************************************** * macdrv_wglMakeCurrent */ static BOOL macdrv_wglMakeCurrent(HDC hdc, struct wgl_context *context) { TRACE("hdc %p context %p/%p/%p\n", hdc, context, (context ? context->context : NULL), (context ? context->cglcontext : NULL)); return macdrv_wglMakeContextCurrentARB(hdc, hdc, context); } /********************************************************************** * macdrv_wglSetPixelFormat */ static BOOL macdrv_wglSetPixelFormat(HDC hdc, int fmt, const PIXELFORMATDESCRIPTOR *descr) { return set_pixel_format(hdc, fmt, FALSE); } /*********************************************************************** * macdrv_wglShareLists */ static BOOL macdrv_wglShareLists(struct wgl_context *org, struct wgl_context *dest) { macdrv_opengl_context saved_context; CGLContextObj saved_cglcontext; TRACE("org %p dest %p\n", org, dest); /* Sharing of display lists works differently in Mac OpenGL and WGL. In Mac OpenGL it is done * at context creation time but in case of WGL it is done using wglShareLists. * * The approach is to create a Mac OpenGL context in wglCreateContext / wglCreateContextAttribsARB * and when a program requests sharing we recreate the destination context if it hasn't been made * current or when it hasn't shared display lists before. */ if (dest->has_been_current) { WARN("could not share display lists, the destination context has been current already\n"); return FALSE; } else if (dest->sharing) { WARN("could not share display lists because dest has already shared lists before\n"); return FALSE; } /* Re-create the Mac context and share display lists */ saved_context = dest->context; saved_cglcontext = dest->cglcontext; dest->context = NULL; dest->cglcontext = NULL; if (!create_context(dest, org->cglcontext)) { dest->context = saved_context; dest->cglcontext = saved_cglcontext; return FALSE; } /* Implicitly disposes of saved_cglcontext. */ macdrv_dispose_opengl_context(saved_context); TRACE("re-created OpenGL context %p/%p/%p sharing lists with context %p/%p/%p\n", dest, dest->context, dest->cglcontext, org, org->context, org->cglcontext); org->sharing = TRUE; dest->sharing = TRUE; return TRUE; } /********************************************************************** * macdrv_wglSwapBuffers */ static BOOL macdrv_wglSwapBuffers(HDC hdc) { struct wgl_context *context = NtCurrentTeb()->glContext; TRACE("hdc %p context %p/%p/%p\n", hdc, context, (context ? context->context : NULL), (context ? context->cglcontext : NULL)); if (!context) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } macdrv_flush_opengl_context(context->context); return TRUE; } static struct opengl_funcs opengl_funcs = { { macdrv_wglCopyContext, /* p_wglCopyContext */ macdrv_wglCreateContext, /* p_wglCreateContext */ macdrv_wglDeleteContext, /* p_wglDeleteContext */ macdrv_wglDescribePixelFormat, /* p_wglDescribePixelFormat */ macdrv_wglGetPixelFormat, /* p_wglGetPixelFormat */ macdrv_wglGetProcAddress, /* p_wglGetProcAddress */ macdrv_wglMakeCurrent, /* p_wglMakeCurrent */ macdrv_wglSetPixelFormat, /* p_wglSetPixelFormat */ macdrv_wglShareLists, /* p_wglShareLists */ macdrv_wglSwapBuffers, /* p_wglSwapBuffers */ } }; /********************************************************************** * macdrv_wine_get_wgl_driver */ struct opengl_funcs *macdrv_wine_get_wgl_driver(PHYSDEV dev, UINT version) { if (version != WINE_WGL_DRIVER_VERSION) { ERR("version mismatch, opengl32 wants %u but macdrv has %u\n", version, WINE_WGL_DRIVER_VERSION); return NULL; } if (!init_opengl()) return (void *)-1; return &opengl_funcs; }