[PATCH v2] winemac: Implement the WGL_WINE_query_renderer extension.

Ken Thomases ken at codeweavers.com
Fri Apr 29 01:59:30 CDT 2016


Signed-off-by: Ken Thomases <ken at codeweavers.com>
---
v2: get WGL_RENDERER_VERSION_WINE by parsing the GL_VERSION string or, failing that, the
        OpenGL framework bundle version
    consolidate some code for getting a GL string from a pixel format
    don't use kCGLPFAOpenGLProfile if core profile not requested; its presence would cause
        CGLCGLChoosePixelFormat() to fail on 10.6 even if a legacy profile is requested
    improved safety in get_iokit_display_property() in case property is not CFData as expected
    remove some duplicated code from WGL_RENDERER_VIDEO_MEMORY_WINE case
    tweaked the FIXME comment for WGL_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_WINE

 dlls/winemac.drv/opengl.c | 717 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 717 insertions(+)

diff --git a/dlls/winemac.drv/opengl.c b/dlls/winemac.drv/opengl.c
index ab79a82..728866b 100644
--- a/dlls/winemac.drv/opengl.c
+++ b/dlls/winemac.drv/opengl.c
@@ -60,6 +60,7 @@ struct wgl_context
 {
     struct list             entry;
     int                     format;
+    GLint                   renderer_id;
     macdrv_opengl_context   context;
     CGLContextObj           cglcontext;
     HWND                    draw_hwnd;
@@ -301,6 +302,7 @@ static const char* debugstr_attrib(int attrib, int value)
         ATTRIB(WGL_PIXEL_TYPE_ARB),
         ATTRIB(WGL_RED_BITS_ARB),
         ATTRIB(WGL_RED_SHIFT_ARB),
+        ATTRIB(WGL_RENDERER_ID_WINE),
         ATTRIB(WGL_SAMPLE_BUFFERS_ARB),
         ATTRIB(WGL_SAMPLES_ARB),
         ATTRIB(WGL_SHARE_ACCUM_ARB),
@@ -372,6 +374,31 @@ static const char* debugstr_attrib(int attrib, int value)
 }
 
 
+/**********************************************************************
+ *              active_displays_mask
+ */
+static CGOpenGLDisplayMask active_displays_mask(void)
+{
+    CGError err;
+    CGDirectDisplayID displays[32];
+    uint32_t count, i;
+    CGOpenGLDisplayMask mask;
+
+    err = CGGetActiveDisplayList(sizeof(displays) / sizeof(displays[0]), displays, &count);
+    if (err != kCGErrorSuccess)
+    {
+        displays[0] = CGMainDisplayID();
+        count = 1;
+    }
+
+    mask = 0;
+    for (i = 0; i < count; i++)
+        mask |= CGDisplayIDToOpenGLDisplayMask(displays[i]);
+
+    return mask;
+}
+
+
 static BOOL get_renderer_property(CGLRendererInfoObj renderer_info, GLint renderer_index,
                                   CGLRendererProperty property, GLint *value)
 {
@@ -1386,6 +1413,14 @@ static BOOL create_context(struct wgl_context *context, CGLContextObj share, uns
     attribs[n++] = kCGLPFAMinimumPolicy;
     attribs[n++] = kCGLPFAClosestPolicy;
 
+    if (context->renderer_id)
+    {
+        attribs[n++] = kCGLPFARendererID;
+        attribs[n++] = context->renderer_id;
+        attribs[n++] = kCGLPFASingleRenderer;
+        attribs[n++] = kCGLPFANoRecovery;
+    }
+
     if (pf->accelerated)
     {
         attribs[n++] = kCGLPFAAccelerated;
@@ -1767,6 +1802,425 @@ static void sync_swap_interval(struct wgl_context *context)
 
 
 /**********************************************************************
+ *              get_iokit_display_property
+ */
+static BOOL get_iokit_display_property(CGLRendererInfoObj renderer_info, GLint renderer, CFStringRef property, GLuint* value)
+{
+    GLint accelerated;
+    GLint display_mask;
+    int i;
+
+    if (!get_renderer_property(renderer_info, renderer, kCGLRPAccelerated, &accelerated) || !accelerated)
+    {
+        TRACE("assuming unaccelerated renderers don't have IOKit properties\n");
+        return FALSE;
+    }
+
+    if (!get_renderer_property(renderer_info, renderer, kCGLRPDisplayMask, &display_mask))
+    {
+        WARN("failed to get kCGLRPDisplayMask\n");
+        return FALSE;
+    }
+
+    for (i = 0; i < sizeof(GLint) * 8; i++)
+    {
+        GLint this_display_mask = (GLint)(1U << i);
+        if (this_display_mask & display_mask)
+        {
+            CGDirectDisplayID display_id = CGOpenGLDisplayMaskToDisplayID(this_display_mask);
+            io_service_t service;
+            CFDataRef data;
+            uint32_t prop_value;
+
+            if (!display_id)
+                continue;
+            service = CGDisplayIOServicePort(display_id);
+            if (!service)
+            {
+                WARN("CGDisplayIOServicePort(%u) failed\n", display_id);
+                continue;
+            }
+
+            data = IORegistryEntrySearchCFProperty(service, kIOServicePlane, property, NULL,
+                                                   kIORegistryIterateRecursively | kIORegistryIterateParents);
+            if (!data)
+            {
+                WARN("IORegistryEntrySearchCFProperty(%s) failed for display %u\n", debugstr_cf(property), display_id);
+                continue;
+            }
+            if (CFGetTypeID(data) != CFDataGetTypeID())
+            {
+                WARN("property %s is not a data object: %s\n", debugstr_cf(property), debugstr_cf(data));
+                CFRelease(data);
+                continue;
+            }
+            if (CFDataGetLength(data) != sizeof(prop_value))
+            {
+                WARN("%s data for display %u has unexpected length %llu\n", debugstr_cf(property), display_id,
+                     (unsigned long long)CFDataGetLength(data));
+                CFRelease(data);
+                continue;
+            }
+
+            CFDataGetBytes(data, CFRangeMake(0, sizeof(prop_value)), (UInt8*)&prop_value);
+            CFRelease(data);
+            *value = prop_value;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+
+/**********************************************************************
+ *              create_pixel_format_for_renderer
+ *
+ * Helper for macdrv_wglQueryRendererIntegerWINE().  Caller is
+ * responsible for releasing the pixel format object.
+ */
+static CGLPixelFormatObj create_pixel_format_for_renderer(CGLRendererInfoObj renderer_info, GLint renderer, BOOL core)
+{
+    GLint renderer_id;
+    CGLPixelFormatAttribute attrs[] = {
+        kCGLPFARendererID, 0,
+        kCGLPFASingleRenderer,
+        0, 0, /* reserve spots for kCGLPFAOpenGLProfile, kCGLOGLPVersion_3_2_Core */
+        0
+    };
+    CGError err;
+    CGLPixelFormatObj pixel_format;
+    GLint virtual_screens;
+
+    if (core)
+    {
+#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+        attrs[3] = kCGLPFAOpenGLProfile;
+        attrs[4] = (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core;
+#else
+        return NULL;
+#endif
+    }
+
+    if (!get_renderer_property(renderer_info, renderer, kCGLRPRendererID, &renderer_id))
+        return NULL;
+
+    attrs[1] = renderer_id;
+    err = CGLChoosePixelFormat(attrs, &pixel_format, &virtual_screens);
+    if (err != kCGLNoError)
+        pixel_format = NULL;
+    return pixel_format;
+}
+
+
+/**********************************************************************
+ *              map_renderer_index
+ *
+ * We can't create pixel formats for all renderers listed.  For example,
+ * in a dual-GPU system, the integrated GPU is typically unavailable
+ * when the discrete GPU is active.
+ *
+ * This function conceptually creates a list of "good" renderers from the
+ * list of all renderers.  It treats the input "renderer" parameter as an
+ * index into that list of good renderers and returns the corresponding
+ * index into the list of all renderers.
+ */
+static GLint map_renderer_index(CGLRendererInfoObj renderer_info, GLint renderer_count, GLint renderer)
+{
+    GLint good_count, i;
+
+    good_count = 0;
+    for (i = 0; i < renderer_count; i++)
+    {
+        CGLPixelFormatObj pix = create_pixel_format_for_renderer(renderer_info, i, FALSE);
+        if (pix)
+        {
+            CGLReleasePixelFormat(pix);
+            good_count++;
+            if (good_count > renderer)
+                break;
+        }
+        else
+            TRACE("skipping bad renderer %d\n", i);
+    }
+
+    TRACE("mapped requested renderer %d to index %d\n", renderer, i);
+    return i;
+}
+
+
+/**********************************************************************
+ *              get_gl_string
+ */
+static const char* get_gl_string(CGLPixelFormatObj pixel_format, GLenum name)
+{
+    const char* ret = NULL;
+    CGLContextObj context, old_context;
+    CGLError err;
+
+    err = CGLCreateContext(pixel_format, NULL, &context);
+    if (err == kCGLNoError && context)
+    {
+        old_context = CGLGetCurrentContext();
+        err = CGLSetCurrentContext(context);
+        if (err == kCGLNoError)
+        {
+            ret = (const char*)opengl_funcs.gl.p_glGetString(name);
+            CGLSetCurrentContext(old_context);
+        }
+        else
+            WARN("CGLSetCurrentContext failed: %d %s\n", err, CGLErrorString(err));
+        CGLReleaseContext(context);
+    }
+    else
+        WARN("CGLCreateContext failed: %d %s\n", err, CGLErrorString(err));
+
+    return ret;
+}
+
+
+/**********************************************************************
+ *              get_fallback_renderer_version
+ */
+static void get_fallback_renderer_version(GLuint *value)
+{
+    BOOL got_it = FALSE;
+    CFURLRef url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/Frameworks/OpenGL.framework"),
+                                                 kCFURLPOSIXPathStyle, TRUE);
+    if (url)
+    {
+        CFBundleRef bundle = CFBundleCreate(NULL, url);
+        CFRelease(url);
+        if (bundle)
+        {
+            CFStringRef version = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey);
+            if (version && CFGetTypeID(version) == CFStringGetTypeID())
+            {
+                size_t len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(version), kCFStringEncodingUTF8);
+                char* buf = HeapAlloc(GetProcessHeap(), 0, len);
+                if (buf && CFStringGetCString(version, buf, len, kCFStringEncodingUTF8))
+                {
+                    unsigned int major, minor, bugfix;
+                    int count = sscanf(buf, "%u.%u.%u", &major, &minor, &bugfix);
+                    if (count >= 2)
+                    {
+                        value[0] = major;
+                        value[1] = minor;
+                        if (count == 3)
+                            value[2] = bugfix;
+                        else
+                            value[2] = 0;
+                        got_it = TRUE;
+                    }
+                }
+                HeapFree(GetProcessHeap(), 0, buf);
+            }
+            CFRelease(bundle);
+        }
+    }
+
+    if (!got_it)
+    {
+        /* Use the version of the OpenGL framework from OS X 10.6, which is the
+           earliest version that the Mac driver supports. */
+        value[0] = 1;
+        value[1] = 6;
+        value[2] = 14;
+    }
+}
+
+
+/**********************************************************************
+ *              parse_renderer_version
+ *
+ * Get the renderer version from the OpenGL version string.  Assumes
+ * the string is of the form
+ * <GL major>.<GL minor>[.<GL bugfix>] <vendor>-<major>.<minor>[.<bugfix>]
+ * where major, minor, and bugfix are what we're interested in.  This
+ * form for the vendor specific information is not generally applicable,
+ * but seems reliable on OS X.
+ */
+static BOOL parse_renderer_version(const char* version, GLuint *value)
+{
+    const char* p = strchr(version, ' ');
+    int count;
+    unsigned int major, minor, bugfix;
+
+    if (p) p = strchr(p + 1, '-');
+    if (!p) return FALSE;
+
+    count = sscanf(p + 1, "%u.%u.%u", &major, &minor, &bugfix);
+    if (count < 2)
+        return FALSE;
+
+    value[0] = major;
+    value[1] = minor;
+    if (count == 3)
+        value[2] = bugfix;
+    else
+        value[2] = 0;
+
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *              query_renderer_integer
+ */
+static BOOL query_renderer_integer(CGLRendererInfoObj renderer_info, GLint renderer, GLenum attribute, GLuint *value)
+{
+    BOOL ret = FALSE;
+    CGLError err;
+
+    if (TRACE_ON(wgl))
+    {
+        GLint renderer_id;
+        if (!get_renderer_property(renderer_info, renderer, kCGLRPRendererID, &renderer_id))
+            renderer_id = 0;
+        TRACE("renderer %d (ID 0x%08x) attribute 0x%04x value %p\n", renderer, renderer_id, attribute, value);
+    }
+
+    switch (attribute)
+    {
+        case WGL_RENDERER_ACCELERATED_WINE:
+            if (!get_renderer_property(renderer_info, renderer, kCGLRPAccelerated, (GLint*)value))
+                break;
+            *value = !!*value;
+            ret = TRUE;
+            TRACE("WGL_RENDERER_ACCELERATED_WINE -> %u\n", *value);
+            break;
+
+        case WGL_RENDERER_DEVICE_ID_WINE:
+            ret = get_iokit_display_property(renderer_info, renderer, CFSTR("device-id"), value);
+            if (!ret)
+            {
+                *value = 0xffffffff;
+                ret = TRUE;
+            }
+            TRACE("WGL_RENDERER_DEVICE_ID_WINE -> 0x%04x\n", *value);
+            break;
+
+        case WGL_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_WINE:
+        case WGL_RENDERER_OPENGL_CORE_PROFILE_VERSION_WINE:
+        {
+            BOOL core = (attribute == WGL_RENDERER_OPENGL_CORE_PROFILE_VERSION_WINE);
+            CGLPixelFormatObj pixel_format = create_pixel_format_for_renderer(renderer_info, renderer, core);
+
+            if (pixel_format)
+            {
+                const char* version = get_gl_string(pixel_format, GL_VERSION);
+
+                CGLReleasePixelFormat(pixel_format);
+                if (version)
+                {
+                    unsigned int major, minor;
+
+                    if (sscanf(version, "%u.%u", &major, &minor) == 2)
+                    {
+                        value[0] = major;
+                        value[1] = minor;
+                        ret = TRUE;
+                    }
+                }
+            }
+
+            if (!ret)
+            {
+                value[0] = value[1] = 0;
+                ret = TRUE;
+            }
+            TRACE("%s -> %u.%u\n", core ? "WGL_RENDERER_OPENGL_CORE_PROFILE_VERSION_WINE" :
+                  "WGL_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_WINE", value[0], value[1]);
+            break;
+        }
+
+        case WGL_RENDERER_PREFERRED_PROFILE_WINE:
+        {
+            CGLPixelFormatObj pixel_format = create_pixel_format_for_renderer(renderer_info, renderer, TRUE);
+
+            if (pixel_format)
+            {
+                CGLReleasePixelFormat(pixel_format);
+                *value = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+                TRACE("WGL_RENDERER_PREFERRED_PROFILE_WINE -> WGL_CONTEXT_CORE_PROFILE_BIT_ARB (0x%04x)\n", *value);
+            }
+            else
+            {
+                *value = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+                TRACE("WGL_RENDERER_PREFERRED_PROFILE_WINE -> WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB (0x%04x)\n", *value);
+            }
+            ret = TRUE;
+            break;
+        }
+
+        case WGL_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_WINE:
+            /* FIXME: no API to query this */
+            *value = 0;
+            ret = TRUE;
+            TRACE("WGL_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_WINE -> %u\n", *value);
+            break;
+
+        case WGL_RENDERER_VENDOR_ID_WINE:
+            ret = get_iokit_display_property(renderer_info, renderer, CFSTR("vendor-id"), value);
+            if (!ret)
+            {
+                *value = 0xffffffff;
+                ret = TRUE;
+            }
+            TRACE("WGL_RENDERER_VENDOR_ID_WINE -> 0x%04x\n", *value);
+            break;
+
+        case WGL_RENDERER_VERSION_WINE:
+        {
+            CGLPixelFormatObj pixel_format = create_pixel_format_for_renderer(renderer_info, renderer, TRUE);
+
+            if (!pixel_format)
+                pixel_format = create_pixel_format_for_renderer(renderer_info, renderer, FALSE);
+            if (pixel_format)
+            {
+                const char* version = get_gl_string(pixel_format, GL_VERSION);
+
+                CGLReleasePixelFormat(pixel_format);
+                if (version)
+                    ret = parse_renderer_version(version, value);
+            }
+
+            if (!ret)
+            {
+                get_fallback_renderer_version(value);
+                ret = TRUE;
+            }
+            TRACE("WGL_RENDERER_VERSION_WINE -> %u.%u.%u\n", value[0], value[1], value[2]);
+            break;
+        }
+
+        case WGL_RENDERER_VIDEO_MEMORY_WINE:
+#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+            err = CGLDescribeRenderer(renderer_info, renderer, kCGLRPVideoMemoryMegabytes, (GLint*)value);
+            if (err != kCGLNoError && err != kCGLBadProperty)
+                WARN("CGLDescribeRenderer(kCGLRPVideoMemoryMegabytes) failed: %d %s\n", err, CGLErrorString(err));
+            if (err != kCGLNoError)
+#endif
+            {
+                if (get_renderer_property(renderer_info, renderer, kCGLRPVideoMemory, (GLint*)value))
+                    *value /= 1024 * 1024;
+                else
+                    *value = 0;
+            }
+            ret = TRUE;
+            TRACE("WGL_RENDERER_VIDEO_MEMORY_WINE -> %uMB\n", *value);
+            break;
+
+        default:
+            FIXME("unrecognized attribute 0x%04x\n", attribute);
+            break;
+    }
+
+    return ret;
+}
+
+
+/**********************************************************************
  *              macdrv_glCopyColorTable
  *
  * Hook into glCopyColorTable as part of the implementation of
@@ -2329,6 +2783,7 @@ static struct wgl_context *macdrv_wglCreateContextAttribsARB(HDC hdc,
     const int *iptr;
     int major = 1, minor = 0, profile = WGL_CONTEXT_CORE_PROFILE_BIT_ARB, flags = 0;
     BOOL core = FALSE;
+    GLint renderer_id = 0;
 
     TRACE("hdc %p, share_context %p, attrib_list %p\n", hdc, share_context, attrib_list);
 
@@ -2380,6 +2835,50 @@ static struct wgl_context *macdrv_wglCreateContextAttribsARB(HDC hdc,
                 profile = value;
                 break;
 
+            case WGL_RENDERER_ID_WINE:
+            {
+                CGLError err;
+                CGLRendererInfoObj renderer_info;
+                GLint renderer_count, temp;
+
+                err = CGLQueryRendererInfo(active_displays_mask(), &renderer_info, &renderer_count);
+                if (err != kCGLNoError)
+                {
+                    WARN("CGLQueryRendererInfo failed: %d %s\n", err, CGLErrorString(err));
+                    SetLastError(ERROR_GEN_FAILURE);
+                    return NULL;
+                }
+
+                value = map_renderer_index(renderer_info, renderer_count, value);
+
+                if (value >= renderer_count)
+                {
+                    WARN("WGL_RENDERER_ID_WINE renderer %d exceeds count (%d)\n", value, renderer_count);
+                    CGLDestroyRendererInfo(renderer_info);
+                    SetLastError(ERROR_INVALID_PARAMETER);
+                    return NULL;
+                }
+
+                if (!get_renderer_property(renderer_info, value, kCGLRPRendererID, &temp))
+                {
+                    WARN("WGL_RENDERER_ID_WINE failed to get ID of renderer %d\n", value);
+                    CGLDestroyRendererInfo(renderer_info);
+                    SetLastError(ERROR_GEN_FAILURE);
+                    return NULL;
+                }
+
+                CGLDestroyRendererInfo(renderer_info);
+
+                if (renderer_id && temp != renderer_id)
+                {
+                    WARN("WGL_RENDERER_ID_WINE requested two different renderers (0x%08x vs. 0x%08x)\n", renderer_id, temp);
+                    SetLastError(ERROR_INVALID_PARAMETER);
+                    return NULL;
+                }
+                renderer_id = temp;
+                break;
+            }
+
             default:
                 WARN("Unknown attribute %s.\n", debugstr_attrib(attr, value));
                 SetLastError(ERROR_INVALID_PARAMETER);
@@ -2435,6 +2934,7 @@ static struct wgl_context *macdrv_wglCreateContextAttribsARB(HDC hdc,
     if (!(context = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context)))) return NULL;
 
     context->format = format;
+    context->renderer_id = renderer_id;
     if (!create_context(context, share_context ? share_context->cglcontext : NULL, major))
     {
         HeapFree(GetProcessHeap(), 0, context);
@@ -3155,6 +3655,124 @@ static BOOL macdrv_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, struct w
 
 
 /**********************************************************************
+ *              macdrv_wglQueryCurrentRendererIntegerWINE
+ *
+ * WGL_WINE_query_renderer: wglQueryCurrentRendererIntegerWINE
+ */
+static BOOL macdrv_wglQueryCurrentRendererIntegerWINE(GLenum attribute, GLuint *value)
+{
+    BOOL ret = FALSE;
+    struct wgl_context *context = NtCurrentTeb()->glContext;
+    CGLPixelFormatObj pixel_format;
+    CGLError err;
+    GLint virtual_screen;
+    GLint display_mask;
+    GLint pf_renderer_id;
+    CGLRendererInfoObj renderer_info;
+    GLint renderer_count;
+    GLint renderer;
+
+    TRACE("context %p/%p/%p attribute 0x%04x value %p\n", context, (context ? context->context : NULL),
+          (context ? context->cglcontext : NULL), attribute, value);
+
+    if (attribute == WGL_RENDERER_VERSION_WINE)
+    {
+        if (!parse_renderer_version((const char*)opengl_funcs.gl.p_glGetString(GL_VERSION), value))
+            get_fallback_renderer_version(value);
+        TRACE("WGL_RENDERER_VERSION_WINE -> %u.%u.%u\n", value[0], value[1], value[2]);
+        return TRUE;
+    }
+
+    pixel_format = CGLGetPixelFormat(context->cglcontext);
+    err = CGLGetVirtualScreen(context->cglcontext, &virtual_screen);
+    if (err != kCGLNoError)
+    {
+        WARN("CGLGetVirtualScreen failed: %d %s\n", err, CGLErrorString(err));
+        return FALSE;
+    }
+
+    err = CGLDescribePixelFormat(pixel_format, virtual_screen, kCGLPFADisplayMask, &display_mask);
+    if (err != kCGLNoError)
+    {
+        WARN("CGLDescribePixelFormat(kCGLPFADisplayMask) failed: %d %s\n", err, CGLErrorString(err));
+        return FALSE;
+    }
+
+    err = CGLDescribePixelFormat(pixel_format, virtual_screen, kCGLPFARendererID, &pf_renderer_id);
+    if (err != kCGLNoError)
+    {
+        WARN("CGLDescribePixelFormat(kCGLPFARendererID) failed: %d %s\n", err, CGLErrorString(err));
+        return FALSE;
+    }
+
+    err = CGLQueryRendererInfo(display_mask, &renderer_info, &renderer_count);
+    if (err != kCGLNoError)
+    {
+        WARN("CGLQueryRendererInfo failed: %d %s\n", err, CGLErrorString(err));
+        return FALSE;
+    }
+
+    for (renderer = 0; renderer < renderer_count; renderer++)
+    {
+        GLint renderer_id;
+
+        if (!get_renderer_property(renderer_info, renderer, kCGLRPRendererID, &renderer_id))
+            continue;
+
+        if (renderer_id == pf_renderer_id)
+        {
+            ret = query_renderer_integer(renderer_info, renderer, attribute, value);
+            break;
+        }
+    }
+
+    if (renderer >= renderer_count)
+        ERR("failed to find renderer ID 0x%08x for display mask 0x%08x\n", pf_renderer_id, display_mask);
+
+    CGLDestroyRendererInfo(renderer_info);
+    return ret;
+}
+
+
+/**********************************************************************
+ *              macdrv_wglQueryCurrentRendererStringWINE
+ *
+ * WGL_WINE_query_renderer: wglQueryCurrentRendererStringWINE
+ */
+static const char *macdrv_wglQueryCurrentRendererStringWINE(GLenum attribute)
+{
+    const char* ret = NULL;
+    struct wgl_context *context = NtCurrentTeb()->glContext;
+
+    TRACE("context %p/%p/%p attribute 0x%04x\n", context, (context ? context->context : NULL),
+          (context ? context->cglcontext : NULL), attribute);
+
+    switch (attribute)
+    {
+        case WGL_RENDERER_DEVICE_ID_WINE:
+        {
+            ret = (const char*)opengl_funcs.gl.p_glGetString(GL_RENDERER);
+            TRACE("WGL_RENDERER_DEVICE_ID_WINE -> %s\n", debugstr_a(ret));
+            break;
+        }
+
+        case WGL_RENDERER_VENDOR_ID_WINE:
+        {
+            ret = (const char*)opengl_funcs.gl.p_glGetString(GL_VENDOR);
+            TRACE("WGL_RENDERER_VENDOR_ID_WINE -> %s\n", debugstr_a(ret));
+            break;
+        }
+
+        default:
+            FIXME("unrecognized attribute 0x%04x\n", attribute);
+            break;
+    }
+
+    return ret;
+}
+
+
+/**********************************************************************
  *              macdrv_wglQueryPbufferARB
  *
  * WGL_ARB_pbuffer: wglQueryPbufferARB
@@ -3262,6 +3880,99 @@ static BOOL macdrv_wglQueryPbufferARB(struct wgl_pbuffer *pbuffer, int iAttribut
 
 
 /**********************************************************************
+ *              macdrv_wglQueryRendererIntegerWINE
+ *
+ * WGL_WINE_query_renderer: wglQueryRendererIntegerWINE
+ */
+static BOOL macdrv_wglQueryRendererIntegerWINE(HDC dc, GLint renderer, GLenum attribute, GLuint *value)
+{
+    BOOL ret = FALSE;
+    CGLRendererInfoObj renderer_info;
+    GLint renderer_count;
+    CGLError err;
+
+    TRACE("dc %p renderer %d attribute 0x%04x value %p\n", dc, renderer, attribute, value);
+
+    err = CGLQueryRendererInfo(active_displays_mask(), &renderer_info, &renderer_count);
+    if (err != kCGLNoError)
+    {
+        WARN("CGLQueryRendererInfo failed: %d %s\n", err, CGLErrorString(err));
+        return FALSE;
+    }
+
+    renderer = map_renderer_index(renderer_info, renderer_count, renderer);
+
+    if (renderer < renderer_count)
+        ret = query_renderer_integer(renderer_info, renderer, attribute, value);
+    else
+        TRACE("requested information for renderer %d exceeding count %d\n", renderer, renderer_count);
+
+    CGLDestroyRendererInfo(renderer_info);
+    return ret;
+}
+
+
+/**********************************************************************
+ *              macdrv_wglQueryRendererStringWINE
+ *
+ * WGL_WINE_query_renderer: wglQueryRendererStringWINE
+ */
+static const char *macdrv_wglQueryRendererStringWINE(HDC dc, GLint renderer, GLenum attribute)
+{
+    const char* ret = NULL;
+    CGLRendererInfoObj renderer_info;
+    GLint renderer_count;
+    CGLError err;
+
+    TRACE("dc %p renderer %d attribute 0x%04x\n", dc, renderer, attribute);
+
+    err = CGLQueryRendererInfo(active_displays_mask(), &renderer_info, &renderer_count);
+    if (err != kCGLNoError)
+    {
+        WARN("CGLQueryRendererInfo failed: %d %s\n", err, CGLErrorString(err));
+        return FALSE;
+    }
+
+    renderer = map_renderer_index(renderer_info, renderer_count, renderer);
+
+    if (renderer >= renderer_count)
+    {
+        TRACE("requested information for renderer %d exceeding count %d\n", renderer, renderer_count);
+        goto done;
+    }
+
+    switch (attribute)
+    {
+        case WGL_RENDERER_DEVICE_ID_WINE:
+        case WGL_RENDERER_VENDOR_ID_WINE:
+        {
+            BOOL device = (attribute == WGL_RENDERER_DEVICE_ID_WINE);
+            CGLPixelFormatObj pixel_format = create_pixel_format_for_renderer(renderer_info, renderer, TRUE);
+
+            if (!pixel_format)
+                pixel_format = create_pixel_format_for_renderer(renderer_info, renderer, FALSE);
+            if (pixel_format)
+            {
+                ret = get_gl_string(pixel_format, device ? GL_RENDERER : GL_VENDOR);
+                CGLReleasePixelFormat(pixel_format);
+            }
+
+            TRACE("%s -> %s\n", device ? "WGL_RENDERER_DEVICE_ID_WINE" : "WGL_RENDERER_VENDOR_ID_WINE", debugstr_a(ret));
+            break;
+        }
+
+        default:
+            FIXME("unrecognized attribute 0x%04x\n", attribute);
+            break;
+    }
+
+done:
+    CGLDestroyRendererInfo(renderer_info);
+    return ret;
+}
+
+
+/**********************************************************************
  *              macdrv_wglReleasePbufferDCARB
  *
  * WGL_ARB_pbuffer: wglReleasePbufferDCARB
@@ -3549,6 +4260,12 @@ static void load_extensions(void)
      */
     register_extension("WGL_WINE_pixel_format_passthrough");
     opengl_funcs.ext.p_wglSetPixelFormatWINE = macdrv_wglSetPixelFormatWINE;
+
+    register_extension("WGL_WINE_query_renderer");
+    opengl_funcs.ext.p_wglQueryCurrentRendererIntegerWINE = macdrv_wglQueryCurrentRendererIntegerWINE;
+    opengl_funcs.ext.p_wglQueryCurrentRendererStringWINE = macdrv_wglQueryCurrentRendererStringWINE;
+    opengl_funcs.ext.p_wglQueryRendererIntegerWINE = macdrv_wglQueryRendererIntegerWINE;
+    opengl_funcs.ext.p_wglQueryRendererStringWINE = macdrv_wglQueryRendererStringWINE;
 }
 
 
-- 
2.6.0




More information about the wine-patches mailing list