mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2025-08-29 02:33:58 +02:00
2126 lines
75 KiB
C
2126 lines
75 KiB
C
/*
|
|
* Copyright 2012 Alexandre Julliard
|
|
* Copyright 2025 Rémi Bernon for CodeWeavers
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
#if 0
|
|
#pragma makedep unix
|
|
#endif
|
|
|
|
#include "config.h"
|
|
|
|
#include <assert.h>
|
|
#include <pthread.h>
|
|
#include <dlfcn.h>
|
|
|
|
#include "ntstatus.h"
|
|
#define WIN32_NO_STATUS
|
|
#include "ntgdi_private.h"
|
|
#include "win32u_private.h"
|
|
#include "ntuser_private.h"
|
|
|
|
#include "wine/opengl_driver.h"
|
|
|
|
#include "dibdrv/dibdrv.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(wgl);
|
|
|
|
struct wgl_pbuffer
|
|
{
|
|
struct opengl_drawable *drawable;
|
|
|
|
HDC hdc;
|
|
GLsizei width;
|
|
GLsizei height;
|
|
GLenum texture_format;
|
|
GLenum texture_target;
|
|
GLint mipmap_level;
|
|
GLenum cube_face;
|
|
};
|
|
|
|
static const struct opengl_driver_funcs nulldrv_funcs, *driver_funcs = &nulldrv_funcs;
|
|
static const struct opengl_funcs *default_funcs; /* default GL function table from opengl32 */
|
|
static struct egl_platform display_egl;
|
|
static struct opengl_funcs display_funcs;
|
|
|
|
static struct wgl_pixel_format *pixel_formats;
|
|
static UINT formats_count, onscreen_count;
|
|
static char wgl_extensions[4096];
|
|
|
|
static BOOL has_extension( const char *list, const char *ext )
|
|
{
|
|
size_t len = strlen( ext );
|
|
const char *cur = list;
|
|
|
|
while (cur && (cur = strstr( cur, ext )))
|
|
{
|
|
if ((!cur[len] || cur[len] == ' ') && (cur == list || cur[-1] == ' ')) return TRUE;
|
|
cur = strchr( cur, ' ' );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void dump_extensions( const char *list )
|
|
{
|
|
const char *start, *end, *ptr;
|
|
|
|
for (start = end = ptr = list; ptr; ptr = strchr( ptr + 1, ' ' ))
|
|
{
|
|
if (ptr - start <= 128) end = ptr;
|
|
else
|
|
{
|
|
TRACE( "%.*s\n", (int)(end - start), start );
|
|
start = end + 1;
|
|
}
|
|
}
|
|
|
|
TRACE( "%s\n", start );
|
|
}
|
|
|
|
static void register_extension( char *list, size_t size, const char *name )
|
|
{
|
|
if (!has_extension( list, name ))
|
|
{
|
|
size_t len = strlen( list );
|
|
assert( size - len >= strlen( name ) + 1 );
|
|
if (*list) strcat( list + len, " " );
|
|
strcat( list + len, name );
|
|
}
|
|
}
|
|
|
|
void *opengl_drawable_create( UINT size, const struct opengl_drawable_funcs *funcs, int format, struct client_surface *client )
|
|
{
|
|
struct opengl_drawable *drawable;
|
|
|
|
if (!(drawable = calloc( 1, size ))) return NULL;
|
|
drawable->funcs = funcs;
|
|
drawable->ref = 1;
|
|
|
|
drawable->format = format;
|
|
drawable->interval = INT_MIN;
|
|
drawable->doublebuffer = !!(pixel_formats[format - 1].pfd.dwFlags & PFD_DOUBLEBUFFER);
|
|
drawable->stereo = !!(pixel_formats[format - 1].pfd.dwFlags & PFD_STEREO);
|
|
if ((drawable->client = client)) client_surface_add_ref( client );
|
|
|
|
TRACE( "created %s\n", debugstr_opengl_drawable( drawable ) );
|
|
return drawable;
|
|
}
|
|
|
|
void opengl_drawable_add_ref( struct opengl_drawable *drawable )
|
|
{
|
|
ULONG ref = InterlockedIncrement( &drawable->ref );
|
|
TRACE( "%s increasing refcount to %u\n", debugstr_opengl_drawable( drawable ), ref );
|
|
}
|
|
|
|
void opengl_drawable_release( struct opengl_drawable *drawable )
|
|
{
|
|
ULONG ref = InterlockedDecrement( &drawable->ref );
|
|
TRACE( "%s decreasing refcount to %u\n", debugstr_opengl_drawable( drawable ), ref );
|
|
|
|
if (!ref)
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
const struct egl_platform *egl = &display_egl;
|
|
|
|
drawable->funcs->destroy( drawable );
|
|
if (drawable->surface) funcs->p_eglDestroySurface( egl->display, drawable->surface );
|
|
if (drawable->client) client_surface_release( drawable->client );
|
|
free( drawable );
|
|
}
|
|
}
|
|
|
|
static void opengl_drawable_flush( struct opengl_drawable *drawable, int interval, UINT flags )
|
|
{
|
|
if (!drawable->client) return;
|
|
|
|
if (InterlockedCompareExchange( &drawable->client->updated, 0, 1 )) flags |= GL_FLUSH_UPDATED;
|
|
if (interval != drawable->interval)
|
|
{
|
|
drawable->interval = interval;
|
|
flags = GL_FLUSH_INTERVAL;
|
|
}
|
|
|
|
if (flags || InterlockedCompareExchange( &drawable->client->offscreen, 0, 0 ))
|
|
drawable->funcs->flush( drawable, flags );
|
|
}
|
|
|
|
#ifdef SONAME_LIBEGL
|
|
|
|
struct framebuffer_surface
|
|
{
|
|
struct opengl_drawable base;
|
|
};
|
|
|
|
static GLenum color_format_from_pfd( const struct wgl_pixel_format *desc )
|
|
{
|
|
TRACE( "format type %u bits %u/%u/%u/%u\n", desc->pixel_type, desc->pfd.cRedBits,
|
|
desc->pfd.cGreenBits, desc->pfd.cBlueBits, desc->pfd.cAlphaBits );
|
|
|
|
if (desc->pixel_type == WGL_TYPE_RGBA_FLOAT_ARB)
|
|
{
|
|
if (desc->pfd.cAlphaBits == 32) return GL_RGBA32F;
|
|
if (desc->pfd.cAlphaBits == 16) return GL_RGBA16F;
|
|
if (desc->pfd.cBlueBits == 32) return GL_RGB32F;
|
|
if (desc->pfd.cBlueBits == 16) return GL_RGB16F;
|
|
if (desc->pfd.cGreenBits == 32) return GL_RG32F;
|
|
if (desc->pfd.cGreenBits == 16) return GL_RG16F;
|
|
if (desc->pfd.cRedBits == 32) return GL_R32F;
|
|
if (desc->pfd.cRedBits == 16) return GL_R16F;
|
|
}
|
|
else
|
|
{
|
|
if (desc->pfd.cBlueBits == 10 && desc->pfd.cGreenBits == 10 &&
|
|
desc->pfd.cRedBits == 10 && desc->pfd.cAlphaBits == 2)
|
|
return GL_RGB10_A2;
|
|
if (desc->pfd.cAlphaBits == 32) return GL_RGBA32UI;
|
|
if (desc->pfd.cAlphaBits == 16) return GL_RGBA16;
|
|
if (desc->pfd.cAlphaBits == 8) return GL_RGBA8;
|
|
if (desc->pfd.cAlphaBits == 4) return GL_RGBA4;
|
|
if (desc->pfd.cBlueBits == 32) return GL_RGB32UI;
|
|
if (desc->pfd.cBlueBits == 16) return GL_RGB16;
|
|
if (desc->pfd.cBlueBits == 8) return GL_RGB8;
|
|
if (desc->pfd.cBlueBits == 4) return GL_RGB4;
|
|
if (desc->pfd.cGreenBits == 32) return GL_RG32UI;
|
|
if (desc->pfd.cGreenBits == 16) return GL_RG16;
|
|
if (desc->pfd.cGreenBits == 8) return GL_RG8;
|
|
if (desc->pfd.cRedBits == 32) return GL_R32UI;
|
|
if (desc->pfd.cRedBits == 16) return GL_R16;
|
|
if (desc->pfd.cRedBits == 8) return GL_R8;
|
|
}
|
|
|
|
FIXME( "Unsupported format type %u bits %u/%u/%u/%u\n", desc->pixel_type, desc->pfd.cRedBits,
|
|
desc->pfd.cGreenBits, desc->pfd.cBlueBits, desc->pfd.cAlphaBits );
|
|
return 0;
|
|
}
|
|
|
|
static GLenum depth_format_from_pfd( const struct wgl_pixel_format *desc )
|
|
{
|
|
TRACE( "format bits %u/%u\n", desc->pfd.cStencilBits, desc->pfd.cDepthBits );
|
|
|
|
if (desc->pfd.cStencilBits)
|
|
{
|
|
if (desc->pfd.cDepthBits == 32) return GL_DEPTH32F_STENCIL8;
|
|
if (desc->pfd.cDepthBits == 24) return GL_DEPTH24_STENCIL8;
|
|
}
|
|
else
|
|
{
|
|
if (desc->pfd.cDepthBits == 32) return GL_DEPTH_COMPONENT32;
|
|
if (desc->pfd.cDepthBits == 24) return GL_DEPTH_COMPONENT24;
|
|
if (desc->pfd.cDepthBits == 16) return GL_DEPTH_COMPONENT16;
|
|
}
|
|
|
|
FIXME( "Unsupported format bits %u/%u\n", desc->pfd.cStencilBits, desc->pfd.cDepthBits );
|
|
return 0;
|
|
}
|
|
|
|
static GLuint create_framebuffer( struct opengl_drawable *drawable, const struct wgl_pixel_format *desc )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
GLuint count = 1, fbo, name;
|
|
|
|
if (drawable->doublebuffer) count *= 2;
|
|
if (drawable->stereo) count *= 2;
|
|
|
|
funcs->p_glCreateFramebuffers( 1, &fbo );
|
|
|
|
for (GLuint i = 0; i < count; i++)
|
|
{
|
|
funcs->p_glCreateRenderbuffers( 1, &name );
|
|
funcs->p_glNamedFramebufferRenderbuffer( fbo, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, name );
|
|
TRACE( "drawable %p/%u created color buffer %#x/%u\n", drawable, fbo, GL_COLOR_ATTACHMENT0 + i, name );
|
|
}
|
|
|
|
if (desc->pfd.cDepthBits)
|
|
{
|
|
funcs->p_glCreateRenderbuffers( 1, &name );
|
|
funcs->p_glNamedFramebufferRenderbuffer( fbo, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, name );
|
|
if (desc->pfd.cStencilBits) funcs->p_glNamedFramebufferRenderbuffer( fbo, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, name );
|
|
TRACE( "drawable %p/%u created depth buffer %u\n", drawable, fbo, name );
|
|
}
|
|
|
|
funcs->p_glNamedFramebufferDrawBuffer( fbo, GL_COLOR_ATTACHMENT0 );
|
|
funcs->p_glNamedFramebufferReadBuffer( fbo, drawable->doublebuffer ? GL_COLOR_ATTACHMENT1 : GL_COLOR_ATTACHMENT0 );
|
|
TRACE( "drawable %p created framebuffer %u\n", drawable, fbo );
|
|
|
|
return fbo;
|
|
}
|
|
|
|
static void resize_framebuffer( struct opengl_drawable *drawable, const struct wgl_pixel_format *desc, GLuint fbo,
|
|
int width, int height )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
GLuint count = 1, name;
|
|
GLenum ret;
|
|
|
|
if (drawable->doublebuffer) count *= 2;
|
|
if (drawable->stereo) count *= 2;
|
|
|
|
for (GLuint i = 0; i < count; i++)
|
|
{
|
|
funcs->p_glGetNamedFramebufferAttachmentParameteriv( fbo, GL_COLOR_ATTACHMENT0 + i, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&name );
|
|
funcs->p_glNamedRenderbufferStorageMultisample( name, desc->samples, color_format_from_pfd( desc ), width, height );
|
|
TRACE( "drawable %p/%u resized color buffer %#x/%u to %d,%d\n", drawable, fbo, GL_COLOR_ATTACHMENT0 + i, name, width, height );
|
|
}
|
|
|
|
if (desc->pfd.cDepthBits)
|
|
{
|
|
funcs->p_glGetNamedFramebufferAttachmentParameteriv( fbo, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&name );
|
|
funcs->p_glNamedRenderbufferStorageMultisample( name, desc->samples, depth_format_from_pfd( desc ), width, height );
|
|
TRACE( "drawable %p/%u resized depth buffer %u to %d,%d\n", drawable, fbo, name, width, height );
|
|
}
|
|
|
|
ret = funcs->p_glCheckNamedFramebufferStatus( fbo, GL_FRAMEBUFFER );
|
|
if (ret != GL_FRAMEBUFFER_COMPLETE) WARN( "glCheckNamedFramebufferStatus returned %#x\n", ret );
|
|
TRACE( "drawable %p/%u resized buffers to %d,%d\n", drawable, fbo, width, height );
|
|
}
|
|
|
|
static void destroy_framebuffer( struct opengl_drawable *drawable, const struct wgl_pixel_format *desc, GLuint fbo )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
GLuint count = 1, name;
|
|
|
|
if (drawable->doublebuffer) count *= 2;
|
|
if (drawable->stereo) count *= 2;
|
|
|
|
for (GLuint i = 0; i < count; i++)
|
|
{
|
|
funcs->p_glGetNamedFramebufferAttachmentParameteriv( fbo, GL_COLOR_ATTACHMENT0 + i, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&name );
|
|
funcs->p_glDeleteRenderbuffers( 1, &name );
|
|
TRACE( "drawable %p/%u destroyed color buffer %#x/%u\n", drawable, fbo, GL_COLOR_ATTACHMENT0 + i, name );
|
|
}
|
|
|
|
if (desc->pfd.cDepthBits)
|
|
{
|
|
funcs->p_glGetNamedFramebufferAttachmentParameteriv( fbo, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&name );
|
|
funcs->p_glDeleteRenderbuffers( 1, &name );
|
|
TRACE( "drawable %p/%u destroyed depth buffer %u\n", drawable, fbo, name );
|
|
}
|
|
|
|
funcs->p_glDeleteFramebuffers( 1, &fbo );
|
|
TRACE( "drawable %p destroyed framebuffer %u\n", drawable, fbo );
|
|
}
|
|
|
|
static void framebuffer_surface_destroy( struct opengl_drawable *drawable )
|
|
{
|
|
TRACE( "%s\n", debugstr_opengl_drawable( drawable ) );
|
|
}
|
|
|
|
static void framebuffer_surface_flush( struct opengl_drawable *drawable, UINT flags )
|
|
{
|
|
struct wgl_pixel_format draw_desc = pixel_formats[drawable->format - 1], read_desc = draw_desc;
|
|
RECT rect;
|
|
|
|
TRACE( "%s, flags %#x\n", debugstr_opengl_drawable( drawable ), flags );
|
|
|
|
NtUserGetClientRect( drawable->client->hwnd, &rect, NtUserGetDpiForWindow( drawable->client->hwnd ) );
|
|
if (!rect.right) rect.right = 1;
|
|
if (!rect.bottom) rect.bottom = 1;
|
|
|
|
read_desc.samples = read_desc.sample_buffers = 0;
|
|
|
|
if (flags & GL_FLUSH_WAS_CURRENT)
|
|
{
|
|
if (drawable->draw_fbo != drawable->read_fbo)
|
|
{
|
|
destroy_framebuffer( drawable, &draw_desc, drawable->draw_fbo );
|
|
drawable->draw_fbo = 0;
|
|
}
|
|
destroy_framebuffer( drawable, &read_desc, drawable->read_fbo );
|
|
drawable->read_fbo = 0;
|
|
}
|
|
|
|
if (flags & GL_FLUSH_SET_CURRENT)
|
|
{
|
|
drawable->read_fbo = create_framebuffer( drawable, &read_desc );
|
|
if (!drawable->read_fbo) ERR( "Failed to create read framebuffer object\n" );
|
|
|
|
if (!draw_desc.sample_buffers) drawable->draw_fbo = drawable->read_fbo;
|
|
else drawable->draw_fbo = create_framebuffer( drawable, &draw_desc );
|
|
if (!drawable->draw_fbo) ERR( "Failed to create draw framebuffer object\n" );
|
|
}
|
|
|
|
if ((flags & (GL_FLUSH_UPDATED | GL_FLUSH_SET_CURRENT)) && drawable->read_fbo)
|
|
{
|
|
TRACE( "Resizing drawable %p/%u to %ux%u\n", drawable, drawable->read_fbo, rect.right, rect.bottom );
|
|
resize_framebuffer( drawable, &read_desc, drawable->read_fbo, rect.right, rect.bottom );
|
|
|
|
if (drawable->draw_fbo != drawable->read_fbo)
|
|
{
|
|
TRACE( "Resizing drawable %p/%u to %ux%u\n", drawable, drawable->draw_fbo, rect.right, rect.bottom );
|
|
resize_framebuffer( drawable, &draw_desc, drawable->draw_fbo, rect.right, rect.bottom );
|
|
}
|
|
}
|
|
}
|
|
|
|
static BOOL framebuffer_surface_swap( struct opengl_drawable *drawable )
|
|
{
|
|
TRACE( "%s\n", debugstr_opengl_drawable( drawable ) );
|
|
return TRUE;
|
|
}
|
|
|
|
static const struct opengl_drawable_funcs framebuffer_surface_funcs =
|
|
{
|
|
.destroy = framebuffer_surface_destroy,
|
|
.flush = framebuffer_surface_flush,
|
|
.swap = framebuffer_surface_swap,
|
|
};
|
|
|
|
static struct opengl_drawable *framebuffer_surface_create( int format, struct client_surface *client )
|
|
{
|
|
struct framebuffer_surface *surface;
|
|
if (!(surface = opengl_drawable_create( sizeof(*surface), &framebuffer_surface_funcs, format, client ))) return NULL;
|
|
return &surface->base;
|
|
}
|
|
|
|
static const struct opengl_drawable_funcs egldrv_pbuffer_funcs;
|
|
|
|
static inline EGLConfig egl_config_for_format( const struct egl_platform *egl, int format )
|
|
{
|
|
assert(format > 0 && format <= 2 * egl->config_count);
|
|
if (format <= egl->config_count) return egl->configs[format - 1];
|
|
return egl->configs[format - egl->config_count - 1];
|
|
}
|
|
|
|
static void egldrv_init_egl_platform( struct egl_platform *platform )
|
|
{
|
|
platform->type = EGL_PLATFORM_SURFACELESS_MESA;
|
|
platform->native_display = 0;
|
|
}
|
|
|
|
static void *egldrv_get_proc_address( const char *name )
|
|
{
|
|
return display_funcs.p_eglGetProcAddress( name );
|
|
}
|
|
|
|
static UINT egldrv_init_pixel_formats( UINT *onscreen_count )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
struct egl_platform *egl = &display_egl;
|
|
EGLConfig *configs;
|
|
EGLint i, j, render, count;
|
|
|
|
funcs->p_eglGetConfigs( egl->display, NULL, 0, &count );
|
|
if (!(configs = malloc( count * sizeof(*configs) ))) return 0;
|
|
if (!funcs->p_eglGetConfigs( egl->display, configs, count, &count ) || !count)
|
|
{
|
|
ERR( "Failed to get any configs from eglChooseConfig\n" );
|
|
free( configs );
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0, j = 0; i < count; i++)
|
|
{
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_RENDERABLE_TYPE, &render );
|
|
if (render & EGL_OPENGL_BIT) configs[j++] = configs[i];
|
|
}
|
|
count = j;
|
|
|
|
if (TRACE_ON(wgl)) for (i = 0; i < count; i++)
|
|
{
|
|
EGLint id, type, visual_id, native, color, r, g, b, a, d, s;
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_NATIVE_VISUAL_ID, &visual_id );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_SURFACE_TYPE, &type );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_RENDERABLE_TYPE, &render );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_CONFIG_ID, &id );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_NATIVE_RENDERABLE, &native );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_COLOR_BUFFER_TYPE, &color );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_RED_SIZE, &r );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_GREEN_SIZE, &g );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_BLUE_SIZE, &b );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_ALPHA_SIZE, &a );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_DEPTH_SIZE, &d );
|
|
funcs->p_eglGetConfigAttrib( egl->display, configs[i], EGL_STENCIL_SIZE, &s );
|
|
TRACE( "%u: config %d id %d type %x visual %d native %d render %x colortype %d rgba %d,%d,%d,%d depth %u stencil %d\n",
|
|
count, i, id, type, visual_id, native, render, color, r, g, b, a, d, s );
|
|
}
|
|
|
|
egl->configs = configs;
|
|
egl->config_count = count;
|
|
*onscreen_count = count;
|
|
return 2 * count;
|
|
}
|
|
|
|
static BOOL describe_egl_config( EGLConfig config, struct wgl_pixel_format *fmt, BOOL onscreen )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
struct egl_platform *egl = &display_egl;
|
|
EGLint value, surface_type;
|
|
PIXELFORMATDESCRIPTOR *pfd = &fmt->pfd;
|
|
|
|
/* If we can't get basic information, there is no point continuing */
|
|
if (!funcs->p_eglGetConfigAttrib( egl->display, config, EGL_SURFACE_TYPE, &surface_type )) return FALSE;
|
|
if (egl->type == EGL_PLATFORM_SURFACELESS_MESA) surface_type |= EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
|
|
|
|
memset( fmt, 0, sizeof(*fmt) );
|
|
pfd->nSize = sizeof(*pfd);
|
|
pfd->nVersion = 1;
|
|
pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_SUPPORT_COMPOSITION;
|
|
if (onscreen)
|
|
{
|
|
pfd->dwFlags |= PFD_DOUBLEBUFFER;
|
|
if (surface_type & EGL_WINDOW_BIT) pfd->dwFlags |= PFD_DRAW_TO_WINDOW;
|
|
}
|
|
pfd->iPixelType = PFD_TYPE_RGBA;
|
|
pfd->iLayerType = PFD_MAIN_PLANE;
|
|
|
|
#define SET_ATTRIB( field, attrib ) \
|
|
value = 0; \
|
|
funcs->p_eglGetConfigAttrib( egl->display, config, attrib, &value ); \
|
|
pfd->field = value;
|
|
#define SET_ATTRIB_ARB( field, attrib ) \
|
|
if (!funcs->p_eglGetConfigAttrib( egl->display, config, attrib, &value )) value = -1; \
|
|
fmt->field = value;
|
|
|
|
/* Although the documentation describes cColorBits as excluding alpha, real
|
|
* drivers tend to return the full pixel size, so do the same. */
|
|
SET_ATTRIB( cColorBits, EGL_BUFFER_SIZE );
|
|
SET_ATTRIB( cRedBits, EGL_RED_SIZE );
|
|
SET_ATTRIB( cGreenBits, EGL_GREEN_SIZE );
|
|
SET_ATTRIB( cBlueBits, EGL_BLUE_SIZE );
|
|
SET_ATTRIB( cAlphaBits, EGL_ALPHA_SIZE );
|
|
/* Although we don't get information from EGL about the component shifts
|
|
* or the native format, the 0xARGB order is the most common. */
|
|
pfd->cBlueShift = 0;
|
|
pfd->cGreenShift = pfd->cBlueBits;
|
|
pfd->cRedShift = pfd->cGreenBits + pfd->cBlueBits;
|
|
if (!pfd->cAlphaBits) pfd->cAlphaShift = 0;
|
|
else pfd->cAlphaShift = pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits;
|
|
|
|
SET_ATTRIB( cDepthBits, EGL_DEPTH_SIZE );
|
|
SET_ATTRIB( cStencilBits, EGL_STENCIL_SIZE );
|
|
|
|
fmt->swap_method = WGL_SWAP_UNDEFINED_ARB;
|
|
|
|
if (funcs->p_eglGetConfigAttrib( egl->display, config, EGL_TRANSPARENT_TYPE, &value ))
|
|
{
|
|
switch (value)
|
|
{
|
|
case EGL_TRANSPARENT_RGB:
|
|
fmt->transparent = GL_TRUE;
|
|
break;
|
|
case EGL_NONE:
|
|
fmt->transparent = GL_FALSE;
|
|
break;
|
|
default:
|
|
ERR( "unexpected transparency type 0x%x\n", value );
|
|
fmt->transparent = -1;
|
|
break;
|
|
}
|
|
}
|
|
else fmt->transparent = -1;
|
|
|
|
if (!egl->has_EGL_EXT_pixel_format_float) fmt->pixel_type = WGL_TYPE_RGBA_ARB;
|
|
else if (funcs->p_eglGetConfigAttrib( egl->display, config, EGL_COLOR_COMPONENT_TYPE_EXT, &value ))
|
|
{
|
|
switch (value)
|
|
{
|
|
case EGL_COLOR_COMPONENT_TYPE_FIXED_EXT:
|
|
fmt->pixel_type = WGL_TYPE_RGBA_ARB;
|
|
break;
|
|
case EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT:
|
|
fmt->pixel_type = WGL_TYPE_RGBA_FLOAT_ARB;
|
|
break;
|
|
default:
|
|
ERR( "unexpected color component type 0x%x\n", value );
|
|
fmt->pixel_type = -1;
|
|
break;
|
|
}
|
|
}
|
|
else fmt->pixel_type = -1;
|
|
|
|
if (egl->force_pbuffer_formats) fmt->draw_to_pbuffer = TRUE;
|
|
else if (surface_type & EGL_PBUFFER_BIT) fmt->draw_to_pbuffer = TRUE;
|
|
if (fmt->draw_to_pbuffer) pfd->dwFlags |= PFD_DRAW_TO_BITMAP;
|
|
|
|
/* Use some arbitrary but reasonable limits (4096 is also Mesa's default) */
|
|
fmt->max_pbuffer_width = 4096;
|
|
fmt->max_pbuffer_height = 4096;
|
|
fmt->max_pbuffer_pixels = fmt->max_pbuffer_width * fmt->max_pbuffer_height;
|
|
|
|
if (funcs->p_eglGetConfigAttrib( egl->display, config, EGL_TRANSPARENT_RED_VALUE, &value ))
|
|
{
|
|
fmt->transparent_red_value_valid = GL_TRUE;
|
|
fmt->transparent_red_value = value;
|
|
}
|
|
if (funcs->p_eglGetConfigAttrib( egl->display, config, EGL_TRANSPARENT_GREEN_VALUE, &value ))
|
|
{
|
|
fmt->transparent_green_value_valid = GL_TRUE;
|
|
fmt->transparent_green_value = value;
|
|
}
|
|
if (funcs->p_eglGetConfigAttrib( egl->display, config, EGL_TRANSPARENT_BLUE_VALUE, &value ))
|
|
{
|
|
fmt->transparent_blue_value_valid = GL_TRUE;
|
|
fmt->transparent_blue_value = value;
|
|
}
|
|
fmt->transparent_alpha_value_valid = GL_TRUE;
|
|
fmt->transparent_alpha_value = 0;
|
|
fmt->transparent_index_value_valid = GL_TRUE;
|
|
fmt->transparent_index_value = 0;
|
|
|
|
SET_ATTRIB_ARB( sample_buffers, EGL_SAMPLE_BUFFERS );
|
|
SET_ATTRIB_ARB( samples, EGL_SAMPLES );
|
|
|
|
fmt->bind_to_texture_rgb = GL_TRUE;
|
|
fmt->bind_to_texture_rgba = GL_TRUE;
|
|
fmt->bind_to_texture_rectangle_rgb = GL_TRUE;
|
|
fmt->bind_to_texture_rectangle_rgba = GL_TRUE;
|
|
|
|
/* TODO: Support SRGB surfaces and enable the attribute */
|
|
fmt->framebuffer_srgb_capable = GL_FALSE;
|
|
|
|
fmt->float_components = GL_FALSE;
|
|
|
|
#undef SET_ATTRIB
|
|
#undef SET_ATTRIB_ARB
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL egldrv_describe_pixel_format( int format, struct wgl_pixel_format *desc )
|
|
{
|
|
struct egl_platform *egl = &display_egl;
|
|
int count = egl->config_count;
|
|
BOOL onscreen = TRUE;
|
|
|
|
if (--format < 0 || format > 2 * count) return FALSE;
|
|
if (format >= count) onscreen = FALSE;
|
|
return describe_egl_config( egl->configs[format % count], desc, onscreen );
|
|
}
|
|
|
|
static const char *egldrv_init_wgl_extensions( struct opengl_funcs *funcs )
|
|
{
|
|
return "";
|
|
}
|
|
|
|
static BOOL egldrv_surface_create( HWND hwnd, int format, struct opengl_drawable **drawable )
|
|
{
|
|
struct client_surface *client;
|
|
|
|
if (!(client = nulldrv_client_surface_create( hwnd ))) return FALSE;
|
|
*drawable = framebuffer_surface_create( format, client );
|
|
client_surface_release( client );
|
|
|
|
return !!*drawable;
|
|
}
|
|
|
|
static BOOL egldrv_pbuffer_create( HDC hdc, int format, BOOL largest, GLenum texture_format, GLenum texture_target,
|
|
GLint max_level, GLsizei *width, GLsizei *height, struct opengl_drawable **drawable )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
const struct egl_platform *egl = &display_egl;
|
|
EGLint attribs[13], *attrib = attribs;
|
|
struct opengl_drawable *gl;
|
|
|
|
TRACE( "hdc %p, format %d, largest %u, texture_format %#x, texture_target %#x, max_level %#x, width %d, height %d, drawable %p\n",
|
|
hdc, format, largest, texture_format, texture_target, max_level, *width, *height, drawable );
|
|
|
|
*attrib++ = EGL_WIDTH;
|
|
*attrib++ = *width;
|
|
*attrib++ = EGL_HEIGHT;
|
|
*attrib++ = *height;
|
|
if (largest)
|
|
{
|
|
*attrib++ = EGL_LARGEST_PBUFFER;
|
|
*attrib++ = 1;
|
|
}
|
|
switch (texture_format)
|
|
{
|
|
case 0: break;
|
|
case GL_RGB:
|
|
*attrib++ = EGL_TEXTURE_FORMAT;
|
|
*attrib++ = EGL_TEXTURE_RGB;
|
|
break;
|
|
case GL_RGBA:
|
|
*attrib++ = EGL_TEXTURE_FORMAT;
|
|
*attrib++ = EGL_TEXTURE_RGBA;
|
|
break;
|
|
default:
|
|
FIXME( "Unsupported format %#x\n", texture_format );
|
|
*attrib++ = EGL_TEXTURE_FORMAT;
|
|
*attrib++ = EGL_TEXTURE_RGBA;
|
|
break;
|
|
}
|
|
switch (texture_target)
|
|
{
|
|
case 0: break;
|
|
case GL_TEXTURE_2D:
|
|
*attrib++ = EGL_TEXTURE_TARGET;
|
|
*attrib++ = EGL_TEXTURE_2D;
|
|
break;
|
|
default:
|
|
FIXME( "Unsupported target %#x\n", texture_target );
|
|
*attrib++ = EGL_TEXTURE_TARGET;
|
|
*attrib++ = EGL_TEXTURE_2D;
|
|
break;
|
|
}
|
|
if (max_level)
|
|
{
|
|
*attrib++ = EGL_MIPMAP_TEXTURE;
|
|
*attrib++ = GL_TRUE;
|
|
}
|
|
*attrib++ = EGL_NONE;
|
|
|
|
if (!(gl = opengl_drawable_create( sizeof(*gl), &egldrv_pbuffer_funcs, format, NULL ))) return FALSE;
|
|
if (!(gl->surface = funcs->p_eglCreatePbufferSurface( egl->display, egl_config_for_format( egl, gl->format ), attribs )))
|
|
{
|
|
opengl_drawable_release( gl );
|
|
return FALSE;
|
|
}
|
|
|
|
funcs->p_eglQuerySurface( egl->display, gl->surface, EGL_WIDTH, width );
|
|
funcs->p_eglQuerySurface( egl->display, gl->surface, EGL_HEIGHT, height );
|
|
|
|
*drawable = gl;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL egldrv_pbuffer_updated( HDC hdc, struct opengl_drawable *drawable, GLenum cube_face, GLint mipmap_level )
|
|
{
|
|
return GL_TRUE;
|
|
}
|
|
|
|
static UINT egldrv_pbuffer_bind( HDC hdc, struct opengl_drawable *drawable, GLenum buffer )
|
|
{
|
|
return -1; /* use default implementation */
|
|
}
|
|
|
|
static BOOL egldrv_context_create( int format, void *share, const int *attribs, void **context )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
const struct egl_platform *egl = &display_egl;
|
|
EGLint egl_attribs[16], *attribs_end = egl_attribs;
|
|
|
|
TRACE( "format %d, share %p, attribs %p\n", format, share, attribs );
|
|
|
|
for (; attribs && attribs[0] != 0; attribs += 2)
|
|
{
|
|
EGLint name;
|
|
|
|
TRACE( "%#x %#x\n", attribs[0], attribs[1] );
|
|
|
|
/* Find the EGL attribute names corresponding to the WGL names.
|
|
* For all of the attributes below, the values match between the two
|
|
* systems, so we can use them directly. */
|
|
switch (attribs[0])
|
|
{
|
|
case WGL_CONTEXT_MAJOR_VERSION_ARB:
|
|
name = EGL_CONTEXT_MAJOR_VERSION_KHR;
|
|
break;
|
|
case WGL_CONTEXT_MINOR_VERSION_ARB:
|
|
name = EGL_CONTEXT_MINOR_VERSION_KHR;
|
|
break;
|
|
case WGL_CONTEXT_FLAGS_ARB:
|
|
name = EGL_CONTEXT_FLAGS_KHR;
|
|
break;
|
|
case WGL_CONTEXT_OPENGL_NO_ERROR_ARB:
|
|
name = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
|
|
break;
|
|
case WGL_CONTEXT_PROFILE_MASK_ARB:
|
|
if (attribs[1] & WGL_CONTEXT_ES2_PROFILE_BIT_EXT)
|
|
{
|
|
ERR( "OpenGL ES contexts are not supported\n" );
|
|
return FALSE;
|
|
}
|
|
name = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
|
|
break;
|
|
default:
|
|
name = EGL_NONE;
|
|
FIXME( "Unhandled attributes: %#x %#x\n", attribs[0], attribs[1] );
|
|
}
|
|
|
|
if (name != EGL_NONE)
|
|
{
|
|
EGLint *dst = egl_attribs;
|
|
/* Check if we have already set the same attribute and replace it. */
|
|
for (; dst != attribs_end && *dst != name; dst += 2) continue;
|
|
/* Our context attribute array should have enough space for all the
|
|
* attributes we support (we merge repetitions), plus EGL_NONE. */
|
|
assert( dst - egl_attribs <= ARRAY_SIZE(egl_attribs) - 3 );
|
|
dst[0] = name;
|
|
dst[1] = attribs[1];
|
|
if (dst == attribs_end) attribs_end += 2;
|
|
}
|
|
}
|
|
*attribs_end = EGL_NONE;
|
|
|
|
/* For now only OpenGL is supported. It's enough to set the API only for
|
|
* context creation, since:
|
|
* 1. the default API is EGL_OPENGL_ES_API
|
|
* 2. the EGL specification says in section 3.7:
|
|
* > EGL_OPENGL_API and EGL_OPENGL_ES_API are interchangeable for all
|
|
* > purposes except eglCreateContext.
|
|
*/
|
|
funcs->p_eglBindAPI( EGL_OPENGL_API );
|
|
*context = funcs->p_eglCreateContext( egl->display, EGL_NO_CONFIG_KHR, share, attribs ? egl_attribs : NULL );
|
|
TRACE( "Created context %p\n", *context );
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL egldrv_context_destroy( void *context )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
const struct egl_platform *egl = &display_egl;
|
|
|
|
funcs->p_eglDestroyContext( egl->display, context );
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL egldrv_make_current( struct opengl_drawable *draw, struct opengl_drawable *read, void *context )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
const struct egl_platform *egl = &display_egl;
|
|
|
|
TRACE( "draw %s, read %s, context %p\n", debugstr_opengl_drawable( draw ), debugstr_opengl_drawable( read ), context );
|
|
|
|
return funcs->p_eglMakeCurrent( egl->display, context ? draw->surface : EGL_NO_SURFACE, context ? read->surface : EGL_NO_SURFACE, context );
|
|
}
|
|
|
|
static void egldrv_pbuffer_destroy( struct opengl_drawable *drawable )
|
|
{
|
|
TRACE( "%s\n", debugstr_opengl_drawable( drawable ) );
|
|
}
|
|
|
|
static const struct opengl_drawable_funcs egldrv_pbuffer_funcs =
|
|
{
|
|
.destroy = egldrv_pbuffer_destroy,
|
|
};
|
|
|
|
static const struct opengl_driver_funcs egldrv_funcs =
|
|
{
|
|
.p_init_egl_platform = egldrv_init_egl_platform,
|
|
.p_get_proc_address = egldrv_get_proc_address,
|
|
.p_init_pixel_formats = egldrv_init_pixel_formats,
|
|
.p_describe_pixel_format = egldrv_describe_pixel_format,
|
|
.p_init_wgl_extensions = egldrv_init_wgl_extensions,
|
|
.p_surface_create = egldrv_surface_create,
|
|
.p_pbuffer_create = egldrv_pbuffer_create,
|
|
.p_pbuffer_updated = egldrv_pbuffer_updated,
|
|
.p_pbuffer_bind = egldrv_pbuffer_bind,
|
|
.p_context_create = egldrv_context_create,
|
|
.p_context_destroy = egldrv_context_destroy,
|
|
.p_make_current = egldrv_make_current,
|
|
};
|
|
|
|
static BOOL egl_init( const struct opengl_driver_funcs **driver_funcs )
|
|
{
|
|
struct opengl_funcs *funcs = &display_funcs;
|
|
const char *extensions;
|
|
|
|
if (!(funcs->egl_handle = dlopen( SONAME_LIBEGL, RTLD_NOW | RTLD_GLOBAL )))
|
|
{
|
|
ERR( "Failed to load %s: %s\n", SONAME_LIBEGL, dlerror() );
|
|
return FALSE;
|
|
}
|
|
|
|
#define LOAD_FUNCPTR( name ) \
|
|
if (!(funcs->p_##name = dlsym( funcs->egl_handle, #name ))) \
|
|
{ \
|
|
ERR( "Failed to find EGL function %s\n", #name ); \
|
|
goto failed; \
|
|
}
|
|
LOAD_FUNCPTR( eglGetProcAddress );
|
|
LOAD_FUNCPTR( eglQueryString );
|
|
#undef LOAD_FUNCPTR
|
|
|
|
if (!(extensions = funcs->p_eglQueryString( EGL_NO_DISPLAY, EGL_EXTENSIONS )))
|
|
{
|
|
ERR( "Failed to find client extensions\n" );
|
|
goto failed;
|
|
}
|
|
TRACE( "EGL client extensions:\n" );
|
|
dump_extensions( extensions );
|
|
|
|
#define CHECK_EXTENSION( ext ) \
|
|
if (!has_extension( extensions, #ext )) \
|
|
{ \
|
|
ERR( "Failed to find required extension %s\n", #ext ); \
|
|
goto failed; \
|
|
}
|
|
CHECK_EXTENSION( EGL_KHR_client_get_all_proc_addresses );
|
|
CHECK_EXTENSION( EGL_EXT_platform_base );
|
|
#undef CHECK_EXTENSION
|
|
|
|
#define USE_GL_FUNC( func ) \
|
|
if (!funcs->p_##func && !(funcs->p_##func = (void *)funcs->p_eglGetProcAddress( #func ))) \
|
|
{ \
|
|
ERR( "Failed to load symbol %s\n", #func ); \
|
|
goto failed; \
|
|
}
|
|
ALL_EGL_FUNCS
|
|
#undef USE_GL_FUNC
|
|
|
|
*driver_funcs = &egldrv_funcs;
|
|
return TRUE;
|
|
|
|
failed:
|
|
dlclose( funcs->egl_handle );
|
|
funcs->egl_handle = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
static void init_egl_platform( struct egl_platform *egl, struct opengl_funcs *funcs,
|
|
const struct opengl_driver_funcs *driver_funcs )
|
|
{
|
|
const char *extensions;
|
|
EGLint major, minor;
|
|
|
|
if (!funcs->egl_handle || !driver_funcs->p_init_egl_platform) return;
|
|
|
|
driver_funcs->p_init_egl_platform( egl );
|
|
if (!egl->type) egl->display = funcs->p_eglGetDisplay( EGL_DEFAULT_DISPLAY );
|
|
else egl->display = funcs->p_eglGetPlatformDisplay( egl->type, egl->native_display, NULL );
|
|
|
|
if (!egl->display)
|
|
{
|
|
ERR( "Failed to open EGL display\n" );
|
|
return;
|
|
}
|
|
|
|
if (!funcs->p_eglInitialize( egl->display, &major, &minor )) return;
|
|
TRACE( "Initialized EGL display %p, version %d.%d\n", egl->display, major, minor );
|
|
|
|
if (!(extensions = funcs->p_eglQueryString( egl->display, EGL_EXTENSIONS ))) return;
|
|
TRACE( "EGL display extensions:\n" );
|
|
dump_extensions( extensions );
|
|
|
|
#define CHECK_EXTENSION( ext ) \
|
|
if (!has_extension( extensions, #ext )) \
|
|
{ \
|
|
ERR( "Failed to find required extension %s\n", #ext ); \
|
|
return; \
|
|
}
|
|
CHECK_EXTENSION( EGL_KHR_create_context );
|
|
CHECK_EXTENSION( EGL_KHR_create_context_no_error );
|
|
CHECK_EXTENSION( EGL_KHR_no_config_context );
|
|
#undef CHECK_EXTENSION
|
|
|
|
egl->has_EGL_EXT_present_opaque = has_extension( extensions, "EGL_EXT_present_opaque" );
|
|
egl->has_EGL_EXT_pixel_format_float = has_extension( extensions, "EGL_EXT_pixel_format_float" );
|
|
}
|
|
|
|
#else /* SONAME_LIBEGL */
|
|
|
|
static BOOL egl_init( const struct opengl_driver_funcs **driver_funcs )
|
|
{
|
|
WARN( "EGL support not compiled in!\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
static void init_egl_platform( struct egl_platform *egl, struct opengl_funcs *funcs,
|
|
const struct opengl_driver_funcs *driver_funcs )
|
|
{
|
|
}
|
|
|
|
#endif /* SONAME_LIBEGL */
|
|
|
|
static const struct
|
|
{
|
|
BYTE color_bits;
|
|
BYTE red_bits, red_shift;
|
|
BYTE green_bits, green_shift;
|
|
BYTE blue_bits, blue_shift;
|
|
BYTE alpha_bits, alpha_shift;
|
|
BYTE accum_bits;
|
|
BYTE depth_bits;
|
|
BYTE stencil_bits;
|
|
} nulldrv_pixel_formats[] =
|
|
{
|
|
{ 32, 8, 16, 8, 8, 8, 0, 8, 24, 16, 32, 8 },
|
|
{ 32, 8, 16, 8, 8, 8, 0, 8, 24, 16, 16, 8 },
|
|
{ 32, 8, 0, 8, 8, 8, 16, 8, 24, 16, 32, 8 },
|
|
{ 32, 8, 0, 8, 8, 8, 16, 8, 24, 16, 16, 8 },
|
|
{ 32, 8, 8, 8, 16, 8, 24, 8, 0, 16, 32, 8 },
|
|
{ 32, 8, 8, 8, 16, 8, 24, 8, 0, 16, 16, 8 },
|
|
{ 24, 8, 0, 8, 8, 8, 16, 0, 0, 16, 32, 8 },
|
|
{ 24, 8, 0, 8, 8, 8, 16, 0, 0, 16, 16, 8 },
|
|
{ 24, 8, 16, 8, 8, 8, 0, 0, 0, 16, 32, 8 },
|
|
{ 24, 8, 16, 8, 8, 8, 0, 0, 0, 16, 16, 8 },
|
|
{ 16, 5, 0, 6, 5, 5, 11, 0, 0, 16, 32, 8 },
|
|
{ 16, 5, 0, 6, 5, 5, 11, 0, 0, 16, 16, 8 },
|
|
};
|
|
|
|
static void *nulldrv_get_proc_address( const char *name )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static UINT nulldrv_init_pixel_formats( UINT *onscreen_count )
|
|
{
|
|
*onscreen_count = ARRAY_SIZE(nulldrv_pixel_formats);
|
|
return ARRAY_SIZE(nulldrv_pixel_formats);
|
|
}
|
|
|
|
static BOOL nulldrv_describe_pixel_format( int format, struct wgl_pixel_format *descr )
|
|
{
|
|
if (format <= 0 || format > ARRAY_SIZE(nulldrv_pixel_formats)) return FALSE;
|
|
|
|
memset( descr, 0, sizeof(*descr) );
|
|
descr->pfd.nSize = sizeof(*descr);
|
|
descr->pfd.nVersion = 1;
|
|
descr->pfd.dwFlags = PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP | PFD_GENERIC_FORMAT;
|
|
descr->pfd.iPixelType = PFD_TYPE_RGBA;
|
|
descr->pfd.cColorBits = nulldrv_pixel_formats[format - 1].color_bits;
|
|
descr->pfd.cRedBits = nulldrv_pixel_formats[format - 1].red_bits;
|
|
descr->pfd.cRedShift = nulldrv_pixel_formats[format - 1].red_shift;
|
|
descr->pfd.cGreenBits = nulldrv_pixel_formats[format - 1].green_bits;
|
|
descr->pfd.cGreenShift = nulldrv_pixel_formats[format - 1].green_shift;
|
|
descr->pfd.cBlueBits = nulldrv_pixel_formats[format - 1].blue_bits;
|
|
descr->pfd.cBlueShift = nulldrv_pixel_formats[format - 1].blue_shift;
|
|
descr->pfd.cAlphaBits = nulldrv_pixel_formats[format - 1].alpha_bits;
|
|
descr->pfd.cAlphaShift = nulldrv_pixel_formats[format - 1].alpha_shift;
|
|
descr->pfd.cAccumBits = nulldrv_pixel_formats[format - 1].accum_bits;
|
|
descr->pfd.cAccumRedBits = nulldrv_pixel_formats[format - 1].accum_bits / 4;
|
|
descr->pfd.cAccumGreenBits = nulldrv_pixel_formats[format - 1].accum_bits / 4;
|
|
descr->pfd.cAccumBlueBits = nulldrv_pixel_formats[format - 1].accum_bits / 4;
|
|
descr->pfd.cAccumAlphaBits = nulldrv_pixel_formats[format - 1].accum_bits / 4;
|
|
descr->pfd.cDepthBits = nulldrv_pixel_formats[format - 1].depth_bits;
|
|
descr->pfd.cStencilBits = nulldrv_pixel_formats[format - 1].stencil_bits;
|
|
descr->pfd.cAuxBuffers = 0;
|
|
descr->pfd.iLayerType = PFD_MAIN_PLANE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static const char *nulldrv_init_wgl_extensions( struct opengl_funcs *funcs )
|
|
{
|
|
return "";
|
|
}
|
|
|
|
static BOOL nulldrv_surface_create( HWND hwnd, int format, struct opengl_drawable **drawable )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL nulldrv_pbuffer_create( HDC hdc, int format, BOOL largest, GLenum texture_format, GLenum texture_target,
|
|
GLint max_level, GLsizei *width, GLsizei *height, struct opengl_drawable **drawable )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL nulldrv_pbuffer_updated( HDC hdc, struct opengl_drawable *drawable, GLenum cube_face, GLint mipmap_level )
|
|
{
|
|
return GL_TRUE;
|
|
}
|
|
|
|
static UINT nulldrv_pbuffer_bind( HDC hdc, struct opengl_drawable *drawable, GLenum buffer )
|
|
{
|
|
return -1; /* use default implementation */
|
|
}
|
|
|
|
static BOOL nulldrv_context_create( int format, void *share, const int *attribs, void **private )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL nulldrv_context_destroy( void *private )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL nulldrv_make_current( struct opengl_drawable *draw_base, struct opengl_drawable *read_base, void *private )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static const struct opengl_driver_funcs nulldrv_funcs =
|
|
{
|
|
.p_get_proc_address = nulldrv_get_proc_address,
|
|
.p_init_pixel_formats = nulldrv_init_pixel_formats,
|
|
.p_describe_pixel_format = nulldrv_describe_pixel_format,
|
|
.p_init_wgl_extensions = nulldrv_init_wgl_extensions,
|
|
.p_surface_create = nulldrv_surface_create,
|
|
.p_pbuffer_create = nulldrv_pbuffer_create,
|
|
.p_pbuffer_updated = nulldrv_pbuffer_updated,
|
|
.p_pbuffer_bind = nulldrv_pbuffer_bind,
|
|
.p_context_create = nulldrv_context_create,
|
|
.p_context_destroy = nulldrv_context_destroy,
|
|
.p_make_current = nulldrv_make_current,
|
|
};
|
|
|
|
static const char *win32u_wglGetExtensionsStringARB( HDC hdc )
|
|
{
|
|
TRACE( "hdc %p\n", hdc );
|
|
if (TRACE_ON(wgl)) dump_extensions( wgl_extensions );
|
|
return wgl_extensions;
|
|
}
|
|
|
|
static const char *win32u_wglGetExtensionsStringEXT(void)
|
|
{
|
|
TRACE( "\n" );
|
|
if (TRACE_ON(wgl)) dump_extensions( wgl_extensions );
|
|
return wgl_extensions;
|
|
}
|
|
|
|
static int get_dc_pixel_format( HDC hdc, BOOL internal )
|
|
{
|
|
int ret = 0;
|
|
HWND hwnd;
|
|
DC *dc;
|
|
|
|
if ((hwnd = NtUserWindowFromDC( hdc )))
|
|
ret = get_window_pixel_format( hwnd, internal );
|
|
else if ((dc = get_dc_ptr( hdc )))
|
|
{
|
|
BOOL is_display = dc->is_display;
|
|
ret = dc->pixel_format;
|
|
release_dc_ptr( dc );
|
|
|
|
/* Offscreen formats can't be used with traditional WGL calls. As has been
|
|
* verified on Windows GetPixelFormat doesn't fail but returns 1.
|
|
*/
|
|
if (is_display && ret >= 0 && ret > onscreen_count) ret = 1;
|
|
}
|
|
else
|
|
{
|
|
WARN( "Invalid DC handle %p\n", hdc );
|
|
RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
|
|
return -1;
|
|
}
|
|
|
|
TRACE( "%p/%p -> %d\n", hdc, hwnd, ret );
|
|
return ret;
|
|
}
|
|
|
|
static int win32u_wglGetPixelFormat( HDC hdc )
|
|
{
|
|
int format = get_dc_pixel_format( hdc, FALSE );
|
|
return format > 0 ? format : 0;
|
|
}
|
|
|
|
void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable )
|
|
{
|
|
void *old_drawable = NULL;
|
|
WND *win;
|
|
|
|
TRACE( "hwnd %p, new_drawable %s\n", hwnd, debugstr_opengl_drawable( new_drawable ) );
|
|
|
|
if ((win = get_win_ptr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS)
|
|
{
|
|
old_drawable = win->opengl_drawable;
|
|
if ((win->opengl_drawable = new_drawable)) opengl_drawable_add_ref( new_drawable );
|
|
release_win_ptr( win );
|
|
}
|
|
|
|
if (old_drawable) opengl_drawable_release( old_drawable );
|
|
}
|
|
|
|
struct opengl_drawable *get_window_opengl_drawable( HWND hwnd )
|
|
{
|
|
void *drawable = NULL;
|
|
WND *win;
|
|
|
|
if ((win = get_win_ptr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS)
|
|
{
|
|
if ((drawable = win->opengl_drawable)) opengl_drawable_add_ref( drawable );
|
|
release_win_ptr( win );
|
|
}
|
|
|
|
TRACE( "hwnd %p, drawable %s\n", hwnd, debugstr_opengl_drawable( drawable ) );
|
|
return drawable;
|
|
}
|
|
|
|
void set_dc_opengl_drawable( HDC hdc, struct opengl_drawable *new_drawable )
|
|
{
|
|
void *old_drawable = NULL;
|
|
DC *dc;
|
|
|
|
TRACE( "hdc %p, new_drawable %s\n", hdc, debugstr_opengl_drawable( new_drawable ) );
|
|
|
|
if ((dc = get_dc_ptr( hdc )))
|
|
{
|
|
old_drawable = dc->opengl_drawable;
|
|
if ((dc->opengl_drawable = new_drawable)) opengl_drawable_add_ref( new_drawable );
|
|
release_dc_ptr( dc );
|
|
}
|
|
|
|
if (old_drawable) opengl_drawable_release( old_drawable );
|
|
}
|
|
|
|
static struct opengl_drawable *get_dc_opengl_drawable( HDC hdc )
|
|
{
|
|
void *drawable = NULL;
|
|
DC *dc;
|
|
|
|
if ((dc = get_dc_ptr( hdc )))
|
|
{
|
|
if ((drawable = dc->opengl_drawable)) opengl_drawable_add_ref( drawable );
|
|
release_dc_ptr( dc );
|
|
}
|
|
|
|
TRACE( "hdc %p, drawable %s\n", hdc, debugstr_opengl_drawable( drawable ) );
|
|
return drawable;
|
|
}
|
|
|
|
static BOOL create_memory_pbuffer( HDC hdc, int format )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
dib_info dib = {.rect = {0, 0, 1, 1}};
|
|
BOOL ret = TRUE;
|
|
BITMAPOBJ *bmp;
|
|
DC *dc;
|
|
|
|
if (!(dc = get_dc_ptr( hdc ))) return FALSE;
|
|
else if (dc->opengl_drawable) ret = FALSE;
|
|
else if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC) ret = FALSE;
|
|
else if ((bmp = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP )))
|
|
{
|
|
init_dib_info_from_bitmapobj( &dib, bmp );
|
|
GDI_ReleaseObj( dc->hBitmap );
|
|
}
|
|
release_dc_ptr( dc );
|
|
|
|
if (ret && format)
|
|
{
|
|
int width = dib.rect.right - dib.rect.left, height = dib.rect.bottom - dib.rect.top;
|
|
struct wgl_pbuffer *pbuffer;
|
|
|
|
if (!(pbuffer = funcs->p_wglCreatePbufferARB( hdc, format, width, height, NULL )))
|
|
WARN( "Failed to create pbuffer for memory DC %p\n", hdc );
|
|
else
|
|
{
|
|
TRACE( "Created pbuffer %p for memory DC %p\n", pbuffer, hdc );
|
|
set_dc_opengl_drawable( hdc, pbuffer->drawable );
|
|
funcs->p_wglDestroyPbufferARB( pbuffer );
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL flush_memory_dc( struct wgl_context *context, HDC hdc, BOOL write, void (*flush)(void) )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
BOOL ret = TRUE;
|
|
BITMAPOBJ *bmp;
|
|
DC *dc;
|
|
|
|
if (!(dc = get_dc_ptr( hdc ))) return FALSE;
|
|
if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC) ret = FALSE;
|
|
else if (context && (bmp = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP )))
|
|
{
|
|
char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
|
|
BITMAPINFO *info = (BITMAPINFO *)buffer;
|
|
struct bitblt_coords src = {0};
|
|
struct gdi_image_bits bits;
|
|
|
|
if (flush) flush();
|
|
|
|
if (!get_image_from_bitmap( bmp, info, &bits, &src ))
|
|
{
|
|
int width = info->bmiHeader.biWidth, height = info->bmiHeader.biSizeImage / 4 / width;
|
|
if (write) funcs->p_glDrawPixels( width, height, GL_BGRA, GL_UNSIGNED_BYTE, bits.ptr );
|
|
else funcs->p_glReadPixels( 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, bits.ptr );
|
|
}
|
|
GDI_ReleaseObj( dc->hBitmap );
|
|
}
|
|
release_dc_ptr( dc );
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
UINT total, onscreen;
|
|
HWND hwnd;
|
|
|
|
funcs->p_get_pixel_formats( NULL, 0, &total, &onscreen );
|
|
if (new_format <= 0 || new_format > total) return FALSE;
|
|
|
|
if ((hwnd = NtUserWindowFromDC( hdc )))
|
|
{
|
|
struct opengl_drawable *drawable;
|
|
int old_format;
|
|
BOOL ret;
|
|
|
|
if (new_format > onscreen)
|
|
{
|
|
WARN( "Invalid format %d for %p/%p\n", new_format, hdc, hwnd );
|
|
return FALSE;
|
|
}
|
|
|
|
TRACE( "%p/%p format %d, internal %u\n", hdc, hwnd, new_format, internal );
|
|
|
|
if ((old_format = get_window_pixel_format( hwnd, FALSE )) && !internal) return old_format == new_format;
|
|
|
|
drawable = get_dc_opengl_drawable( hdc );
|
|
if ((ret = driver_funcs->p_surface_create( hwnd, new_format, &drawable )))
|
|
{
|
|
/* update the current window drawable to the last used draw surface */
|
|
if ((hwnd = NtUserWindowFromDC( hdc ))) set_window_opengl_drawable( hwnd, drawable );
|
|
set_dc_opengl_drawable( hdc, drawable );
|
|
}
|
|
if (drawable) opengl_drawable_release( drawable );
|
|
|
|
if (!ret) return FALSE;
|
|
return set_window_pixel_format( hwnd, new_format, internal );
|
|
}
|
|
|
|
TRACE( "%p/%p format %d, internal %u\n", hdc, hwnd, new_format, internal );
|
|
return NtGdiSetPixelFormat( hdc, new_format );
|
|
}
|
|
|
|
static BOOL win32u_wglSetPixelFormat( HDC hdc, int format, const PIXELFORMATDESCRIPTOR *pfd )
|
|
{
|
|
return set_dc_pixel_format( hdc, format, FALSE );
|
|
}
|
|
|
|
static BOOL win32u_wglSetPixelFormatWINE( HDC hdc, int format )
|
|
{
|
|
return set_dc_pixel_format( hdc, format, TRUE );
|
|
}
|
|
|
|
static PROC win32u_wglGetProcAddress( const char *name )
|
|
{
|
|
PROC ret;
|
|
if (!strncmp( name, "wgl", 3 )) return NULL;
|
|
ret = driver_funcs->p_get_proc_address( name );
|
|
TRACE( "%s -> %p\n", debugstr_a(name), ret );
|
|
return ret;
|
|
}
|
|
|
|
static void win32u_get_pixel_formats( struct wgl_pixel_format *formats, UINT max_formats,
|
|
UINT *num_formats, UINT *num_onscreen_formats )
|
|
{
|
|
memcpy( formats, pixel_formats, min( max_formats, formats_count ) * sizeof(*pixel_formats) );
|
|
*num_formats = formats_count;
|
|
*num_onscreen_formats = onscreen_count;
|
|
}
|
|
|
|
static void context_set_drawables( struct wgl_context *context, struct opengl_drawable *new_draw, struct opengl_drawable *new_read )
|
|
{
|
|
struct opengl_drawable *old_draw = context->draw, *old_read = context->read;
|
|
|
|
TRACE( "context %p new_draw %s new_read %s\n", context, debugstr_opengl_drawable(new_draw), debugstr_opengl_drawable(new_read) );
|
|
|
|
if ((context->draw = new_draw)) opengl_drawable_add_ref( new_draw );
|
|
if ((context->read = new_read)) opengl_drawable_add_ref( new_read );
|
|
if (old_draw) opengl_drawable_release( old_draw );
|
|
if (old_read) opengl_drawable_release( old_read );
|
|
}
|
|
|
|
static BOOL context_unset_current( struct wgl_context *context )
|
|
{
|
|
struct opengl_drawable *old_draw = context->draw, *old_read = context->read;
|
|
|
|
TRACE( "context %p\n", context );
|
|
|
|
opengl_drawable_flush( old_read, old_read->interval, GL_FLUSH_WAS_CURRENT );
|
|
if (old_read != old_draw) opengl_drawable_flush( old_draw, old_draw->interval, GL_FLUSH_WAS_CURRENT );
|
|
if (driver_funcs->p_make_current( NULL, NULL, NULL )) return TRUE;
|
|
opengl_drawable_flush( old_read, old_read->interval, GL_FLUSH_SET_CURRENT );
|
|
if (old_read != old_draw) opengl_drawable_flush( old_draw, old_draw->interval, GL_FLUSH_SET_CURRENT );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, HDC read_hdc )
|
|
{
|
|
struct wgl_context *previous = NtCurrentTeb()->glContext;
|
|
struct opengl_drawable *new_draw, *new_read;
|
|
BOOL ret = FALSE, flush;
|
|
HWND hwnd;
|
|
|
|
flush = create_memory_pbuffer( draw_hdc, context->format );
|
|
new_draw = get_dc_opengl_drawable( draw_hdc );
|
|
|
|
/* get the last used window drawable when reading */
|
|
if ((hwnd = NtUserWindowFromDC( read_hdc ))) new_read = get_window_opengl_drawable( hwnd );
|
|
else new_read = get_dc_opengl_drawable( read_hdc );
|
|
|
|
TRACE( "context %p, new_draw %s, new_read %s\n", context, debugstr_opengl_drawable( new_draw ), debugstr_opengl_drawable( new_read ) );
|
|
|
|
if (!new_draw || !new_read)
|
|
{
|
|
WARN( "One of the drawable has been lost, ignoring\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
if (previous == context && new_draw == context->draw && new_read == context->read) ret = TRUE;
|
|
else if (previous)
|
|
{
|
|
struct opengl_drawable *old_draw = previous->draw, *old_read = previous->read;
|
|
opengl_drawable_flush( old_read, old_read->interval, GL_FLUSH_WAS_CURRENT );
|
|
if (old_read != old_draw) opengl_drawable_flush( old_draw, old_draw->interval, GL_FLUSH_WAS_CURRENT );
|
|
}
|
|
|
|
if (!ret && (ret = driver_funcs->p_make_current( new_draw, new_read, context->driver_private )))
|
|
{
|
|
NtCurrentTeb()->glContext = context;
|
|
context_set_drawables( context, new_draw, new_read );
|
|
if (previous && previous != context) context_set_drawables( previous, NULL, NULL );
|
|
|
|
opengl_drawable_flush( new_read, new_read->interval, GL_FLUSH_SET_CURRENT );
|
|
if (new_read != new_draw) opengl_drawable_flush( new_draw, new_draw->interval, GL_FLUSH_SET_CURRENT );
|
|
}
|
|
|
|
if (ret)
|
|
{
|
|
opengl_drawable_flush( new_read, new_read->interval, 0 );
|
|
opengl_drawable_flush( new_draw, new_draw->interval, 0 );
|
|
/* update the current window drawable to the last used draw surface */
|
|
if ((hwnd = NtUserWindowFromDC( draw_hdc ))) set_window_opengl_drawable( hwnd, new_draw );
|
|
if (flush) flush_memory_dc( context, draw_hdc, TRUE, NULL );
|
|
}
|
|
else if (previous)
|
|
{
|
|
struct opengl_drawable *old_draw = previous->draw, *old_read = previous->read;
|
|
opengl_drawable_flush( old_read, old_read->interval, GL_FLUSH_SET_CURRENT );
|
|
if (old_read != old_draw) opengl_drawable_flush( old_draw, old_draw->interval, GL_FLUSH_SET_CURRENT );
|
|
}
|
|
|
|
opengl_drawable_release( new_draw );
|
|
opengl_drawable_release( new_read );
|
|
return ret;
|
|
}
|
|
|
|
static void push_internal_context( struct wgl_context *context, HDC hdc, int format )
|
|
{
|
|
TRACE( "context %p, hdc %p\n", context, hdc );
|
|
|
|
if (!context->internal_context)
|
|
{
|
|
driver_funcs->p_context_create( format, context->driver_private, NULL, &context->internal_context );
|
|
if (!context->internal_context) ERR( "Failed to create internal context\n" );
|
|
}
|
|
|
|
driver_funcs->p_make_current( context->draw, context->read, context->internal_context );
|
|
}
|
|
|
|
static void pop_internal_context( struct wgl_context *context )
|
|
{
|
|
TRACE( "context %p\n", context );
|
|
driver_funcs->p_make_current( context->draw, context->read, context->driver_private );
|
|
}
|
|
|
|
static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct wgl_context *context )
|
|
{
|
|
struct wgl_context *prev_context = NtCurrentTeb()->glContext;
|
|
int format;
|
|
|
|
TRACE( "draw_hdc %p, read_hdc %p, context %p\n", draw_hdc, read_hdc, context );
|
|
|
|
if (!context)
|
|
{
|
|
if (!(context = prev_context)) return TRUE;
|
|
if (!context_unset_current( context )) return FALSE;
|
|
NtCurrentTeb()->glContext = NULL;
|
|
context_set_drawables( context, NULL, NULL );
|
|
return TRUE;
|
|
}
|
|
|
|
if ((format = get_dc_pixel_format( draw_hdc, TRUE )) <= 0)
|
|
{
|
|
WARN( "Invalid draw_hdc %p format %u\n", draw_hdc, format );
|
|
if (!format) RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT );
|
|
return FALSE;
|
|
}
|
|
if (context->format != format)
|
|
{
|
|
WARN( "Mismatched draw_hdc %p format %u, context %p format %u\n", draw_hdc, format, context, context->format );
|
|
RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT );
|
|
return FALSE;
|
|
}
|
|
|
|
if (!context_sync_drawables( context, draw_hdc, read_hdc )) return FALSE;
|
|
NtCurrentTeb()->glContext = context;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL win32u_wglMakeCurrent( HDC hdc, struct wgl_context *context )
|
|
{
|
|
return win32u_wglMakeContextCurrentARB( hdc, hdc, context );
|
|
}
|
|
|
|
static struct wgl_pbuffer *win32u_wglCreatePbufferARB( HDC hdc, int format, int width, int height,
|
|
const int *attribs )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
UINT total, onscreen, size, max_level = 0;
|
|
struct wgl_pbuffer *pbuffer;
|
|
BOOL largest = FALSE;
|
|
|
|
TRACE( "(%p, %d, %d, %d, %p)\n", hdc, format, width, height, attribs );
|
|
|
|
funcs->p_get_pixel_formats( NULL, 0, &total, &onscreen );
|
|
if (format <= 0 || format > total)
|
|
{
|
|
RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT );
|
|
return NULL;
|
|
}
|
|
if (width <= 0 || height <= 0)
|
|
{
|
|
RtlSetLastWin32Error( ERROR_INVALID_DATA );
|
|
return NULL;
|
|
}
|
|
|
|
if (!(pbuffer = calloc( 1, sizeof(*pbuffer) )) || !(pbuffer->hdc = NtGdiOpenDCW( NULL, NULL, NULL, 0, TRUE, NULL, NULL, NULL )))
|
|
{
|
|
RtlSetLastWin32Error( ERROR_NO_SYSTEM_RESOURCES );
|
|
free( pbuffer );
|
|
return NULL;
|
|
}
|
|
NtGdiSetPixelFormat( pbuffer->hdc, format );
|
|
pbuffer->width = width;
|
|
pbuffer->height = height;
|
|
pbuffer->mipmap_level = -1;
|
|
|
|
for (; attribs && attribs[0]; attribs += 2)
|
|
{
|
|
switch (attribs[0])
|
|
{
|
|
case WGL_PBUFFER_LARGEST_ARB:
|
|
TRACE( "WGL_PBUFFER_LARGEST_ARB %#x\n", attribs[1] );
|
|
largest = !!attribs[1];
|
|
break;
|
|
|
|
case WGL_TEXTURE_FORMAT_ARB:
|
|
TRACE( "WGL_TEXTURE_FORMAT_ARB %#x\n", attribs[1] );
|
|
switch (attribs[1])
|
|
{
|
|
case WGL_NO_TEXTURE_ARB:
|
|
pbuffer->texture_format = 0;
|
|
break;
|
|
case WGL_TEXTURE_RGB_ARB:
|
|
pbuffer->texture_format = GL_RGB;
|
|
break;
|
|
case WGL_TEXTURE_RGBA_ARB:
|
|
pbuffer->texture_format = GL_RGBA;
|
|
break;
|
|
/* WGL_FLOAT_COMPONENTS_NV */
|
|
case WGL_TEXTURE_FLOAT_R_NV:
|
|
pbuffer->texture_format = GL_FLOAT_R_NV;
|
|
break;
|
|
case WGL_TEXTURE_FLOAT_RG_NV:
|
|
pbuffer->texture_format = GL_FLOAT_RG_NV;
|
|
break;
|
|
case WGL_TEXTURE_FLOAT_RGB_NV:
|
|
pbuffer->texture_format = GL_FLOAT_RGB_NV;
|
|
break;
|
|
case WGL_TEXTURE_FLOAT_RGBA_NV:
|
|
pbuffer->texture_format = GL_FLOAT_RGBA_NV;
|
|
break;
|
|
default:
|
|
FIXME( "Unknown texture format: %x\n", attribs[1] );
|
|
goto failed;
|
|
}
|
|
break;
|
|
|
|
case WGL_TEXTURE_TARGET_ARB:
|
|
TRACE( "WGL_TEXTURE_TARGET_ARB %#x\n", attribs[1] );
|
|
switch (attribs[1])
|
|
{
|
|
case WGL_NO_TEXTURE_ARB:
|
|
pbuffer->texture_target = 0;
|
|
break;
|
|
case WGL_TEXTURE_CUBE_MAP_ARB:
|
|
if (width != height) goto failed;
|
|
pbuffer->texture_target = GL_TEXTURE_CUBE_MAP;
|
|
break;
|
|
case WGL_TEXTURE_1D_ARB:
|
|
if (height != 1) goto failed;
|
|
pbuffer->texture_target = GL_TEXTURE_1D;
|
|
break;
|
|
case WGL_TEXTURE_2D_ARB:
|
|
pbuffer->texture_target = GL_TEXTURE_2D;
|
|
break;
|
|
case WGL_TEXTURE_RECTANGLE_NV:
|
|
pbuffer->texture_target = GL_TEXTURE_RECTANGLE_NV;
|
|
break;
|
|
default:
|
|
FIXME( "Unknown texture target: %x\n", attribs[1] );
|
|
goto failed;
|
|
}
|
|
break;
|
|
|
|
case WGL_MIPMAP_TEXTURE_ARB:
|
|
TRACE( "WGL_MIPMAP_TEXTURE_ARB %#x\n", attribs[1] );
|
|
if (attribs[1])
|
|
{
|
|
pbuffer->mipmap_level = max_level = 0;
|
|
for (size = min( width, height ) / 2; size; size /= 2) max_level++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
WARN( "attribute %#x %#x not handled\n", attribs[0], attribs[1] );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (driver_funcs->p_pbuffer_create( pbuffer->hdc, format, largest, pbuffer->texture_format,
|
|
pbuffer->texture_target, max_level, &pbuffer->width,
|
|
&pbuffer->height, &pbuffer->drawable ))
|
|
{
|
|
set_dc_opengl_drawable( pbuffer->hdc, pbuffer->drawable );
|
|
return pbuffer;
|
|
}
|
|
|
|
failed:
|
|
RtlSetLastWin32Error( ERROR_INVALID_DATA );
|
|
NtGdiDeleteObjectApp( pbuffer->hdc );
|
|
free( pbuffer );
|
|
return NULL;
|
|
}
|
|
|
|
static BOOL win32u_wglDestroyPbufferARB( struct wgl_pbuffer *pbuffer )
|
|
{
|
|
TRACE( "pbuffer %p\n", pbuffer );
|
|
|
|
opengl_drawable_release( pbuffer->drawable );
|
|
NtGdiDeleteObjectApp( pbuffer->hdc );
|
|
free( pbuffer );
|
|
|
|
return GL_TRUE;
|
|
}
|
|
|
|
static HDC win32u_wglGetPbufferDCARB( struct wgl_pbuffer *pbuffer )
|
|
{
|
|
TRACE( "pbuffer %p\n", pbuffer );
|
|
return pbuffer->hdc;
|
|
}
|
|
|
|
static int win32u_wglReleasePbufferDCARB( struct wgl_pbuffer *pbuffer, HDC hdc )
|
|
{
|
|
TRACE( "pbuffer %p, hdc %p\n", pbuffer, hdc );
|
|
|
|
if (hdc != pbuffer->hdc)
|
|
{
|
|
RtlSetLastWin32Error( ERROR_DC_NOT_FOUND );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL win32u_wglQueryPbufferARB( struct wgl_pbuffer *pbuffer, int attrib, int *value )
|
|
{
|
|
TRACE( "pbuffer %p, attrib %#x, value %p\n", pbuffer, attrib, value );
|
|
|
|
switch (attrib)
|
|
{
|
|
case WGL_PBUFFER_WIDTH_ARB:
|
|
*value = pbuffer->width;
|
|
break;
|
|
case WGL_PBUFFER_HEIGHT_ARB:
|
|
*value = pbuffer->height;
|
|
break;
|
|
case WGL_PBUFFER_LOST_ARB:
|
|
*value = GL_FALSE;
|
|
break;
|
|
|
|
case WGL_TEXTURE_FORMAT_ARB:
|
|
switch (pbuffer->texture_format)
|
|
{
|
|
case 0: *value = WGL_NO_TEXTURE_ARB; break;
|
|
case GL_RGB: *value = WGL_TEXTURE_RGB_ARB; break;
|
|
case GL_RGBA: *value = WGL_TEXTURE_RGBA_ARB; break;
|
|
/* WGL_FLOAT_COMPONENTS_NV */
|
|
case GL_FLOAT_R_NV: *value = WGL_TEXTURE_FLOAT_R_NV; break;
|
|
case GL_FLOAT_RG_NV: *value = WGL_TEXTURE_FLOAT_RG_NV; break;
|
|
case GL_FLOAT_RGB_NV: *value = WGL_TEXTURE_FLOAT_RGB_NV; break;
|
|
case GL_FLOAT_RGBA_NV: *value = WGL_TEXTURE_FLOAT_RGBA_NV; break;
|
|
default: ERR( "Unknown texture format: %x\n", pbuffer->texture_format );
|
|
}
|
|
break;
|
|
|
|
case WGL_TEXTURE_TARGET_ARB:
|
|
switch (pbuffer->texture_target)
|
|
{
|
|
case 0: *value = WGL_NO_TEXTURE_ARB; break;
|
|
case GL_TEXTURE_1D: *value = WGL_TEXTURE_1D_ARB; break;
|
|
case GL_TEXTURE_2D: *value = WGL_TEXTURE_2D_ARB; break;
|
|
case GL_TEXTURE_CUBE_MAP: *value = WGL_TEXTURE_CUBE_MAP_ARB; break;
|
|
case GL_TEXTURE_RECTANGLE_NV: *value = WGL_TEXTURE_RECTANGLE_NV; break;
|
|
}
|
|
break;
|
|
|
|
case WGL_MIPMAP_TEXTURE_ARB:
|
|
*value = pbuffer->mipmap_level >= 0;
|
|
break;
|
|
case WGL_MIPMAP_LEVEL_ARB:
|
|
*value = max( pbuffer->mipmap_level, 0 );
|
|
break;
|
|
case WGL_CUBE_MAP_FACE_ARB:
|
|
switch (pbuffer->cube_face)
|
|
{
|
|
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
|
default:
|
|
*value = WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
|
|
break;
|
|
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
|
*value = WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB;
|
|
break;
|
|
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
|
*value = WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB;
|
|
break;
|
|
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
|
*value = WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB;
|
|
break;
|
|
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
|
*value = WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB;
|
|
break;
|
|
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
|
*value = WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
FIXME( "unexpected attribute %x\n", attrib );
|
|
break;
|
|
}
|
|
|
|
return GL_TRUE;
|
|
}
|
|
|
|
static GLenum binding_from_target( GLenum target )
|
|
{
|
|
switch (target)
|
|
{
|
|
case GL_TEXTURE_CUBE_MAP: return GL_TEXTURE_BINDING_CUBE_MAP;
|
|
case GL_TEXTURE_1D: return GL_TEXTURE_BINDING_1D;
|
|
case GL_TEXTURE_2D: return GL_TEXTURE_BINDING_2D;
|
|
case GL_TEXTURE_RECTANGLE_NV: return GL_TEXTURE_BINDING_RECTANGLE_NV;
|
|
}
|
|
FIXME( "Unsupported target %#x\n", target );
|
|
return 0;
|
|
}
|
|
|
|
static BOOL win32u_wglBindTexImageARB( struct wgl_pbuffer *pbuffer, int buffer )
|
|
{
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
int prev_texture = 0, format = win32u_wglGetPixelFormat( pbuffer->hdc );
|
|
struct wgl_pixel_format desc;
|
|
GLenum source;
|
|
UINT ret;
|
|
|
|
TRACE( "pbuffer %p, buffer %d\n", pbuffer, buffer );
|
|
|
|
if (!pbuffer->texture_format)
|
|
{
|
|
RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
|
|
return GL_FALSE;
|
|
}
|
|
|
|
if (!driver_funcs->p_describe_pixel_format( format, &desc ))
|
|
{
|
|
RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT );
|
|
return FALSE;
|
|
}
|
|
|
|
switch (buffer)
|
|
{
|
|
case WGL_FRONT_LEFT_ARB:
|
|
if (desc.pfd.dwFlags & PFD_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 (desc.pfd.dwFlags & PFD_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 %#x\n", buffer );
|
|
RtlSetLastWin32Error( ERROR_INVALID_DATA );
|
|
return GL_FALSE;
|
|
|
|
default:
|
|
WARN( "Unknown source buffer %#x\n", buffer );
|
|
RtlSetLastWin32Error( ERROR_INVALID_DATA );
|
|
return GL_FALSE;
|
|
}
|
|
|
|
if ((ret = driver_funcs->p_pbuffer_bind( pbuffer->hdc, pbuffer->drawable, source )) != -1)
|
|
return ret;
|
|
|
|
funcs->p_glGetIntegerv( binding_from_target( pbuffer->texture_target ), &prev_texture );
|
|
push_internal_context( NtCurrentTeb()->glContext, pbuffer->hdc, format );
|
|
|
|
/* Make sure that the prev_texture is set as the current texture state isn't shared
|
|
* between contexts. After that copy the pbuffer texture data. */
|
|
funcs->p_glBindTexture( pbuffer->texture_target, prev_texture );
|
|
funcs->p_glCopyTexImage2D( pbuffer->texture_target, 0, pbuffer->texture_format, 0, 0,
|
|
pbuffer->width, pbuffer->height, 0 );
|
|
|
|
pop_internal_context( NtCurrentTeb()->glContext );
|
|
return GL_TRUE;
|
|
}
|
|
|
|
static BOOL win32u_wglReleaseTexImageARB( struct wgl_pbuffer *pbuffer, int buffer )
|
|
{
|
|
TRACE( "pbuffer %p, buffer %d\n", pbuffer, buffer );
|
|
|
|
if (!pbuffer->texture_format)
|
|
{
|
|
RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
|
|
return GL_FALSE;
|
|
}
|
|
|
|
return !!driver_funcs->p_pbuffer_bind( pbuffer->hdc, pbuffer->drawable, GL_NONE );
|
|
}
|
|
|
|
static BOOL win32u_wglSetPbufferAttribARB( struct wgl_pbuffer *pbuffer, const int *attribs )
|
|
{
|
|
TRACE( "pbuffer %p, attribs %p\n", pbuffer, attribs );
|
|
|
|
if (!pbuffer->texture_format)
|
|
{
|
|
RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
|
|
return GL_FALSE;
|
|
}
|
|
|
|
for (; attribs && attribs[0]; attribs += 2)
|
|
{
|
|
switch (attribs[0])
|
|
{
|
|
case WGL_MIPMAP_LEVEL_ARB:
|
|
TRACE( "WGL_MIPMAP_LEVEL_ARB %#x\n", attribs[1] );
|
|
pbuffer->mipmap_level = attribs[1];
|
|
break;
|
|
|
|
case WGL_CUBE_MAP_FACE_ARB:
|
|
TRACE( "WGL_CUBE_MAP_FACE_ARB %#x\n", attribs[1] );
|
|
switch (attribs[1])
|
|
{
|
|
case WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
|
|
pbuffer->cube_face = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
|
break;
|
|
case WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
|
|
pbuffer->cube_face = GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
|
|
break;
|
|
case WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
|
|
pbuffer->cube_face = GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
|
|
break;
|
|
case WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
|
|
pbuffer->cube_face = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
|
|
break;
|
|
case WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
|
|
pbuffer->cube_face = GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
|
|
break;
|
|
case WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
|
|
pbuffer->cube_face = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
|
|
break;
|
|
default:
|
|
FIXME( "Unknown texture face: %x\n", attribs[1] );
|
|
RtlSetLastWin32Error( ERROR_INVALID_DATA );
|
|
return GL_FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
FIXME( "Invalid attribute 0x%x\n", attribs[0] );
|
|
RtlSetLastWin32Error( ERROR_INVALID_DATA );
|
|
return GL_FALSE;
|
|
}
|
|
}
|
|
|
|
return driver_funcs->p_pbuffer_updated( pbuffer->hdc, pbuffer->drawable, pbuffer->cube_face,
|
|
max( pbuffer->mipmap_level, 0 ) );
|
|
}
|
|
|
|
static int get_window_swap_interval( HWND hwnd )
|
|
{
|
|
int interval;
|
|
WND *win;
|
|
|
|
if (!(win = get_win_ptr( hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return 0;
|
|
interval = win->swap_interval;
|
|
release_win_ptr( win );
|
|
|
|
return interval;
|
|
}
|
|
|
|
static BOOL win32u_wgl_context_reset( struct wgl_context *context, HDC hdc, struct wgl_context *share, const int *attribs )
|
|
{
|
|
void *share_private = share ? share->driver_private : NULL;
|
|
int format;
|
|
|
|
TRACE( "context %p, hdc %p, share %p, attribs %p\n", context, hdc, share, attribs );
|
|
|
|
if (context->internal_context)
|
|
{
|
|
driver_funcs->p_context_destroy( context->internal_context );
|
|
context->internal_context = NULL;
|
|
}
|
|
if (context->driver_private && !driver_funcs->p_context_destroy( context->driver_private ))
|
|
{
|
|
WARN( "Failed to destroy driver context %p\n", context->driver_private );
|
|
return FALSE;
|
|
}
|
|
context->driver_private = NULL;
|
|
if (!hdc) return TRUE;
|
|
|
|
if ((format = get_dc_pixel_format( hdc, TRUE )) <= 0)
|
|
{
|
|
if (!format) RtlSetLastWin32Error( ERROR_INVALID_PIXEL_FORMAT );
|
|
return FALSE;
|
|
}
|
|
if (!driver_funcs->p_context_create( format, share_private, attribs, &context->driver_private ))
|
|
{
|
|
WARN( "Failed to create driver context for context %p\n", context );
|
|
return FALSE;
|
|
}
|
|
context->format = format;
|
|
|
|
TRACE( "reset context %p, format %u for driver context %p\n", context, format, context->driver_private );
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush)(void) )
|
|
{
|
|
HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1];
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
struct opengl_drawable *draw;
|
|
UINT flags = 0;
|
|
int interval;
|
|
HWND hwnd;
|
|
|
|
if (!(hwnd = NtUserWindowFromDC( draw_hdc ))) interval = 0;
|
|
else interval = get_window_swap_interval( hwnd );
|
|
|
|
TRACE( "context %p, hwnd %p, draw_hdc %p, interval %d, flush %p\n", context, hwnd, draw_hdc, interval, flush );
|
|
|
|
context_sync_drawables( context, draw_hdc, read_hdc );
|
|
if (flush_memory_dc( context, draw_hdc, FALSE, flush )) return TRUE;
|
|
|
|
if (flush) flush();
|
|
if (flush == funcs->p_glFinish) flags |= GL_FLUSH_FINISHED;
|
|
|
|
if (!(draw = get_dc_opengl_drawable( draw_hdc ))) return FALSE;
|
|
opengl_drawable_flush( draw, interval, flags );
|
|
opengl_drawable_release( draw );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL win32u_wglSwapBuffers( HDC hdc )
|
|
{
|
|
HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1];
|
|
struct wgl_context *context = NtCurrentTeb()->glContext;
|
|
const struct opengl_funcs *funcs = &display_funcs;
|
|
struct opengl_drawable *draw;
|
|
int interval;
|
|
HWND hwnd;
|
|
BOOL ret;
|
|
|
|
if (!(hwnd = NtUserWindowFromDC( hdc ))) interval = 0;
|
|
else interval = get_window_swap_interval( hwnd );
|
|
|
|
context_sync_drawables( context, draw_hdc, read_hdc );
|
|
if (flush_memory_dc( context, hdc, FALSE, funcs->p_glFlush )) return TRUE;
|
|
|
|
if (!(draw = get_dc_opengl_drawable( draw_hdc ))) return FALSE;
|
|
opengl_drawable_flush( draw, interval, 0 );
|
|
if (!draw->client) ret = FALSE; /* pbuffer, nothing to do */
|
|
else ret = draw->funcs->swap( draw );
|
|
opengl_drawable_release( draw );
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL win32u_wglSwapIntervalEXT( int interval )
|
|
{
|
|
HDC hdc = NtCurrentTeb()->glReserved1[0];
|
|
HWND hwnd;
|
|
WND *win;
|
|
|
|
if (!(hwnd = NtUserWindowFromDC( hdc )) || !(win = get_win_ptr( hwnd )))
|
|
{
|
|
RtlSetLastWin32Error( ERROR_DC_NOT_FOUND );
|
|
return FALSE;
|
|
}
|
|
if (win == WND_DESKTOP || win == WND_OTHER_PROCESS)
|
|
{
|
|
WARN( "setting swap interval on win %p not supported\n", hwnd );
|
|
return TRUE;
|
|
}
|
|
|
|
TRACE( "setting window %p swap interval %d\n", hwnd, interval );
|
|
win->swap_interval = interval;
|
|
release_win_ptr( win );
|
|
return TRUE;
|
|
}
|
|
|
|
static int win32u_wglGetSwapIntervalEXT(void)
|
|
{
|
|
HDC hdc = NtCurrentTeb()->glReserved1[0];
|
|
int interval;
|
|
HWND hwnd;
|
|
WND *win;
|
|
|
|
if (!(hwnd = NtUserWindowFromDC( hdc )) || !(win = get_win_ptr( hwnd )))
|
|
{
|
|
RtlSetLastWin32Error( ERROR_DC_NOT_FOUND );
|
|
return 0;
|
|
}
|
|
if (win == WND_DESKTOP || win == WND_OTHER_PROCESS)
|
|
{
|
|
WARN( "setting swap interval on win %p not supported\n", hwnd );
|
|
return TRUE;
|
|
}
|
|
interval = win->swap_interval;
|
|
release_win_ptr( win );
|
|
|
|
return interval;
|
|
}
|
|
|
|
static void display_funcs_init(void)
|
|
{
|
|
UINT status;
|
|
|
|
if (egl_init( &driver_funcs )) TRACE( "Initialized EGL library\n" );
|
|
|
|
if ((status = user_driver->pOpenGLInit( WINE_OPENGL_DRIVER_VERSION, &display_funcs, &driver_funcs )))
|
|
WARN( "Failed to initialize the driver OpenGL functions, status %#x\n", status );
|
|
init_egl_platform( &display_egl, &display_funcs, driver_funcs );
|
|
|
|
formats_count = driver_funcs->p_init_pixel_formats( &onscreen_count );
|
|
if (!(pixel_formats = malloc( formats_count * sizeof(*pixel_formats) ))) ERR( "Failed to allocate memory for pixel formats\n" );
|
|
else for (int i = 0; i < formats_count; i++) driver_funcs->p_describe_pixel_format( i + 1, pixel_formats + i );
|
|
|
|
#define USE_GL_FUNC(func) \
|
|
if (!display_funcs.p_##func && !(display_funcs.p_##func = driver_funcs->p_get_proc_address( #func ))) \
|
|
{ \
|
|
WARN( "%s not found for memory DCs.\n", #func ); \
|
|
display_funcs.p_##func = default_funcs->p_##func; \
|
|
}
|
|
ALL_GL_FUNCS
|
|
USE_GL_FUNC(glBindFramebuffer)
|
|
USE_GL_FUNC(glCheckNamedFramebufferStatus)
|
|
USE_GL_FUNC(glCreateFramebuffers)
|
|
USE_GL_FUNC(glCreateRenderbuffers)
|
|
USE_GL_FUNC(glDeleteFramebuffers)
|
|
USE_GL_FUNC(glDeleteRenderbuffers)
|
|
USE_GL_FUNC(glGetNamedFramebufferAttachmentParameteriv)
|
|
USE_GL_FUNC(glNamedFramebufferDrawBuffer)
|
|
USE_GL_FUNC(glNamedFramebufferReadBuffer)
|
|
USE_GL_FUNC(glNamedFramebufferRenderbuffer)
|
|
USE_GL_FUNC(glNamedRenderbufferStorageMultisample)
|
|
#undef USE_GL_FUNC
|
|
|
|
display_funcs.p_wglGetProcAddress = win32u_wglGetProcAddress;
|
|
display_funcs.p_get_pixel_formats = win32u_get_pixel_formats;
|
|
|
|
strcpy( wgl_extensions, driver_funcs->p_init_wgl_extensions( &display_funcs ) );
|
|
display_funcs.p_wglGetPixelFormat = win32u_wglGetPixelFormat;
|
|
display_funcs.p_wglSetPixelFormat = win32u_wglSetPixelFormat;
|
|
|
|
display_funcs.p_wglCreateContext = (void *)1; /* never called */
|
|
display_funcs.p_wglDeleteContext = (void *)1; /* never called */
|
|
display_funcs.p_wglCopyContext = (void *)1; /* never called */
|
|
display_funcs.p_wglShareLists = (void *)1; /* never called */
|
|
display_funcs.p_wglMakeCurrent = win32u_wglMakeCurrent;
|
|
|
|
display_funcs.p_wglSwapBuffers = win32u_wglSwapBuffers;
|
|
display_funcs.p_wgl_context_reset = win32u_wgl_context_reset;
|
|
display_funcs.p_wgl_context_flush = win32u_wgl_context_flush;
|
|
|
|
if (display_egl.has_EGL_EXT_pixel_format_float)
|
|
{
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_pixel_format_float" );
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ATI_pixel_format_float" );
|
|
}
|
|
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_extensions_string" );
|
|
display_funcs.p_wglGetExtensionsStringARB = win32u_wglGetExtensionsStringARB;
|
|
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_EXT_extensions_string" );
|
|
display_funcs.p_wglGetExtensionsStringEXT = win32u_wglGetExtensionsStringEXT;
|
|
|
|
/* 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_extensions, ARRAY_SIZE(wgl_extensions), "WGL_WINE_pixel_format_passthrough" );
|
|
display_funcs.p_wglSetPixelFormatWINE = win32u_wglSetPixelFormatWINE;
|
|
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_pixel_format" );
|
|
display_funcs.p_wglChoosePixelFormatARB = (void *)1; /* never called */
|
|
display_funcs.p_wglGetPixelFormatAttribfvARB = (void *)1; /* never called */
|
|
display_funcs.p_wglGetPixelFormatAttribivARB = (void *)1; /* never called */
|
|
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_create_context" );
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_create_context_no_error" );
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_create_context_profile" );
|
|
display_funcs.p_wglCreateContextAttribsARB = (void *)1; /* never called */
|
|
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_make_current_read" );
|
|
display_funcs.p_wglGetCurrentReadDCARB = (void *)1; /* never called */
|
|
display_funcs.p_wglMakeContextCurrentARB = win32u_wglMakeContextCurrentARB;
|
|
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_pbuffer" );
|
|
display_funcs.p_wglCreatePbufferARB = win32u_wglCreatePbufferARB;
|
|
display_funcs.p_wglDestroyPbufferARB = win32u_wglDestroyPbufferARB;
|
|
display_funcs.p_wglGetPbufferDCARB = win32u_wglGetPbufferDCARB;
|
|
display_funcs.p_wglReleasePbufferDCARB = win32u_wglReleasePbufferDCARB;
|
|
display_funcs.p_wglQueryPbufferARB = win32u_wglQueryPbufferARB;
|
|
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_ARB_render_texture" );
|
|
display_funcs.p_wglBindTexImageARB = win32u_wglBindTexImageARB;
|
|
display_funcs.p_wglReleaseTexImageARB = win32u_wglReleaseTexImageARB;
|
|
display_funcs.p_wglSetPbufferAttribARB = win32u_wglSetPbufferAttribARB;
|
|
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_EXT_swap_control" );
|
|
register_extension( wgl_extensions, ARRAY_SIZE(wgl_extensions), "WGL_EXT_swap_control_tear" );
|
|
display_funcs.p_wglSwapIntervalEXT = win32u_wglSwapIntervalEXT;
|
|
display_funcs.p_wglGetSwapIntervalEXT = win32u_wglGetSwapIntervalEXT;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* __wine_get_wgl_driver (win32u.@)
|
|
*/
|
|
const struct opengl_funcs *__wine_get_wgl_driver( HDC hdc, UINT version, const struct opengl_funcs *null_funcs )
|
|
{
|
|
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
|
DWORD is_disabled, is_display, is_memdc;
|
|
DC *dc;
|
|
|
|
if (version != WINE_OPENGL_DRIVER_VERSION)
|
|
{
|
|
ERR( "version mismatch, opengl32 wants %u but dibdrv has %u\n",
|
|
version, WINE_OPENGL_DRIVER_VERSION );
|
|
return NULL;
|
|
}
|
|
|
|
InterlockedExchangePointer( (void *)&default_funcs, (void *)null_funcs );
|
|
|
|
if (!(dc = get_dc_ptr( hdc ))) return NULL;
|
|
is_memdc = get_gdi_object_type( hdc ) == NTGDI_OBJ_MEMDC;
|
|
is_display = dc->is_display;
|
|
is_disabled = dc->attr->disabled;
|
|
release_dc_ptr( dc );
|
|
|
|
if (is_disabled) return NULL;
|
|
if (!is_display && !is_memdc) return NULL;
|
|
pthread_once( &init_once, display_funcs_init );
|
|
return &display_funcs;
|
|
}
|