2022-10-07 09:31:05 +00:00
|
|
|
/* Window-specific OpenGL functions implementation.
|
|
|
|
*
|
|
|
|
* Copyright (c) 1999 Lionel Ulmer
|
|
|
|
* Copyright (c) 2005 Raphael Junqueira
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2022-11-07 15:26:41 +00:00
|
|
|
#if 0
|
|
|
|
#pragma makedep unix
|
|
|
|
#endif
|
|
|
|
|
2022-10-07 09:31:05 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2022-11-07 15:26:41 +00:00
|
|
|
#include <pthread.h>
|
|
|
|
|
2022-10-07 09:31:05 +00:00
|
|
|
#include "ntstatus.h"
|
|
|
|
#define WIN32_NO_STATUS
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
2022-11-07 12:58:25 +00:00
|
|
|
#include "winreg.h"
|
2022-10-07 09:31:05 +00:00
|
|
|
#include "ntuser.h"
|
|
|
|
|
|
|
|
#include "unixlib.h"
|
2022-11-07 15:24:08 +00:00
|
|
|
#include "unix_private.h"
|
2022-10-07 09:31:05 +00:00
|
|
|
|
|
|
|
#include "wine/debug.h"
|
|
|
|
|
2022-11-07 12:58:25 +00:00
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(wgl);
|
|
|
|
|
2022-11-07 15:26:41 +00:00
|
|
|
static pthread_mutex_t wgl_lock = PTHREAD_MUTEX_INITIALIZER;
|
2022-10-07 09:31:05 +00:00
|
|
|
|
2022-10-06 09:51:30 +00:00
|
|
|
/* handle management */
|
|
|
|
|
|
|
|
enum wgl_handle_type
|
|
|
|
{
|
|
|
|
HANDLE_PBUFFER = 0 << 12,
|
|
|
|
HANDLE_CONTEXT = 1 << 12,
|
|
|
|
HANDLE_CONTEXT_V3 = 3 << 12,
|
|
|
|
HANDLE_TYPE_MASK = 15 << 12
|
|
|
|
};
|
|
|
|
|
|
|
|
struct opengl_context
|
|
|
|
{
|
|
|
|
DWORD tid; /* thread that the context is current in */
|
|
|
|
void (CALLBACK *debug_callback)( GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar *, const void * ); /* debug callback */
|
|
|
|
const void *debug_user; /* debug user parameter */
|
|
|
|
GLubyte *extensions; /* extension string */
|
|
|
|
GLuint *disabled_exts; /* indices of disabled extensions */
|
|
|
|
struct wgl_context *drv_ctx; /* driver context */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct wgl_handle
|
|
|
|
{
|
|
|
|
UINT handle;
|
|
|
|
struct opengl_funcs *funcs;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
struct opengl_context *context; /* for HANDLE_CONTEXT */
|
|
|
|
struct wgl_pbuffer *pbuffer; /* for HANDLE_PBUFFER */
|
|
|
|
struct wgl_handle *next; /* for free handles */
|
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAX_WGL_HANDLES 1024
|
|
|
|
static struct wgl_handle wgl_handles[MAX_WGL_HANDLES];
|
|
|
|
static struct wgl_handle *next_free;
|
|
|
|
static unsigned int handle_count;
|
|
|
|
|
|
|
|
/* the current context is assumed valid and doesn't need locking */
|
|
|
|
static inline struct wgl_handle *get_current_context_ptr(void)
|
|
|
|
{
|
|
|
|
if (!NtCurrentTeb()->glCurrentRC) return NULL;
|
|
|
|
return &wgl_handles[LOWORD(NtCurrentTeb()->glCurrentRC) & ~HANDLE_TYPE_MASK];
|
|
|
|
}
|
|
|
|
|
2022-10-07 09:31:05 +00:00
|
|
|
static inline HANDLE next_handle( struct wgl_handle *ptr, enum wgl_handle_type type )
|
|
|
|
{
|
|
|
|
WORD generation = HIWORD( ptr->handle ) + 1;
|
|
|
|
if (!generation) generation++;
|
|
|
|
ptr->handle = MAKELONG( ptr - wgl_handles, generation ) | type;
|
|
|
|
return ULongToHandle( ptr->handle );
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct wgl_handle *get_handle_ptr( HANDLE handle, enum wgl_handle_type type )
|
|
|
|
{
|
|
|
|
unsigned int index = LOWORD( handle ) & ~HANDLE_TYPE_MASK;
|
|
|
|
|
|
|
|
if (index < handle_count && ULongToHandle(wgl_handles[index].handle) == handle)
|
|
|
|
return &wgl_handles[index];
|
|
|
|
|
2022-10-06 14:19:55 +00:00
|
|
|
RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
|
2022-10-07 09:31:05 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HANDLE alloc_handle( enum wgl_handle_type type, struct opengl_funcs *funcs, void *user_ptr )
|
|
|
|
{
|
|
|
|
HANDLE handle = 0;
|
|
|
|
struct wgl_handle *ptr = NULL;
|
|
|
|
|
|
|
|
if ((ptr = next_free))
|
|
|
|
next_free = next_free->u.next;
|
|
|
|
else if (handle_count < MAX_WGL_HANDLES)
|
|
|
|
ptr = &wgl_handles[handle_count++];
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
ptr->funcs = funcs;
|
|
|
|
ptr->u.context = user_ptr;
|
|
|
|
handle = next_handle( ptr, type );
|
|
|
|
}
|
2022-10-06 14:19:55 +00:00
|
|
|
else RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY );
|
2022-10-07 09:31:05 +00:00
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_handle_ptr( struct wgl_handle *ptr )
|
|
|
|
{
|
|
|
|
ptr->handle |= 0xffff;
|
|
|
|
ptr->u.next = next_free;
|
|
|
|
ptr->funcs = NULL;
|
|
|
|
next_free = ptr;
|
|
|
|
}
|
|
|
|
|
2022-11-07 12:58:25 +00:00
|
|
|
/* check if the extension is present in the list */
|
|
|
|
static BOOL has_extension( const char *list, const char *ext, size_t len )
|
|
|
|
{
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
while (*list == ' ') list++;
|
|
|
|
if (!strncmp( list, ext, len ) && (!list[len] || list[len] == ' ')) return TRUE;
|
|
|
|
list = strchr( list, ' ' );
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GLubyte *filter_extensions_list( const char *extensions, const char *disabled )
|
|
|
|
{
|
|
|
|
const char *end;
|
|
|
|
char *p, *str;
|
|
|
|
|
2022-11-07 15:26:41 +00:00
|
|
|
p = str = malloc( strlen( extensions ) + 2 );
|
2022-11-07 12:58:25 +00:00
|
|
|
if (!str) return NULL;
|
|
|
|
|
|
|
|
TRACE( "GL_EXTENSIONS:\n" );
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
while (*extensions == ' ') extensions++;
|
|
|
|
if (!*extensions) break;
|
|
|
|
|
|
|
|
if (!(end = strchr( extensions, ' ' ))) end = extensions + strlen( extensions );
|
|
|
|
memcpy( p, extensions, end - extensions );
|
|
|
|
p[end - extensions] = 0;
|
|
|
|
|
|
|
|
if (!has_extension( disabled, p, strlen( p ) ))
|
|
|
|
{
|
|
|
|
TRACE( "++ %s\n", p );
|
|
|
|
p += end - extensions;
|
|
|
|
*p++ = ' ';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TRACE( "-- %s (disabled by config)\n", p );
|
|
|
|
}
|
|
|
|
extensions = end;
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
return (GLubyte *)str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GLuint *filter_extensions_index( const char *disabled )
|
|
|
|
{
|
|
|
|
const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
GLuint *disabled_index;
|
|
|
|
GLint extensions_count;
|
|
|
|
unsigned int i = 0, j;
|
|
|
|
const char *ext;
|
|
|
|
|
|
|
|
if (!funcs->ext.p_glGetStringi)
|
|
|
|
{
|
|
|
|
void **func_ptr = (void **)&funcs->ext.p_glGetStringi;
|
|
|
|
*func_ptr = funcs->wgl.p_wglGetProcAddress( "glGetStringi" );
|
|
|
|
if (!funcs->ext.p_glGetStringi) return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
funcs->gl.p_glGetIntegerv( GL_NUM_EXTENSIONS, &extensions_count );
|
2022-11-07 15:26:41 +00:00
|
|
|
disabled_index = malloc( extensions_count * sizeof(*disabled_index) );
|
2022-11-07 12:58:25 +00:00
|
|
|
if (!disabled_index) return NULL;
|
|
|
|
|
|
|
|
TRACE( "GL_EXTENSIONS:\n" );
|
|
|
|
|
|
|
|
for (j = 0; j < extensions_count; ++j)
|
|
|
|
{
|
|
|
|
ext = (const char *)funcs->ext.p_glGetStringi( GL_EXTENSIONS, j );
|
|
|
|
if (!has_extension( disabled, ext, strlen( ext ) ))
|
|
|
|
{
|
|
|
|
TRACE( "++ %s\n", ext );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TRACE( "-- %s (disabled by config)\n", ext );
|
|
|
|
disabled_index[i++] = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
disabled_index[i] = ~0u;
|
|
|
|
return disabled_index;
|
|
|
|
}
|
|
|
|
|
2022-11-07 15:26:16 +00:00
|
|
|
static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )
|
|
|
|
{
|
|
|
|
while (len--) *dst++ = (unsigned char)*src++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline UINT asciiz_to_unicode( WCHAR *dst, const char *src )
|
|
|
|
{
|
|
|
|
WCHAR *p = dst;
|
|
|
|
while ((*p++ = *src++));
|
|
|
|
return (p - dst) * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
|
2022-11-12 14:37:54 +00:00
|
|
|
static inline void unicode_to_ascii( char *dst, const WCHAR *src, size_t len )
|
|
|
|
{
|
|
|
|
while (len--) *dst++ = *src++;
|
|
|
|
}
|
|
|
|
|
2022-11-07 15:26:16 +00:00
|
|
|
static HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len )
|
|
|
|
{
|
|
|
|
UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name };
|
|
|
|
OBJECT_ATTRIBUTES attr;
|
|
|
|
HANDLE ret;
|
|
|
|
|
|
|
|
attr.Length = sizeof(attr);
|
|
|
|
attr.RootDirectory = root;
|
|
|
|
attr.ObjectName = &nameW;
|
|
|
|
attr.Attributes = 0;
|
|
|
|
attr.SecurityDescriptor = NULL;
|
|
|
|
attr.SecurityQualityOfService = NULL;
|
|
|
|
|
|
|
|
return NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 ) ? 0 : ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HKEY open_hkcu_key( const char *name )
|
|
|
|
{
|
|
|
|
WCHAR bufferW[256];
|
|
|
|
static HKEY hkcu;
|
|
|
|
|
|
|
|
if (!hkcu)
|
|
|
|
{
|
|
|
|
char buffer[256];
|
|
|
|
DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)];
|
|
|
|
DWORD i, len = sizeof(sid_data);
|
|
|
|
SID *sid;
|
|
|
|
|
|
|
|
if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len ))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
sid = ((TOKEN_USER *)sid_data)->User.Sid;
|
|
|
|
len = sprintf( buffer, "\\Registry\\User\\S-%u-%u", sid->Revision,
|
|
|
|
MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5],
|
|
|
|
sid->IdentifierAuthority.Value[4] ),
|
|
|
|
MAKEWORD( sid->IdentifierAuthority.Value[3],
|
|
|
|
sid->IdentifierAuthority.Value[2] )));
|
|
|
|
for (i = 0; i < sid->SubAuthorityCount; i++)
|
|
|
|
len += sprintf( buffer + len, "-%u", sid->SubAuthority[i] );
|
|
|
|
|
|
|
|
ascii_to_unicode( bufferW, buffer, len );
|
|
|
|
hkcu = reg_open_key( NULL, bufferW, len * sizeof(WCHAR) );
|
|
|
|
}
|
|
|
|
|
|
|
|
return reg_open_key( hkcu, bufferW, asciiz_to_unicode( bufferW, name ) - sizeof(WCHAR) );
|
|
|
|
}
|
|
|
|
|
2022-11-12 14:37:54 +00:00
|
|
|
static NTSTATUS query_reg_value( HKEY hkey, const WCHAR *name, KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size )
|
2022-11-07 15:26:16 +00:00
|
|
|
{
|
|
|
|
unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0;
|
|
|
|
UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name };
|
|
|
|
|
2022-11-12 14:37:54 +00:00
|
|
|
return NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, info, size, &size );
|
2022-11-07 15:26:16 +00:00
|
|
|
}
|
|
|
|
|
2022-11-07 12:58:25 +00:00
|
|
|
/* build the extension string by filtering out the disabled extensions */
|
2022-11-07 14:16:48 +00:00
|
|
|
static BOOL filter_extensions( const char *extensions, GLubyte **exts_list, GLuint **disabled_exts )
|
2022-11-07 12:58:25 +00:00
|
|
|
{
|
|
|
|
static const char *disabled;
|
|
|
|
|
|
|
|
if (!disabled)
|
|
|
|
{
|
|
|
|
char *str = NULL;
|
2022-11-07 15:26:16 +00:00
|
|
|
HKEY hkey;
|
2022-11-07 12:58:25 +00:00
|
|
|
|
|
|
|
/* @@ Wine registry key: HKCU\Software\Wine\OpenGL */
|
2022-11-07 15:26:16 +00:00
|
|
|
if ((hkey = open_hkcu_key( "Software\\Wine\\OpenGL" )))
|
2022-11-07 12:58:25 +00:00
|
|
|
{
|
2022-11-07 15:26:16 +00:00
|
|
|
char buffer[4096];
|
|
|
|
KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
|
|
|
|
static WCHAR disabled_extensionsW[] = {'D','i','s','a','b','l','e','d','E','x','t','e','n','s','i','o','n','s',0};
|
|
|
|
|
2022-11-12 14:37:54 +00:00
|
|
|
if (!query_reg_value( hkey, disabled_extensionsW, value, sizeof(buffer) ))
|
|
|
|
{
|
|
|
|
ULONG len = value->DataLength / sizeof(WCHAR);
|
|
|
|
|
|
|
|
unicode_to_ascii( buffer, (WCHAR *)value->Data, len );
|
|
|
|
buffer[len] = 0;
|
|
|
|
str = strdup( buffer );
|
|
|
|
}
|
2022-11-07 15:26:16 +00:00
|
|
|
NtClose( hkey );
|
2022-11-07 12:58:25 +00:00
|
|
|
}
|
|
|
|
if (str)
|
|
|
|
{
|
2022-11-07 15:26:41 +00:00
|
|
|
if (InterlockedCompareExchangePointer( (void **)&disabled, str, NULL )) free( str );
|
2022-11-07 12:58:25 +00:00
|
|
|
}
|
|
|
|
else disabled = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!disabled[0]) return FALSE;
|
|
|
|
if (extensions && !*exts_list) *exts_list = filter_extensions_list( extensions, disabled );
|
|
|
|
if (!*disabled_exts) *disabled_exts = filter_extensions_index( disabled );
|
|
|
|
return (exts_list && *exts_list) || *disabled_exts;
|
|
|
|
}
|
|
|
|
|
2022-11-07 14:18:07 +00:00
|
|
|
static const GLuint *disabled_extensions_index(void)
|
2022-11-07 12:58:25 +00:00
|
|
|
{
|
|
|
|
struct wgl_handle *ptr = get_current_context_ptr();
|
|
|
|
GLuint **disabled = &ptr->u.context->disabled_exts;
|
|
|
|
if (*disabled || filter_extensions( NULL, NULL, disabled )) return *disabled;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if a GL extension is supported */
|
2022-11-07 14:41:48 +00:00
|
|
|
static BOOL check_extension_support( const char *extension, const char *available_extensions )
|
2022-11-07 12:58:25 +00:00
|
|
|
{
|
|
|
|
const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
TRACE( "Checking for extension '%s'\n", extension );
|
|
|
|
|
|
|
|
/* We use the GetProcAddress function from the display driver to retrieve function pointers
|
|
|
|
* for OpenGL and WGL extensions. In case of winex11.drv the OpenGL extension lookup is done
|
|
|
|
* using glXGetProcAddress. This function is quite unreliable in the sense that its specs don't
|
|
|
|
* require the function to return NULL when an extension isn't found. For this reason we check
|
|
|
|
* if the OpenGL extension required for the function we are looking up is supported. */
|
|
|
|
|
|
|
|
while ((len = strcspn( extension, " " )))
|
|
|
|
{
|
|
|
|
/* Check if the extension is part of the GL extension string to see if it is supported. */
|
|
|
|
if (has_extension( available_extensions, extension, len )) return TRUE;
|
|
|
|
|
|
|
|
/* In general an OpenGL function starts as an ARB/EXT extension and at some stage
|
|
|
|
* it becomes part of the core OpenGL library and can be reached without the ARB/EXT
|
|
|
|
* suffix as well. In the extension table, these functions contain GL_VERSION_major_minor.
|
|
|
|
* Check if we are searching for a core GL function */
|
|
|
|
if (!strncmp( extension, "GL_VERSION_", 11 ))
|
|
|
|
{
|
|
|
|
const GLubyte *gl_version = funcs->gl.p_glGetString( GL_VERSION );
|
|
|
|
const char *version = extension + 11; /* Move past 'GL_VERSION_' */
|
|
|
|
|
|
|
|
if (!gl_version)
|
|
|
|
{
|
|
|
|
ERR( "No OpenGL version found!\n" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compare the major/minor version numbers of the native OpenGL library and what is required by the function.
|
|
|
|
* The gl_version string is guaranteed to have at least a major/minor and sometimes it has a release number as well. */
|
|
|
|
if ((gl_version[0] > version[0]) || ((gl_version[0] == version[0]) && (gl_version[2] >= version[2]))) return TRUE;
|
|
|
|
|
|
|
|
WARN( "The function requires OpenGL version '%c.%c' while your drivers only provide '%c.%c'\n",
|
|
|
|
version[0], version[2], gl_version[0], gl_version[2] );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (extension[len] == ' ') len++;
|
|
|
|
extension += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-11-07 14:18:07 +00:00
|
|
|
static void WINAPI wrap_glGetIntegerv( GLenum pname, GLint *data )
|
|
|
|
{
|
|
|
|
const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
const GLuint *disabled;
|
|
|
|
|
|
|
|
funcs->gl.p_glGetIntegerv( pname, data );
|
|
|
|
|
|
|
|
if (pname == GL_NUM_EXTENSIONS && (disabled = disabled_extensions_index()))
|
|
|
|
while (*disabled++ != ~0u) (*data)--;
|
|
|
|
}
|
|
|
|
|
2022-11-07 14:16:48 +00:00
|
|
|
static const GLubyte * WINAPI wrap_glGetString( GLenum name )
|
|
|
|
{
|
|
|
|
const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
const GLubyte *ret;
|
|
|
|
|
|
|
|
if ((ret = funcs->gl.p_glGetString( name )) && name == GL_EXTENSIONS)
|
|
|
|
{
|
|
|
|
struct wgl_handle *ptr = get_current_context_ptr();
|
|
|
|
GLubyte **extensions = &ptr->u.context->extensions;
|
|
|
|
GLuint **disabled = &ptr->u.context->disabled_exts;
|
|
|
|
if (*extensions || filter_extensions( (const char *)ret, extensions, disabled )) return *extensions;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-11-07 12:29:46 +00:00
|
|
|
static const GLubyte * WINAPI wrap_glGetStringi( GLenum name, GLuint index )
|
|
|
|
{
|
|
|
|
const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
const GLuint *disabled;
|
|
|
|
|
|
|
|
if (!funcs->ext.p_glGetStringi)
|
|
|
|
{
|
|
|
|
void **func_ptr = (void **)&funcs->ext.p_glGetStringi;
|
|
|
|
*func_ptr = funcs->wgl.p_wglGetProcAddress( "glGetStringi" );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == GL_EXTENSIONS && (disabled = disabled_extensions_index()))
|
|
|
|
while (index >= *disabled++) index++;
|
|
|
|
|
|
|
|
return funcs->ext.p_glGetStringi( name, index );
|
|
|
|
}
|
|
|
|
|
2022-11-07 14:41:48 +00:00
|
|
|
static char *build_extension_list(void)
|
2022-11-07 12:29:46 +00:00
|
|
|
{
|
|
|
|
GLint len = 0, capacity, i, extensions_count;
|
|
|
|
char *extension, *tmp, *available_extensions;
|
|
|
|
|
2022-11-07 14:18:07 +00:00
|
|
|
wrap_glGetIntegerv( GL_NUM_EXTENSIONS, &extensions_count );
|
2022-11-07 12:29:46 +00:00
|
|
|
capacity = 128 * extensions_count;
|
|
|
|
|
2022-11-07 15:26:41 +00:00
|
|
|
if (!(available_extensions = malloc( capacity ))) return NULL;
|
2022-11-07 12:29:46 +00:00
|
|
|
for (i = 0; i < extensions_count; ++i)
|
|
|
|
{
|
|
|
|
extension = (char *)wrap_glGetStringi( GL_EXTENSIONS, i );
|
|
|
|
capacity = max( capacity, len + strlen( extension ) + 2 );
|
2022-11-07 15:26:41 +00:00
|
|
|
if (!(tmp = realloc( available_extensions, capacity ))) break;
|
2022-11-07 12:29:46 +00:00
|
|
|
available_extensions = tmp;
|
|
|
|
len += sprintf( available_extensions + len, "%s ", extension );
|
|
|
|
}
|
|
|
|
if (len) available_extensions[len - 1] = 0;
|
|
|
|
|
|
|
|
return available_extensions;
|
|
|
|
}
|
|
|
|
|
2022-11-07 14:41:48 +00:00
|
|
|
static inline enum wgl_handle_type get_current_context_type(void)
|
|
|
|
{
|
|
|
|
if (!NtCurrentTeb()->glCurrentRC) return HANDLE_CONTEXT;
|
|
|
|
return LOWORD(NtCurrentTeb()->glCurrentRC) & HANDLE_TYPE_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if a GL extension is supported */
|
|
|
|
static BOOL is_extension_supported( const char *extension )
|
|
|
|
{
|
|
|
|
enum wgl_handle_type type = get_current_context_type();
|
|
|
|
char *available_extensions = NULL;
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
2022-11-07 15:26:41 +00:00
|
|
|
if (type == HANDLE_CONTEXT) available_extensions = strdup( (const char *)wrap_glGetString( GL_EXTENSIONS ) );
|
2022-11-07 14:41:48 +00:00
|
|
|
if (!available_extensions) available_extensions = build_extension_list();
|
|
|
|
|
|
|
|
if (!available_extensions) ERR( "No OpenGL extensions found, check if your OpenGL setup is correct!\n" );
|
|
|
|
else ret = check_extension_support( extension, available_extensions );
|
|
|
|
|
2022-11-07 15:26:41 +00:00
|
|
|
free( available_extensions );
|
2022-11-07 14:41:48 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int registry_entry_cmp( const void *a, const void *b )
|
|
|
|
{
|
|
|
|
const struct registry_entry *entry_a = a, *entry_b = b;
|
|
|
|
return strcmp( entry_a->name, entry_b->name );
|
|
|
|
}
|
|
|
|
|
|
|
|
static PROC WINAPI wrap_wglGetProcAddress( LPCSTR name )
|
|
|
|
{
|
|
|
|
const struct registry_entry entry = {.name = name}, *found;
|
|
|
|
struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
const void **func_ptr;
|
|
|
|
|
|
|
|
/* Without an active context opengl32 doesn't know to what
|
|
|
|
* driver it has to dispatch wglGetProcAddress.
|
|
|
|
*/
|
|
|
|
if (!get_current_context_ptr())
|
|
|
|
{
|
|
|
|
WARN( "No active WGL context found\n" );
|
|
|
|
return (void *)-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(found = bsearch( &entry, extension_registry, extension_registry_size, sizeof(entry), registry_entry_cmp )))
|
|
|
|
{
|
|
|
|
WARN( "Function %s unknown\n", name );
|
|
|
|
return (void *)-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
func_ptr = (const void **)&funcs->ext + (found - extension_registry);
|
|
|
|
if (!*func_ptr)
|
|
|
|
{
|
|
|
|
void *driver_func = funcs->wgl.p_wglGetProcAddress( name );
|
|
|
|
|
|
|
|
if (!is_extension_supported( found->extension ))
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
static const struct { const char *name, *alt; } alternatives[] =
|
|
|
|
{
|
|
|
|
{ "glCopyTexSubImage3DEXT", "glCopyTexSubImage3D" }, /* needed by RuneScape */
|
|
|
|
{ "glVertexAttribDivisor", "glVertexAttribDivisorARB"}, /* needed by Caffeine */
|
|
|
|
};
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(alternatives); i++)
|
|
|
|
{
|
|
|
|
if (strcmp( name, alternatives[i].name )) continue;
|
|
|
|
WARN( "Extension %s required for %s not supported, trying %s\n", found->extension,
|
|
|
|
name, alternatives[i].alt );
|
|
|
|
return wrap_wglGetProcAddress( alternatives[i].alt );
|
|
|
|
}
|
|
|
|
|
|
|
|
WARN( "Extension %s required for %s not supported\n", found->extension, name );
|
|
|
|
return (void *)-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (driver_func == NULL)
|
|
|
|
{
|
|
|
|
WARN( "Function %s not supported by driver\n", name );
|
|
|
|
return (void *)-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*func_ptr = driver_func;
|
|
|
|
}
|
|
|
|
|
2022-11-14 21:51:31 +00:00
|
|
|
/* Return the index into the extension registry instead of a useless
|
|
|
|
* function pointer, PE side will returns its own function pointers.
|
|
|
|
*/
|
2022-11-07 14:41:48 +00:00
|
|
|
return (void *)(UINT_PTR)(found - extension_registry);
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglCopyContext( HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
struct wgl_handle *src, *dst;
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
if (!(src = get_handle_ptr( hglrcSrc, HANDLE_CONTEXT ))) return FALSE;
|
|
|
|
if ((dst = get_handle_ptr( hglrcDst, HANDLE_CONTEXT )))
|
|
|
|
{
|
2022-10-06 14:19:55 +00:00
|
|
|
if (src->funcs != dst->funcs) RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
|
2022-10-07 09:31:05 +00:00
|
|
|
else ret = src->funcs->wgl.p_wglCopyContext( src->u.context->drv_ctx, dst->u.context->drv_ctx, mask );
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static HGLRC wrap_wglCreateContext( HDC hdc )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
HGLRC ret = 0;
|
|
|
|
struct wgl_context *drv_ctx;
|
|
|
|
struct opengl_context *context;
|
|
|
|
struct opengl_funcs *funcs = get_dc_funcs( hdc );
|
|
|
|
|
|
|
|
if (!funcs) return 0;
|
|
|
|
if (!(drv_ctx = funcs->wgl.p_wglCreateContext( hdc ))) return 0;
|
2022-11-07 15:26:41 +00:00
|
|
|
if ((context = calloc( 1, sizeof(*context) )))
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
context->drv_ctx = drv_ctx;
|
2022-11-07 15:26:41 +00:00
|
|
|
if (!(ret = alloc_handle( HANDLE_CONTEXT, funcs, context ))) free( context );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
if (!ret) funcs->wgl.p_wglDeleteContext( drv_ctx );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglMakeCurrent( HDC hdc, HGLRC hglrc )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
BOOL ret = TRUE;
|
|
|
|
struct wgl_handle *ptr, *prev = get_current_context_ptr();
|
|
|
|
|
|
|
|
if (hglrc)
|
|
|
|
{
|
|
|
|
if (!(ptr = get_handle_ptr( hglrc, HANDLE_CONTEXT ))) return FALSE;
|
|
|
|
if (!ptr->u.context->tid || ptr->u.context->tid == GetCurrentThreadId())
|
|
|
|
{
|
|
|
|
ret = ptr->funcs->wgl.p_wglMakeCurrent( hdc, ptr->u.context->drv_ctx );
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
if (prev) prev->u.context->tid = 0;
|
|
|
|
ptr->u.context->tid = GetCurrentThreadId();
|
2022-10-06 09:51:30 +00:00
|
|
|
NtCurrentTeb()->glReserved1[0] = hdc;
|
|
|
|
NtCurrentTeb()->glReserved1[1] = hdc;
|
2022-10-07 09:31:05 +00:00
|
|
|
NtCurrentTeb()->glCurrentRC = hglrc;
|
|
|
|
NtCurrentTeb()->glTable = ptr->funcs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-10-06 14:19:55 +00:00
|
|
|
RtlSetLastWin32Error( ERROR_BUSY );
|
2022-10-07 09:31:05 +00:00
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (prev)
|
|
|
|
{
|
|
|
|
if (!prev->funcs->wgl.p_wglMakeCurrent( 0, NULL )) return FALSE;
|
|
|
|
prev->u.context->tid = 0;
|
|
|
|
NtCurrentTeb()->glCurrentRC = 0;
|
|
|
|
NtCurrentTeb()->glTable = &null_opengl_funcs;
|
|
|
|
}
|
|
|
|
else if (!hdc)
|
|
|
|
{
|
2022-10-06 14:19:55 +00:00
|
|
|
RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
|
2022-10-07 09:31:05 +00:00
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-10-06 10:20:55 +00:00
|
|
|
static BOOL wrap_wglDeleteContext( HGLRC hglrc )
|
|
|
|
{
|
2022-10-06 10:08:13 +00:00
|
|
|
struct wgl_handle *ptr;
|
2022-10-06 10:20:55 +00:00
|
|
|
|
2022-10-06 10:08:13 +00:00
|
|
|
if (!(ptr = get_handle_ptr( hglrc, HANDLE_CONTEXT ))) return FALSE;
|
2022-10-06 10:20:55 +00:00
|
|
|
if (ptr->u.context->tid && ptr->u.context->tid != GetCurrentThreadId())
|
|
|
|
{
|
2022-10-06 14:19:55 +00:00
|
|
|
RtlSetLastWin32Error( ERROR_BUSY );
|
2022-10-06 10:20:55 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (hglrc == NtCurrentTeb()->glCurrentRC) wrap_wglMakeCurrent( 0, 0 );
|
|
|
|
ptr->funcs->wgl.p_wglDeleteContext( ptr->u.context->drv_ctx );
|
2022-11-07 15:26:41 +00:00
|
|
|
free( ptr->u.context->disabled_exts );
|
|
|
|
free( ptr->u.context->extensions );
|
|
|
|
free( ptr->u.context );
|
2022-10-06 10:20:55 +00:00
|
|
|
free_handle_ptr( ptr );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglShareLists( HGLRC hglrcSrc, HGLRC hglrcDst )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
struct wgl_handle *src, *dst;
|
|
|
|
|
|
|
|
if (!(src = get_handle_ptr( hglrcSrc, HANDLE_CONTEXT ))) return FALSE;
|
|
|
|
if ((dst = get_handle_ptr( hglrcDst, HANDLE_CONTEXT )))
|
|
|
|
{
|
2022-10-06 14:19:55 +00:00
|
|
|
if (src->funcs != dst->funcs) RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
|
2022-10-07 09:31:05 +00:00
|
|
|
else ret = src->funcs->wgl.p_wglShareLists( src->u.context->drv_ctx, dst->u.context->drv_ctx );
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglBindTexImageARB( HPBUFFERARB handle, int buffer )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
2022-10-06 10:08:13 +00:00
|
|
|
struct wgl_handle *ptr;
|
|
|
|
if (!(ptr = get_handle_ptr( handle, HANDLE_PBUFFER ))) return FALSE;
|
|
|
|
return ptr->funcs->ext.p_wglBindTexImageARB( ptr->u.pbuffer, buffer );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static HGLRC wrap_wglCreateContextAttribsARB( HDC hdc, HGLRC share, const int *attribs )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
HGLRC ret = 0;
|
|
|
|
struct wgl_context *drv_ctx;
|
|
|
|
struct wgl_handle *share_ptr = NULL;
|
|
|
|
struct opengl_context *context;
|
|
|
|
struct opengl_funcs *funcs = get_dc_funcs( hdc );
|
|
|
|
|
|
|
|
if (!funcs)
|
|
|
|
{
|
2022-10-06 14:19:55 +00:00
|
|
|
RtlSetLastWin32Error( ERROR_DC_NOT_FOUND );
|
2022-10-07 09:31:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!funcs->ext.p_wglCreateContextAttribsARB) return 0;
|
|
|
|
if (share && !(share_ptr = get_handle_ptr( share, HANDLE_CONTEXT )))
|
|
|
|
{
|
2022-10-06 14:19:55 +00:00
|
|
|
RtlSetLastWin32Error( ERROR_INVALID_OPERATION );
|
2022-10-07 09:31:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if ((drv_ctx = funcs->ext.p_wglCreateContextAttribsARB( hdc, share_ptr ? share_ptr->u.context->drv_ctx : NULL, attribs )))
|
|
|
|
{
|
2022-11-07 15:26:41 +00:00
|
|
|
if ((context = calloc( 1, sizeof(*context) )))
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
enum wgl_handle_type type = HANDLE_CONTEXT;
|
|
|
|
|
|
|
|
if (attribs)
|
|
|
|
{
|
|
|
|
while (*attribs)
|
|
|
|
{
|
|
|
|
if (attribs[0] == WGL_CONTEXT_MAJOR_VERSION_ARB)
|
|
|
|
{
|
|
|
|
if (attribs[1] >= 3) type = HANDLE_CONTEXT_V3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
attribs += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
context->drv_ctx = drv_ctx;
|
2022-11-07 15:26:41 +00:00
|
|
|
if (!(ret = alloc_handle( type, funcs, context ))) free( context );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
if (!ret) funcs->wgl.p_wglDeleteContext( drv_ctx );
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static HPBUFFERARB wrap_wglCreatePbufferARB( HDC hdc, int format, int width, int height, const int *attribs )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
HPBUFFERARB ret;
|
|
|
|
struct wgl_pbuffer *pbuffer;
|
|
|
|
struct opengl_funcs *funcs = get_dc_funcs( hdc );
|
|
|
|
|
|
|
|
if (!funcs || !funcs->ext.p_wglCreatePbufferARB) return 0;
|
|
|
|
if (!(pbuffer = funcs->ext.p_wglCreatePbufferARB( hdc, format, width, height, attribs ))) return 0;
|
|
|
|
ret = alloc_handle( HANDLE_PBUFFER, funcs, pbuffer );
|
|
|
|
if (!ret) funcs->ext.p_wglDestroyPbufferARB( pbuffer );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglDestroyPbufferARB( HPBUFFERARB handle )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
2022-10-06 10:08:13 +00:00
|
|
|
struct wgl_handle *ptr;
|
2022-10-07 09:31:05 +00:00
|
|
|
|
2022-10-06 10:08:13 +00:00
|
|
|
if (!(ptr = get_handle_ptr( handle, HANDLE_PBUFFER ))) return FALSE;
|
2022-10-07 09:31:05 +00:00
|
|
|
ptr->funcs->ext.p_wglDestroyPbufferARB( ptr->u.pbuffer );
|
|
|
|
free_handle_ptr( ptr );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static HDC wrap_wglGetPbufferDCARB( HPBUFFERARB handle )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
2022-10-06 10:08:13 +00:00
|
|
|
struct wgl_handle *ptr;
|
|
|
|
if (!(ptr = get_handle_ptr( handle, HANDLE_PBUFFER ))) return 0;
|
|
|
|
return ptr->funcs->ext.p_wglGetPbufferDCARB( ptr->u.pbuffer );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, HGLRC hglrc )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
BOOL ret = TRUE;
|
|
|
|
struct wgl_handle *ptr, *prev = get_current_context_ptr();
|
|
|
|
|
|
|
|
if (hglrc)
|
|
|
|
{
|
|
|
|
if (!(ptr = get_handle_ptr( hglrc, HANDLE_CONTEXT ))) return FALSE;
|
|
|
|
if (!ptr->u.context->tid || ptr->u.context->tid == GetCurrentThreadId())
|
|
|
|
{
|
|
|
|
ret = (ptr->funcs->ext.p_wglMakeContextCurrentARB &&
|
|
|
|
ptr->funcs->ext.p_wglMakeContextCurrentARB( draw_hdc, read_hdc, ptr->u.context->drv_ctx ));
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
if (prev) prev->u.context->tid = 0;
|
|
|
|
ptr->u.context->tid = GetCurrentThreadId();
|
2022-10-06 09:51:30 +00:00
|
|
|
NtCurrentTeb()->glReserved1[0] = draw_hdc;
|
|
|
|
NtCurrentTeb()->glReserved1[1] = read_hdc;
|
2022-10-07 09:31:05 +00:00
|
|
|
NtCurrentTeb()->glCurrentRC = hglrc;
|
|
|
|
NtCurrentTeb()->glTable = ptr->funcs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-10-06 14:19:55 +00:00
|
|
|
RtlSetLastWin32Error( ERROR_BUSY );
|
2022-10-07 09:31:05 +00:00
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (prev)
|
|
|
|
{
|
|
|
|
if (!prev->funcs->wgl.p_wglMakeCurrent( 0, NULL )) return FALSE;
|
|
|
|
prev->u.context->tid = 0;
|
|
|
|
NtCurrentTeb()->glCurrentRC = 0;
|
|
|
|
NtCurrentTeb()->glTable = &null_opengl_funcs;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglQueryPbufferARB( HPBUFFERARB handle, int attrib, int *value )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
2022-10-06 10:08:13 +00:00
|
|
|
struct wgl_handle *ptr;
|
|
|
|
if (!(ptr = get_handle_ptr( handle, HANDLE_PBUFFER ))) return FALSE;
|
|
|
|
return ptr->funcs->ext.p_wglQueryPbufferARB( ptr->u.pbuffer, attrib, value );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static int wrap_wglReleasePbufferDCARB( HPBUFFERARB handle, HDC hdc )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
2022-10-06 10:08:13 +00:00
|
|
|
struct wgl_handle *ptr;
|
|
|
|
if (!(ptr = get_handle_ptr( handle, HANDLE_PBUFFER ))) return FALSE;
|
|
|
|
return ptr->funcs->ext.p_wglReleasePbufferDCARB( ptr->u.pbuffer, hdc );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglReleaseTexImageARB( HPBUFFERARB handle, int buffer )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
2022-10-06 10:08:13 +00:00
|
|
|
struct wgl_handle *ptr;
|
|
|
|
if (!(ptr = get_handle_ptr( handle, HANDLE_PBUFFER ))) return FALSE;
|
|
|
|
return ptr->funcs->ext.p_wglReleaseTexImageARB( ptr->u.pbuffer, buffer );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static BOOL wrap_wglSetPbufferAttribARB( HPBUFFERARB handle, const int *attribs )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
2022-10-06 10:08:13 +00:00
|
|
|
struct wgl_handle *ptr;
|
|
|
|
if (!(ptr = get_handle_ptr( handle, HANDLE_PBUFFER ))) return FALSE;
|
|
|
|
return ptr->funcs->ext.p_wglSetPbufferAttribARB( ptr->u.pbuffer, attribs );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void gl_debug_message_callback( GLenum source, GLenum type, GLuint id, GLenum severity,
|
|
|
|
GLsizei length, const GLchar *message, const void *userParam )
|
|
|
|
{
|
|
|
|
struct wine_gl_debug_message_params params =
|
|
|
|
{
|
|
|
|
.source = source,
|
|
|
|
.type = type,
|
|
|
|
.id = id,
|
|
|
|
.severity = severity,
|
|
|
|
.length = length,
|
|
|
|
.message = message,
|
|
|
|
};
|
2022-11-07 15:26:41 +00:00
|
|
|
void *ret_ptr;
|
|
|
|
ULONG ret_len;
|
2022-10-07 09:31:05 +00:00
|
|
|
|
|
|
|
struct wgl_handle *ptr = (struct wgl_handle *)userParam;
|
|
|
|
if (!(params.user_callback = ptr->u.context->debug_callback)) return;
|
|
|
|
params.user_data = ptr->u.context->debug_user;
|
|
|
|
|
2022-11-07 15:26:41 +00:00
|
|
|
KeUserModeCallback( NtUserCallOpenGLDebugMessageCallback, ¶ms, sizeof(params),
|
|
|
|
&ret_ptr, &ret_len );
|
2022-10-07 09:31:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static void WINAPI wrap_glDebugMessageCallback( GLDEBUGPROC callback, const void *userParam )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
struct wgl_handle *ptr = get_current_context_ptr();
|
|
|
|
const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
if (!funcs->ext.p_glDebugMessageCallback) return;
|
2022-10-07 09:31:05 +00:00
|
|
|
|
|
|
|
ptr->u.context->debug_callback = callback;
|
|
|
|
ptr->u.context->debug_user = userParam;
|
|
|
|
funcs->ext.p_glDebugMessageCallback( gl_debug_message_callback, ptr );
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static void WINAPI wrap_glDebugMessageCallbackAMD( GLDEBUGPROCAMD callback, void *userParam )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
struct wgl_handle *ptr = get_current_context_ptr();
|
|
|
|
const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
if (!funcs->ext.p_glDebugMessageCallbackAMD) return;
|
2022-10-07 09:31:05 +00:00
|
|
|
|
|
|
|
ptr->u.context->debug_callback = callback;
|
|
|
|
ptr->u.context->debug_user = userParam;
|
|
|
|
funcs->ext.p_glDebugMessageCallbackAMD( gl_debug_message_callback, ptr );
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
static void WINAPI wrap_glDebugMessageCallbackARB( GLDEBUGPROCARB callback, const void *userParam )
|
2022-10-07 09:31:05 +00:00
|
|
|
{
|
|
|
|
struct wgl_handle *ptr = get_current_context_ptr();
|
|
|
|
const struct opengl_funcs *funcs = NtCurrentTeb()->glTable;
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
if (!funcs->ext.p_glDebugMessageCallbackARB) return;
|
2022-10-07 09:31:05 +00:00
|
|
|
|
|
|
|
ptr->u.context->debug_callback = callback;
|
|
|
|
ptr->u.context->debug_user = userParam;
|
|
|
|
funcs->ext.p_glDebugMessageCallbackARB( gl_debug_message_callback, ptr );
|
|
|
|
}
|
2022-10-07 16:34:09 +00:00
|
|
|
|
|
|
|
NTSTATUS wgl_wglCopyContext( void *args )
|
|
|
|
{
|
|
|
|
struct wglCopyContext_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglCopyContext( params->hglrcSrc, params->hglrcDst, params->mask );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS wgl_wglCreateContext( void *args )
|
|
|
|
{
|
|
|
|
struct wglCreateContext_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglCreateContext( params->hDc );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS wgl_wglDeleteContext( void *args )
|
|
|
|
{
|
|
|
|
struct wglDeleteContext_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglDeleteContext( params->oldContext );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-11-07 14:41:48 +00:00
|
|
|
NTSTATUS wgl_wglGetProcAddress( void *args )
|
|
|
|
{
|
|
|
|
struct wglGetProcAddress_params *params = args;
|
|
|
|
params->ret = wrap_wglGetProcAddress( params->lpszProc );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
NTSTATUS wgl_wglMakeCurrent( void *args )
|
|
|
|
{
|
|
|
|
struct wglMakeCurrent_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
if (params->newContext) pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglMakeCurrent( params->hDc, params->newContext );
|
2022-11-07 15:26:41 +00:00
|
|
|
if (params->newContext) pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS wgl_wglShareLists( void *args )
|
|
|
|
{
|
|
|
|
struct wglShareLists_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglShareLists( params->hrcSrvShare, params->hrcSrvSource );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-11-07 14:18:07 +00:00
|
|
|
NTSTATUS gl_glGetIntegerv( void *args )
|
|
|
|
{
|
|
|
|
struct glGetIntegerv_params *params = args;
|
|
|
|
wrap_glGetIntegerv( params->pname, params->data );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-11-07 14:16:48 +00:00
|
|
|
NTSTATUS gl_glGetString( void *args )
|
|
|
|
{
|
|
|
|
struct glGetString_params *params = args;
|
|
|
|
params->ret = wrap_glGetString( params->name );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
NTSTATUS ext_glDebugMessageCallback( void *args )
|
|
|
|
{
|
|
|
|
struct glDebugMessageCallback_params *params = args;
|
|
|
|
wrap_glDebugMessageCallback( params->callback, params->userParam );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2022-10-06 10:08:13 +00:00
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
NTSTATUS ext_glDebugMessageCallbackAMD( void *args )
|
|
|
|
{
|
|
|
|
struct glDebugMessageCallbackAMD_params *params = args;
|
|
|
|
wrap_glDebugMessageCallbackAMD( params->callback, params->userParam );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2022-10-06 10:08:13 +00:00
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
NTSTATUS ext_glDebugMessageCallbackARB( void *args )
|
|
|
|
{
|
|
|
|
struct glDebugMessageCallbackARB_params *params = args;
|
|
|
|
wrap_glDebugMessageCallbackARB( params->callback, params->userParam );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-11-07 12:29:46 +00:00
|
|
|
NTSTATUS ext_glGetStringi( void *args )
|
|
|
|
{
|
|
|
|
struct glGetStringi_params *params = args;
|
|
|
|
params->ret = wrap_glGetStringi( params->name, params->index );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:34:09 +00:00
|
|
|
NTSTATUS ext_wglBindTexImageARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglBindTexImageARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglBindTexImageARB( params->hPbuffer, params->iBuffer );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglCreateContextAttribsARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglCreateContextAttribsARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglCreateContextAttribsARB( params->hDC, params->hShareContext, params->attribList );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglCreatePbufferARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglCreatePbufferARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglCreatePbufferARB( params->hDC, params->iPixelFormat, params->iWidth, params->iHeight, params->piAttribList );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglDestroyPbufferARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglDestroyPbufferARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglDestroyPbufferARB( params->hPbuffer );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglGetPbufferDCARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglGetPbufferDCARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglGetPbufferDCARB( params->hPbuffer );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglMakeContextCurrentARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglMakeContextCurrentARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
if (params->hglrc) pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglMakeContextCurrentARB( params->hDrawDC, params->hReadDC, params->hglrc );
|
2022-11-07 15:26:41 +00:00
|
|
|
if (params->hglrc) pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglQueryPbufferARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglQueryPbufferARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglQueryPbufferARB( params->hPbuffer, params->iAttribute, params->piValue );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglReleasePbufferDCARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglReleasePbufferDCARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglReleasePbufferDCARB( params->hPbuffer, params->hDC );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglReleaseTexImageARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglReleaseTexImageARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglReleaseTexImageARB( params->hPbuffer, params->iBuffer );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ext_wglSetPbufferAttribARB( void *args )
|
|
|
|
{
|
|
|
|
struct wglSetPbufferAttribARB_params *params = args;
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_lock( &wgl_lock );
|
2022-10-07 16:34:09 +00:00
|
|
|
params->ret = wrap_wglSetPbufferAttribARB( params->hPbuffer, params->piAttribList );
|
2022-11-07 15:26:41 +00:00
|
|
|
pthread_mutex_unlock( &wgl_lock );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS WINAPI thread_attach( void *args )
|
|
|
|
{
|
|
|
|
NtCurrentTeb()->glTable = &null_opengl_funcs;
|
2022-10-07 16:34:09 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2022-10-07 16:12:51 +00:00
|
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
|
|
|
|
typedef ULONG PTR32;
|
|
|
|
|
|
|
|
extern NTSTATUS ext_glPathGlyphIndexRangeNV( void *args ) DECLSPEC_HIDDEN;
|
|
|
|
|
2022-11-14 21:51:46 +00:00
|
|
|
static inline void update_teb32_context(void)
|
|
|
|
{
|
|
|
|
TEB *teb = NtCurrentTeb();
|
|
|
|
void *teb32;
|
|
|
|
|
|
|
|
if (!teb->WowTebOffset) return;
|
|
|
|
teb32 = (char *)teb + teb->WowTebOffset;
|
|
|
|
|
|
|
|
((TEB32 *)teb32)->glCurrentRC = (UINT_PTR)teb->glCurrentRC;
|
|
|
|
((TEB32 *)teb32)->glReserved1[0] = (UINT_PTR)teb->glReserved1[0];
|
|
|
|
((TEB32 *)teb32)->glReserved1[1] = (UINT_PTR)teb->glReserved1[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS wow64_wgl_wglCreateContext( void *args )
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
PTR32 hDc;
|
|
|
|
PTR32 ret;
|
|
|
|
} *params32 = args;
|
|
|
|
struct wglCreateContext_params params =
|
|
|
|
{
|
|
|
|
.hDc = ULongToPtr(params32->hDc),
|
|
|
|
};
|
|
|
|
NTSTATUS status;
|
|
|
|
if ((status = wgl_wglCreateContext( ¶ms ))) return status;
|
|
|
|
params32->ret = (UINT_PTR)params.ret;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS wow64_wgl_wglDeleteContext( void *args )
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
PTR32 oldContext;
|
|
|
|
BOOL ret;
|
|
|
|
} *params32 = args;
|
|
|
|
struct wglDeleteContext_params params =
|
|
|
|
{
|
|
|
|
.oldContext = ULongToPtr(params32->oldContext),
|
|
|
|
};
|
|
|
|
NTSTATUS status;
|
|
|
|
if (!(status = wgl_wglDeleteContext( ¶ms ))) update_teb32_context();
|
|
|
|
params32->ret = params.ret;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS wow64_wgl_wglMakeCurrent( void *args )
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
PTR32 hDc;
|
|
|
|
PTR32 newContext;
|
|
|
|
BOOL ret;
|
|
|
|
} *params32 = args;
|
|
|
|
struct wglMakeCurrent_params params =
|
|
|
|
{
|
|
|
|
.hDc = ULongToPtr(params32->hDc),
|
|
|
|
.newContext = ULongToPtr(params32->newContext),
|
|
|
|
};
|
|
|
|
NTSTATUS status;
|
|
|
|
if (!(status = wgl_wglMakeCurrent( ¶ms ))) update_teb32_context();
|
|
|
|
params32->ret = params.ret;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS wow64_ext_wglMakeContextCurrentARB( void *args )
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
PTR32 hDrawDC;
|
|
|
|
PTR32 hReadDC;
|
|
|
|
PTR32 hglrc;
|
|
|
|
BOOL ret;
|
|
|
|
} *params32 = args;
|
|
|
|
struct wglMakeContextCurrentARB_params params =
|
|
|
|
{
|
|
|
|
.hDrawDC = ULongToPtr(params32->hDrawDC),
|
|
|
|
.hReadDC = ULongToPtr(params32->hReadDC),
|
|
|
|
.hglrc = ULongToPtr(params32->hglrc),
|
|
|
|
};
|
|
|
|
NTSTATUS status;
|
|
|
|
if (!(status = ext_wglMakeContextCurrentARB( ¶ms ))) update_teb32_context();
|
|
|
|
params32->ret = params.ret;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2022-11-14 21:51:31 +00:00
|
|
|
NTSTATUS wow64_wgl_wglGetProcAddress( void *args )
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
PTR32 lpszProc;
|
|
|
|
PTR32 ret;
|
|
|
|
} *params32 = args;
|
|
|
|
struct wglGetProcAddress_params params =
|
|
|
|
{
|
|
|
|
.lpszProc = ULongToPtr(params32->lpszProc),
|
|
|
|
};
|
|
|
|
NTSTATUS status;
|
|
|
|
if ((status = wgl_wglGetProcAddress( ¶ms ))) return status;
|
|
|
|
params32->ret = (UINT_PTR)params.ret;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-10-07 16:12:51 +00:00
|
|
|
NTSTATUS wow64_ext_glPathGlyphIndexRangeNV( void *args )
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
GLenum fontTarget;
|
|
|
|
PTR32 fontName;
|
|
|
|
GLbitfield fontStyle;
|
|
|
|
GLuint pathParameterTemplate;
|
|
|
|
GLfloat emScale;
|
|
|
|
GLuint baseAndCount[2];
|
|
|
|
GLenum ret;
|
|
|
|
} *params32 = args;
|
|
|
|
struct glPathGlyphIndexRangeNV_params params =
|
|
|
|
{
|
|
|
|
.fontTarget = params32->fontTarget,
|
|
|
|
.fontName = ULongToPtr(params32->fontName),
|
|
|
|
.fontStyle = params32->fontStyle,
|
|
|
|
.pathParameterTemplate = params32->pathParameterTemplate,
|
|
|
|
.emScale = params32->emScale,
|
|
|
|
.baseAndCount = {params32->baseAndCount[0], params32->baseAndCount[1]},
|
|
|
|
};
|
|
|
|
NTSTATUS status;
|
|
|
|
if ((status = ext_glPathGlyphIndexRangeNV( ¶ms ))) return status;
|
|
|
|
params32->ret = params.ret;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|