2013-03-06 11:59:07 +01:00
|
|
|
/*
|
|
|
|
* 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_
|
2013-03-07 23:12:45 +01:00
|
|
|
#define __gltypes_h_
|
2013-03-06 11:59:07 +01:00
|
|
|
#include <OpenGL/OpenGL.h>
|
|
|
|
#include <OpenGL/glu.h>
|
|
|
|
#include <OpenGL/CGLRenderers.h>
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(wgl);
|
|
|
|
|
|
|
|
|
|
|
|
struct gl_info {
|
|
|
|
char *glVersion;
|
|
|
|
char *glExtensions;
|
|
|
|
|
|
|
|
char wglExtensions[4096];
|
2013-03-06 11:59:21 +01:00
|
|
|
|
|
|
|
GLint max_viewport_dims[2];
|
2013-03-06 11:59:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct gl_info gl_info;
|
|
|
|
|
|
|
|
|
|
|
|
struct wgl_context
|
|
|
|
{
|
|
|
|
HDC hdc;
|
|
|
|
int format;
|
|
|
|
macdrv_opengl_context context;
|
|
|
|
CGLContextObj cglcontext;
|
2013-03-06 11:59:14 +01:00
|
|
|
macdrv_view draw_view;
|
2013-03-06 11:59:21 +01:00
|
|
|
struct wgl_pbuffer *draw_pbuffer;
|
2013-03-06 11:59:14 +01:00
|
|
|
macdrv_view read_view;
|
2013-03-06 11:59:21 +01:00
|
|
|
struct wgl_pbuffer *read_pbuffer;
|
2013-03-06 11:59:07 +01:00
|
|
|
BOOL has_been_current;
|
|
|
|
BOOL sharing;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
struct wgl_pbuffer
|
|
|
|
{
|
|
|
|
CGLPBufferObj pbuffer;
|
|
|
|
int format;
|
2013-03-06 11:59:25 +01:00
|
|
|
BOOL no_texture;
|
|
|
|
int max_level;
|
|
|
|
GLint level;
|
|
|
|
GLenum face;
|
2013-03-06 11:59:21 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
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 };
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:14 +01:00
|
|
|
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);
|
2013-03-06 11:59:07 +01:00
|
|
|
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;
|
2013-03-27 13:01:37 +01:00
|
|
|
int color_ordering;
|
2013-03-06 11:59:07 +01:00
|
|
|
};
|
|
|
|
|
2013-03-27 13:01:37 +01:00
|
|
|
/* The value of "color_ordering" is somewhat arbitrary. It incorporates some
|
|
|
|
observations of the behavior of Windows systems, but also subjective judgments
|
|
|
|
about what color formats are more "normal" than others.
|
|
|
|
|
|
|
|
On at least some Windows systems, integer color formats are listed before
|
|
|
|
floating-point formats. Within the integer formats, higher color bits were
|
|
|
|
usually listed before lower color bits, while for floating-point formats it
|
|
|
|
was the reverse. However, that leads D3D to select 64-bit integer formats in
|
|
|
|
preference to 32-bit formats when the latter would be sufficient. It seems
|
|
|
|
that a 32-bit format is much more likely to be normally used in that case.
|
|
|
|
|
|
|
|
Also, there are certain odd color formats supported on the Mac which seem like
|
|
|
|
they would be less appropriate than more common ones. For instance, the color
|
|
|
|
formats with alpha in a separate byte (e.g. kCGLRGB888A8Bit with R8G8B8 in one
|
|
|
|
32-bit value and A8 in a separate 8-bit value) and the formats with 10-bit RGB
|
|
|
|
components.
|
|
|
|
|
|
|
|
For two color formats which differ only in whether or not they have alpha bits,
|
|
|
|
we use the same ordering. pixel_format_comparator() gives alpha bits a
|
|
|
|
different weight than color formats.
|
|
|
|
*/
|
2013-03-06 11:59:07 +01:00
|
|
|
static const struct color_mode color_modes[] = {
|
2013-03-27 13:01:37 +01:00
|
|
|
{ kCGLRGB444Bit, 16, 12, 4, 8, 4, 4, 4, 0, 0, 0, FALSE, 5 },
|
|
|
|
{ kCGLARGB4444Bit, 16, 16, 4, 8, 4, 4, 4, 0, 4, 12, FALSE, 5 },
|
|
|
|
{ kCGLRGB444A8Bit, 24, 20, 4, 8, 4, 4, 4, 0, 8, 16, FALSE, 10 },
|
|
|
|
{ kCGLRGB555Bit, 16, 15, 5, 10, 5, 5, 5, 0, 0, 0, FALSE, 4 },
|
|
|
|
{ kCGLARGB1555Bit, 16, 16, 5, 10, 5, 5, 5, 0, 1, 15, FALSE, 4 },
|
|
|
|
{ kCGLRGB555A8Bit, 24, 23, 5, 10, 5, 5, 5, 0, 8, 16, FALSE, 9 },
|
|
|
|
{ kCGLRGB565Bit, 16, 16, 5, 11, 6, 5, 5, 0, 0, 0, FALSE, 3 },
|
|
|
|
{ kCGLRGB565A8Bit, 24, 24, 5, 11, 6, 5, 5, 0, 8, 16, FALSE, 8 },
|
|
|
|
{ kCGLRGB888Bit, 32, 24, 8, 16, 8, 8, 8, 0, 0, 0, FALSE, 0 },
|
|
|
|
{ kCGLARGB8888Bit, 32, 32, 8, 16, 8, 8, 8, 0, 8, 24, FALSE, 0 },
|
|
|
|
{ kCGLRGB888A8Bit, 40, 32, 8, 16, 8, 8, 8, 0, 8, 32, FALSE, 7 },
|
|
|
|
{ kCGLRGB101010Bit, 32, 30, 10, 20, 10, 10, 10, 0, 0, 0, FALSE, 6 },
|
|
|
|
{ kCGLARGB2101010Bit, 32, 32, 10, 20, 10, 10, 10, 0, 2, 30, FALSE, 6 },
|
|
|
|
{ kCGLRGB101010_A8Bit, 40, 38, 10, 20, 10, 10, 10, 0, 8, 32, FALSE, 11 },
|
|
|
|
{ kCGLRGB121212Bit, 48, 36, 12, 24, 12, 12, 12, 0, 0, 0, FALSE, 2 },
|
|
|
|
{ kCGLARGB12121212Bit, 48, 48, 12, 24, 12, 12, 12, 0, 12, 36, FALSE, 2 },
|
|
|
|
{ kCGLRGB161616Bit, 64, 48, 16, 48, 16, 32, 16, 16, 0, 0, FALSE, 1 },
|
|
|
|
{ kCGLRGBA16161616Bit, 64, 64, 16, 48, 16, 32, 16, 16, 16, 0, FALSE, 1 },
|
|
|
|
{ kCGLRGBFloat64Bit, 64, 48, 16, 32, 16, 16, 16, 0, 0, 0, TRUE, 12 },
|
|
|
|
{ kCGLRGBAFloat64Bit, 64, 64, 16, 48, 16, 32, 16, 16, 16, 0, TRUE, 12 },
|
|
|
|
{ kCGLRGBFloat128Bit, 128, 96, 32, 96, 32, 64, 32, 32, 0, 0, TRUE, 13 },
|
|
|
|
{ kCGLRGBAFloat128Bit, 128, 128, 32, 96, 32, 64, 32, 32, 32, 0, TRUE, 13 },
|
|
|
|
{ kCGLRGBFloat256Bit, 256, 192, 64, 192, 64, 128, 64, 64, 0, 0, TRUE, 14 },
|
|
|
|
{ kCGLRGBAFloat256Bit, 256, 256, 64, 192, 64, 128, 64, 64, 64, 0, TRUE, 15 },
|
2013-03-06 11:59:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
2013-05-04 06:05:08 +02:00
|
|
|
C_ASSERT(sizeof(((pixel_format_or_code*)0)->format) <= sizeof(((pixel_format_or_code*)0)->code));
|
2013-03-06 11:59:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
static pixel_format *pixel_formats;
|
|
|
|
static int nb_formats, nb_displayable_formats;
|
|
|
|
|
|
|
|
|
|
|
|
static void *opengl_handle;
|
|
|
|
|
|
|
|
|
2013-04-25 03:18:29 +02:00
|
|
|
static const char* debugstr_attrib(int attrib, int value)
|
|
|
|
{
|
|
|
|
static const struct {
|
|
|
|
int attrib;
|
|
|
|
const char *name;
|
|
|
|
} attrib_names[] = {
|
|
|
|
#define ATTRIB(a) { a, #a }
|
|
|
|
ATTRIB(WGL_ACCELERATION_ARB),
|
|
|
|
ATTRIB(WGL_ACCUM_ALPHA_BITS_ARB),
|
|
|
|
ATTRIB(WGL_ACCUM_BITS_ARB),
|
|
|
|
ATTRIB(WGL_ACCUM_BLUE_BITS_ARB),
|
|
|
|
ATTRIB(WGL_ACCUM_GREEN_BITS_ARB),
|
|
|
|
ATTRIB(WGL_ACCUM_RED_BITS_ARB),
|
|
|
|
ATTRIB(WGL_ALPHA_BITS_ARB),
|
|
|
|
ATTRIB(WGL_ALPHA_SHIFT_ARB),
|
|
|
|
ATTRIB(WGL_AUX_BUFFERS_ARB),
|
|
|
|
ATTRIB(WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV),
|
|
|
|
ATTRIB(WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV),
|
|
|
|
ATTRIB(WGL_BIND_TO_TEXTURE_RGB_ARB),
|
|
|
|
ATTRIB(WGL_BIND_TO_TEXTURE_RGBA_ARB),
|
|
|
|
ATTRIB(WGL_BLUE_BITS_ARB),
|
|
|
|
ATTRIB(WGL_BLUE_SHIFT_ARB),
|
|
|
|
ATTRIB(WGL_COLOR_BITS_ARB),
|
|
|
|
ATTRIB(WGL_DEPTH_BITS_ARB),
|
|
|
|
ATTRIB(WGL_DOUBLE_BUFFER_ARB),
|
|
|
|
ATTRIB(WGL_DRAW_TO_BITMAP_ARB),
|
|
|
|
ATTRIB(WGL_DRAW_TO_PBUFFER_ARB),
|
|
|
|
ATTRIB(WGL_DRAW_TO_WINDOW_ARB),
|
|
|
|
ATTRIB(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB),
|
|
|
|
ATTRIB(WGL_GREEN_BITS_ARB),
|
|
|
|
ATTRIB(WGL_GREEN_SHIFT_ARB),
|
|
|
|
ATTRIB(WGL_NEED_PALETTE_ARB),
|
|
|
|
ATTRIB(WGL_NEED_SYSTEM_PALETTE_ARB),
|
|
|
|
ATTRIB(WGL_NUMBER_OVERLAYS_ARB),
|
|
|
|
ATTRIB(WGL_NUMBER_PIXEL_FORMATS_ARB),
|
|
|
|
ATTRIB(WGL_NUMBER_UNDERLAYS_ARB),
|
|
|
|
ATTRIB(WGL_PIXEL_TYPE_ARB),
|
|
|
|
ATTRIB(WGL_RED_BITS_ARB),
|
|
|
|
ATTRIB(WGL_RED_SHIFT_ARB),
|
|
|
|
ATTRIB(WGL_SAMPLE_BUFFERS_ARB),
|
|
|
|
ATTRIB(WGL_SAMPLES_ARB),
|
|
|
|
ATTRIB(WGL_SHARE_ACCUM_ARB),
|
|
|
|
ATTRIB(WGL_SHARE_DEPTH_ARB),
|
|
|
|
ATTRIB(WGL_SHARE_STENCIL_ARB),
|
|
|
|
ATTRIB(WGL_STENCIL_BITS_ARB),
|
|
|
|
ATTRIB(WGL_STEREO_ARB),
|
|
|
|
ATTRIB(WGL_SUPPORT_GDI_ARB),
|
|
|
|
ATTRIB(WGL_SUPPORT_OPENGL_ARB),
|
|
|
|
ATTRIB(WGL_SWAP_LAYER_BUFFERS_ARB),
|
|
|
|
ATTRIB(WGL_SWAP_METHOD_ARB),
|
|
|
|
ATTRIB(WGL_TRANSPARENT_ALPHA_VALUE_ARB),
|
|
|
|
ATTRIB(WGL_TRANSPARENT_ARB),
|
|
|
|
ATTRIB(WGL_TRANSPARENT_BLUE_VALUE_ARB),
|
|
|
|
ATTRIB(WGL_TRANSPARENT_GREEN_VALUE_ARB),
|
|
|
|
ATTRIB(WGL_TRANSPARENT_INDEX_VALUE_ARB),
|
|
|
|
ATTRIB(WGL_TRANSPARENT_RED_VALUE_ARB),
|
|
|
|
#undef ATTRIB
|
|
|
|
};
|
|
|
|
int i;
|
|
|
|
const char *attrib_name = NULL;
|
|
|
|
const char *value_name = NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(attrib_names) / sizeof(attrib_names[0]); i++)
|
|
|
|
{
|
|
|
|
if (attrib_names[i].attrib == attrib)
|
|
|
|
{
|
|
|
|
attrib_name = attrib_names[i].name;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!attrib_name)
|
|
|
|
attrib_name = wine_dbg_sprintf("Attrib 0x%04x", attrib);
|
|
|
|
|
|
|
|
switch (attrib)
|
|
|
|
{
|
|
|
|
case WGL_ACCELERATION_ARB:
|
|
|
|
switch (value)
|
|
|
|
{
|
|
|
|
case WGL_FULL_ACCELERATION_ARB: value_name = "WGL_FULL_ACCELERATION_ARB"; break;
|
|
|
|
case WGL_GENERIC_ACCELERATION_ARB: value_name = "WGL_GENERIC_ACCELERATION_ARB"; break;
|
|
|
|
case WGL_NO_ACCELERATION_ARB: value_name = "WGL_NO_ACCELERATION_ARB"; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WGL_PIXEL_TYPE_ARB:
|
|
|
|
switch (value)
|
|
|
|
{
|
|
|
|
case WGL_TYPE_COLORINDEX_ARB: value_name = "WGL_TYPE_COLORINDEX_ARB"; break;
|
|
|
|
case WGL_TYPE_RGBA_ARB: value_name = "WGL_TYPE_RGBA_ARB"; break;
|
|
|
|
case WGL_TYPE_RGBA_FLOAT_ARB: value_name = "WGL_TYPE_RGBA_FLOAT_ARB"; break;
|
|
|
|
case WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT: value_name = "WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT"; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WGL_SWAP_METHOD_ARB:
|
|
|
|
switch (value)
|
|
|
|
{
|
|
|
|
case WGL_SWAP_COPY_ARB: value_name = "WGL_SWAP_COPY_ARB"; break;
|
|
|
|
case WGL_SWAP_EXCHANGE_ARB: value_name = "WGL_SWAP_EXCHANGE_ARB"; break;
|
|
|
|
case WGL_SWAP_UNDEFINED_ARB: value_name = "WGL_SWAP_UNDEFINED_ARB"; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!value_name)
|
|
|
|
value_name = wine_dbg_sprintf("%d / 0x%04x", value, value);
|
|
|
|
|
|
|
|
return wine_dbg_sprintf("%40s: %s", attrib_name, value_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
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,
|
2013-03-25 06:34:32 +01:00
|
|
|
pf->accum_mode ? color_modes[pf->accum_mode - 1].color_bits : 0,
|
2013-03-06 11:59:07 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-27 13:01:37 +01:00
|
|
|
/* Explicit color mode ordering. */
|
|
|
|
if (color_modes[pf1.color_mode].color_ordering < color_modes[pf2.color_mode].color_ordering)
|
2013-03-06 11:59:07 +01:00
|
|
|
return kCFCompareLessThan;
|
2013-03-27 13:01:37 +01:00
|
|
|
if (color_modes[pf1.color_mode].color_ordering > color_modes[pf2.color_mode].color_ordering)
|
2013-03-06 11:59:07 +01:00
|
|
|
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");
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
opengl_funcs.gl.p_glGetIntegerv(GL_MAX_VIEWPORT_DIMS, gl_info.max_viewport_dims);
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:14 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* make_context_current
|
|
|
|
*/
|
|
|
|
static void make_context_current(struct wgl_context *context, BOOL read)
|
|
|
|
{
|
2013-03-06 11:59:21 +01:00
|
|
|
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
|
|
|
|
{
|
2013-03-06 11:59:25 +01:00
|
|
|
CGLSetPBuffer(context->cglcontext, pbuffer->pbuffer, pbuffer->face,
|
|
|
|
pbuffer->level, 0);
|
2013-03-06 11:59:21 +01:00
|
|
|
CGLSetCurrentContext(context->cglcontext);
|
|
|
|
}
|
2013-03-06 11:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
if (context->read_view || context->read_pbuffer)
|
2013-03-06 11:59:14 +01:00
|
|
|
make_context_current(context, TRUE);
|
|
|
|
|
|
|
|
pglCopyColorTable(target, internalformat, x, y, width);
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
if (context->read_view || context->read_pbuffer)
|
2013-03-06 11:59:14 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
if (context->read_view || context->read_pbuffer)
|
2013-03-06 11:59:14 +01:00
|
|
|
make_context_current(context, TRUE);
|
|
|
|
|
|
|
|
pglCopyPixels(x, y, width, height, type);
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
if (context->read_view || context->read_pbuffer)
|
2013-03-06 11:59:14 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
if (context->read_view || context->read_pbuffer)
|
2013-03-06 11:59:14 +01:00
|
|
|
make_context_current(context, TRUE);
|
|
|
|
|
|
|
|
pglReadPixels(x, y, width, height, format, type, pixels);
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
if (context->read_view || context->read_pbuffer)
|
2013-03-06 11:59:14 +01:00
|
|
|
make_context_current(context, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:25 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:17 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* 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];
|
|
|
|
|
2013-04-25 03:18:29 +02:00
|
|
|
TRACE("%s\n", debugstr_attrib(attr, value));
|
|
|
|
|
2013-03-06 11:59:17 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
case WGL_DRAW_TO_PBUFFER_ARB:
|
2013-03-06 11:59:25 +01:00
|
|
|
case WGL_BIND_TO_TEXTURE_RGB_ARB:
|
|
|
|
case WGL_BIND_TO_TEXTURE_RGBA_ARB:
|
2013-03-06 11:59:30 +01:00
|
|
|
case WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV:
|
|
|
|
case WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV:
|
2013-03-06 11:59:21 +01:00
|
|
|
if (valid.pbuffer && (!pf.pbuffer != !value)) goto cant_match;
|
|
|
|
pf.pbuffer = (value != 0);
|
|
|
|
valid.pbuffer = 1;
|
2013-03-06 11:59:30 +01:00
|
|
|
if ((attr == WGL_BIND_TO_TEXTURE_RGBA_ARB || attr == WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV) &&
|
|
|
|
!alpha_bits)
|
2013-03-06 11:59:25 +01:00
|
|
|
alpha_bits = 1;
|
2013-03-06 11:59:21 +01:00
|
|
|
break;
|
|
|
|
|
2013-03-06 11:59:17 +01:00
|
|
|
default:
|
2013-04-25 03:18:29 +02:00
|
|
|
WARN("invalid attribute %s\n", debugstr_attrib(attr, value));
|
2013-03-06 11:59:17 +01:00
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-25 03:18:29 +02:00
|
|
|
TRACE("required: w/p/a %s/%s/%s col/r/g/b/a %d%s/%d/%d/%d/%d srgb %d ac %d/%d/%d/%d/%d dp/stn/ax/b/db/str %u/%u/%u/%s/%s/%s samp %u/%u\n",
|
|
|
|
valid.window ? (pf.window ? "1" : "0") : "?",
|
|
|
|
valid.pbuffer ? (pf.pbuffer ? "1" : "0") : "?",
|
|
|
|
valid.accelerated ? (pf.accelerated ? "1" : "0") : "?",
|
|
|
|
color_bits,
|
|
|
|
float_color == -1 ? "?" : float_color ? "f" : "",
|
|
|
|
red_bits,
|
|
|
|
green_bits,
|
|
|
|
blue_bits,
|
|
|
|
alpha_bits,
|
|
|
|
(int)srgb,
|
|
|
|
accum_bits,
|
|
|
|
accum_red_bits,
|
|
|
|
accum_green_bits,
|
|
|
|
accum_blue_bits,
|
|
|
|
accum_alpha_bits,
|
|
|
|
pf.depth_bits,
|
|
|
|
pf.stencil_bits,
|
|
|
|
pf.aux_buffers,
|
|
|
|
valid.backing_store ? (pf.backing_store ? "1" : "0") : "?",
|
|
|
|
valid.double_buffer ? (pf.double_buffer ? "1" : "0") : "?",
|
|
|
|
valid.stereo ? (pf.stereo ? "1" : "0") : "?",
|
|
|
|
pf.sample_buffers,
|
|
|
|
pf.samples);
|
|
|
|
|
2013-03-06 11:59:17 +01:00
|
|
|
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
|
2013-04-18 18:58:05 +02:00
|
|
|
expects that to match such a pixel format, we need to accommodate that. */
|
2013-03-06 11:59:17 +01:00
|
|
|
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;
|
|
|
|
|
2013-04-25 03:18:43 +02:00
|
|
|
piFormats[found++] = i + 1;
|
|
|
|
TRACE("match: pixel format %d %s\n", i + 1, debugstr_pf(&pixel_formats[i]));
|
2013-03-06 11:59:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
cant_match:
|
|
|
|
*nNumFormats = found;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
2013-03-06 11:59:25 +01:00
|
|
|
GLenum target = 0;
|
|
|
|
GLenum internalFormat = 0;
|
2013-03-06 11:59:21 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-06 11:59:25 +01:00
|
|
|
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;
|
2013-03-06 11:59:30 +01:00
|
|
|
case WGL_TEXTURE_RECTANGLE_NV:
|
|
|
|
TRACE("WGL_TEXTURE_TARGET_ARB: WGL_TEXTURE_RECTANGLE_NV\n");
|
|
|
|
target = GL_TEXTURE_RECTANGLE;
|
|
|
|
break;
|
2013-03-06 11:59:25 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
default:
|
|
|
|
WARN("unknown attribute 0x%x\n", attr);
|
|
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-06 11:59:25 +01:00
|
|
|
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);
|
2013-03-06 11:59:21 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:17 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
2013-04-25 03:18:29 +02:00
|
|
|
TRACE("%s\n", debugstr_attrib(piAttributes[0], piValues[0]));
|
2013-03-06 11:59:17 +01:00
|
|
|
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
|
2013-04-18 18:58:05 +02:00
|
|
|
pixel format, we need to accommodate that. */
|
2013-03-06 11:59:17 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
case WGL_DRAW_TO_PBUFFER_ARB:
|
2013-03-06 11:59:25 +01:00
|
|
|
case WGL_BIND_TO_TEXTURE_RGB_ARB:
|
2013-03-06 11:59:30 +01:00
|
|
|
case WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV:
|
2013-03-06 11:59:21 +01:00
|
|
|
piValues[i] = pf->pbuffer ? GL_TRUE : GL_FALSE;
|
|
|
|
break;
|
|
|
|
|
2013-03-06 11:59:25 +01:00
|
|
|
case WGL_BIND_TO_TEXTURE_RGBA_ARB:
|
2013-03-06 11:59:30 +01:00
|
|
|
case WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV:
|
2013-03-06 11:59:25 +01:00
|
|
|
piValues[i] = (pf->pbuffer && color_modes[pf->color_mode].alpha_bits) ? GL_TRUE : GL_FALSE;
|
|
|
|
break;
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-06 11:59:17 +01:00
|
|
|
default:
|
|
|
|
WARN("invalid attribute %x\n", piAttributes[i]);
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-04-25 03:18:29 +02:00
|
|
|
TRACE("%s\n", debugstr_attrib(piAttributes[i], piValues[i]));
|
2013-03-06 11:59:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:35 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:14 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* 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;
|
2013-03-06 11:59:21 +01:00
|
|
|
context->draw_pbuffer = NULL;
|
2013-03-06 11:59:14 +01:00
|
|
|
release_win_data(data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-06 11:59:21 +01:00
|
|
|
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);
|
2013-03-06 11:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
context->read_view = NULL;
|
2013-03-06 11:59:21 +01:00
|
|
|
context->read_pbuffer = NULL;
|
2013-03-06 11:59:14 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2013-03-06 11:59:21 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
EnterCriticalSection(&dc_pbuffers_section);
|
|
|
|
context->read_pbuffer = (struct wgl_pbuffer*)CFDictionaryGetValue(dc_pbuffers, read_hdc);
|
|
|
|
LeaveCriticalSection(&dc_pbuffers_section);
|
|
|
|
}
|
2013-03-06 11:59:14 +01:00
|
|
|
}
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
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);
|
2013-03-06 11:59:14 +01:00
|
|
|
|
|
|
|
make_context_current(context, FALSE);
|
|
|
|
context->has_been_current = TRUE;
|
|
|
|
NtCurrentTeb()->glContext = context;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
2013-03-06 11:59:25 +01:00
|
|
|
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:
|
2013-03-06 11:59:30 +01:00
|
|
|
*piValue = WGL_TEXTURE_2D_ARB;
|
|
|
|
break;
|
2013-03-06 11:59:25 +01:00
|
|
|
case GL_TEXTURE_RECTANGLE:
|
|
|
|
default:
|
2013-03-06 11:59:30 +01:00
|
|
|
*piValue = WGL_TEXTURE_RECTANGLE_NV;
|
2013-03-06 11:59:25 +01:00
|
|
|
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;
|
2013-03-06 11:59:21 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:25 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* macdrv_wglSetPixelFormatWINE
|
|
|
|
*
|
|
|
|
* WGL_WINE_pixel_format_passthrough: wglSetPixelFormatWINE
|
|
|
|
*/
|
|
|
|
static BOOL macdrv_wglSetPixelFormatWINE(HDC hdc, int fmt)
|
|
|
|
{
|
|
|
|
return set_pixel_format(hdc, fmt, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:35 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
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;
|
|
|
|
|
2013-03-06 11:59:14 +01:00
|
|
|
register_extension("WGL_ARB_make_current_read");
|
|
|
|
opengl_funcs.ext.p_wglGetCurrentReadDCARB = (void *)1; /* never called */
|
|
|
|
opengl_funcs.ext.p_wglMakeContextCurrentARB = macdrv_wglMakeContextCurrentARB;
|
|
|
|
|
2013-03-06 11:59:17 +01:00
|
|
|
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");
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
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;
|
2013-03-06 11:59:25 +01:00
|
|
|
|
|
|
|
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;
|
2013-03-06 11:59:30 +01:00
|
|
|
|
|
|
|
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");
|
2013-03-06 11:59:21 +01:00
|
|
|
}
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
/* 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;
|
|
|
|
|
2013-03-06 11:59:35 +01:00
|
|
|
register_extension("WGL_EXT_swap_control");
|
|
|
|
opengl_funcs.ext.p_wglSwapIntervalEXT = macdrv_wglSwapIntervalEXT;
|
|
|
|
opengl_funcs.ext.p_wglGetSwapIntervalEXT = macdrv_wglGetSwapIntervalEXT;
|
|
|
|
|
2013-03-06 11:59:17 +01:00
|
|
|
/* 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");
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
/*
|
|
|
|
* 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");
|
|
|
|
|
2013-03-06 11:59:21 +01:00
|
|
|
dc_pbuffers = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
|
|
|
|
if (!dc_pbuffers)
|
|
|
|
{
|
|
|
|
WARN("CFDictionaryCreateMutable failed\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
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)
|
2013-03-06 11:59:14 +01:00
|
|
|
REDIRECT(glCopyPixels);
|
|
|
|
REDIRECT(glReadPixels);
|
2013-03-06 11:59:07 +01:00
|
|
|
REDIRECT(glViewport);
|
|
|
|
#undef REDIRECT
|
|
|
|
|
2013-03-06 11:59:14 +01:00
|
|
|
/* 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
|
|
|
|
|
2013-03-06 11:59:07 +01:00
|
|
|
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
|
|
|
|
{
|
2013-03-06 11:59:21 +01:00
|
|
|
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);
|
2013-03-06 11:59:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2013-03-27 13:01:22 +01:00
|
|
|
{
|
2013-03-06 11:59:07 +01:00
|
|
|
attribs[n++] = kCGLPFAAccelerated;
|
2013-03-27 13:01:22 +01:00
|
|
|
attribs[n++] = kCGLPFANoRecovery;
|
|
|
|
}
|
2013-03-06 11:59:07 +01:00
|
|
|
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
|
2013-04-18 18:58:05 +02:00
|
|
|
cColorBits >= 32 for such a pixel format, we need to accommodate that. */
|
2013-03-06 11:59:07 +01:00
|
|
|
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));
|
|
|
|
|
2013-03-06 11:59:14 +01:00
|
|
|
return macdrv_wglMakeContextCurrentARB(hdc, hdc, context);
|
2013-03-06 11:59:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|