As mentioned in https://gitlab.winehq.org/wine/wine/-/merge_requests/5264, the next step for OpenGL in the Wayland driver is support for WGL_ARB_pixel_format. It seems possible, at least in theory, to move a large part of the logic involved in this extension outside the drivers for common use by all of them (or ones that want to opt-in).
The goal of this RFC MR is, through experimentation and discussion/feedback, evaluate:
1. Whether making such functionality available outside the drivers (likely in an opt-in manner to begin with) is a productive way forward, or the complexity and platform specific decisions favor the current per-driver approach. 2. If we think that (1) is a worthy goal, what's the best mechanism to achieve it.
Note that the focus of this MR is currently on being a proof-of-concept, rather providing ready-for-detailed-review code (although I have done my best to keep the code decent). This MR currently (roughly in commit order):
* Introduces a new wgl driver callback to allow drivers to provide to opengl32/unix a list of formats and many details about them. * Uses the information in that list to implement wglGetPixelFormatAttrib*. * Uses the information in that list plus format sorting rules from WineX11 (effectively GLX rules plus tweaks) to implement wglChoosePixelFormatARB. * Implements the get_pixel_formats callback for the Wayland driver. * Hacks the get_pixel_formats callback for WineX11, and to allow me to run some experiments to compare the output of native WineX11 and get_pixel_formats-WineX11. In the admittedly not too many games I tried the sort order is the same, so at least that's encouraging.
My thoughts and notes so far:
* Using this approach for wglGetPixelFormatAttrib* works well, and we can also implement wglDescribePixelFormat in this way. * It's not at all clear what the "right" sorting rules are for wglChoosePixelFormatARB. * WineX11 uses GLX + tweaks (e.g., changes depth sorting). This means that larger formats tend to be preferred, at least according to the GLX spec. For example, asking for a r5, g6, b5 in the attributes is supposed to give back rgb888 (or even higher if available) as the top format in the list. Interestingly, and to confuse things even more, I haven't been able to make GLX return non-888(8) configs at all to actually test this more, so perhaps that's what saves it here? However, eglChooseConfig works similarly and there I was able to verify this behavior (e.g., got a nice surprise 10-bit format when asking for 5551 :)). * Winemac has its own custom logic. * Mesa's WGL implementation uses a different approach, closer to Wine's normal (wgl)ChoosePixelFormat, where proximity to the target format is strongly rewarded (so it seems asking for r5g6b5 is much more likely to actually get you that). * Of course, the "gold standard" here would be to try to infer and use the rules used by some windows driver.
Looking forward to thoughts/feedback!
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/opengl32/make_opengl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index ec6c7cbe4df..b5afeeaa415 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -185,6 +185,16 @@ my %manual_win_thunks = "wglQueryRendererStringWINE" => 1, "wglSwapBuffers" => 1, ); +my %manual_unix_functions = + ( + "glDebugMessageCallback" => 1, + "glDebugMessageCallbackAMD" => 1, + "glDebugMessageCallbackARB" => 1, + "glGetString" => 1, + "glGetStringi" => 1, + "glGetIntegerv" => 1, + "wglGetProcAddress" => 1, + ); my %manual_wow64_thunks = ( "glClientWaitSync" => 1, @@ -709,7 +719,7 @@ sub needs_wrapper($$) { my ($name, $func) = @_;
- return 1 if $name =~ /^glDebugMessageCallback|^glGetString|^glGetIntegerv|^wglGetProcAddress/; + return 1 if defined $manual_unix_functions{$name};
# check if return value needs special handling (my $type = $func->[0]->textContent()) =~ s/ $//;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
We want to use wgl_pixel_format in the wgl driver API. --- dlls/winex11.drv/opengl.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index afedfb38af3..08b6d8f67e2 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -184,7 +184,7 @@ static char wglExtensions[4096]; static int glxVersion[2]; static int glx_opcode;
-struct wgl_pixel_format +struct glx_pixel_format { GLXFBConfig fbconfig; XVisualInfo *visual; @@ -199,7 +199,7 @@ struct wgl_context BOOL has_been_current; BOOL sharing; BOOL gl3_context; - const struct wgl_pixel_format *fmt; + const struct glx_pixel_format *fmt; int numAttribs; /* This is needed for delaying wglCreateContextAttribsARB */ int attribList[16]; /* This is needed for delaying wglCreateContextAttribsARB */ GLXContext ctx; @@ -224,7 +224,7 @@ struct gl_drawable GLXDrawable drawable; /* drawable for rendering with GL */ Window window; /* window if drawable is a GLXWindow */ Pixmap pixmap; /* base pixmap if drawable is a GLXPixmap */ - const struct wgl_pixel_format *format; /* pixel format for the drawable */ + const struct glx_pixel_format *format; /* pixel format for the drawable */ SIZE pixmap_size; /* pixmap size for GLXPixmap drawables */ int swap_interval; BOOL refresh_swap_interval; @@ -234,7 +234,7 @@ struct gl_drawable struct wgl_pbuffer { struct gl_drawable *gl; - const struct wgl_pixel_format* fmt; + const struct glx_pixel_format* fmt; int width; int height; int* attribList; @@ -266,7 +266,7 @@ static XContext gl_pbuffer_context;
static struct list context_list = LIST_INIT( context_list ); static struct list pbuffer_list = LIST_INIT( pbuffer_list ); -static struct wgl_pixel_format *pixel_formats; +static struct glx_pixel_format *pixel_formats; static int nb_pixel_formats, nb_onscreen_formats; static BOOL use_render_texture_emulation = TRUE;
@@ -998,7 +998,7 @@ static BOOL check_fbconfig_bitmap_capability(Display *display, GLXFBConfig fbcon
static void init_pixel_formats( Display *display ) { - struct wgl_pixel_format *list; + struct glx_pixel_format *list; int size = 0, onscreen_size = 0; int fmt_id, nCfgs, i, run, bmp_formats; GLXFBConfig* cfgs; @@ -1117,7 +1117,7 @@ static inline BOOL is_onscreen_pixel_format( int format ) return format > 0 && format <= nb_onscreen_formats; }
-static inline int pixel_format_index( const struct wgl_pixel_format *format ) +static inline int pixel_format_index( const struct glx_pixel_format *format ) { return format - pixel_formats + 1; } @@ -1127,7 +1127,7 @@ static inline int pixel_format_index( const struct wgl_pixel_format *format ) * Wine's main visual and offscreen formats (if they are available). * This function converts a WGL format to its corresponding GLX one. */ -static const struct wgl_pixel_format *get_pixel_format(Display *display, int iPixelFormat, BOOL AllowOffscreen) +static const struct glx_pixel_format *get_pixel_format(Display *display, int iPixelFormat, BOOL AllowOffscreen) { /* Check if the pixelformat is valid. Note that it is legal to pass an invalid * iPixelFormat in case of probing the number of pixelformats. @@ -1305,7 +1305,7 @@ static GLXContext create_glxcontext(Display *display, struct wgl_context *contex /*********************************************************************** * create_gl_drawable */ -static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel_format *format, BOOL known_child, +static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct glx_pixel_format *format, BOOL known_child, BOOL mutable_pf ) { struct gl_drawable *gl, *prev; @@ -1390,7 +1390,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel /*********************************************************************** * set_win_format */ -static BOOL set_win_format( HWND hwnd, const struct wgl_pixel_format *format, BOOL internal ) +static BOOL set_win_format( HWND hwnd, const struct glx_pixel_format *format, BOOL internal ) { struct gl_drawable *old, *gl;
@@ -1421,7 +1421,7 @@ static BOOL set_win_format( HWND hwnd, const struct wgl_pixel_format *format, BO
static BOOL set_pixel_format( HDC hdc, int format, BOOL internal ) { - const struct wgl_pixel_format *fmt; + const struct glx_pixel_format *fmt; int value; HWND hwnd = NtUserWindowFromDC( hdc ); int prev; @@ -1552,7 +1552,7 @@ static int describe_pixel_format( int iPixelFormat, PIXELFORMATDESCRIPTOR *ppfd, /*XVisualInfo *vis;*/ int value; int rb,gb,bb,ab; - const struct wgl_pixel_format *fmt; + const struct glx_pixel_format *fmt;
if (!has_opengl()) return 0;
@@ -2155,7 +2155,7 @@ static struct wgl_pbuffer *X11DRV_wglCreatePbufferARB( HDC hdc, int iPixelFormat const int *piAttribList ) { struct wgl_pbuffer* object; - const struct wgl_pixel_format *fmt; + const struct glx_pixel_format *fmt; int attribs[256]; int nAttribs = 0;
@@ -2698,7 +2698,7 @@ static BOOL X11DRV_wglGetPixelFormatAttribivARB( HDC hdc, int iPixelFormat, int UINT nAttributes, const int *piAttributes, int *piValues ) { UINT i; - const struct wgl_pixel_format *fmt; + const struct glx_pixel_format *fmt; int hTest; int tmp; int curGLXAttr = 0;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Introduce a new wgl driver callback function to allow the driver to provide a complete list of all pixel formats along with all the information needed to implement WGL_ARB_pixel_format. --- dlls/opengl32/make_opengl | 55 ++++++++++ dlls/opengl32/unix_thunks.c | 10 +- dlls/opengl32/unix_wgl.c | 193 ++++++++++++++++++++++++++++++++++++ include/wine/wgl_driver.h | 56 ++++++++++- 4 files changed, 304 insertions(+), 10 deletions(-)
diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index b5afeeaa415..f3f669ddf93 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -193,6 +193,7 @@ my %manual_unix_functions = "glGetString" => 1, "glGetStringi" => 1, "glGetIntegerv" => 1, + "wglGetPixelFormatAttribivARB" => 1, "wglGetProcAddress" => 1, ); my %manual_wow64_thunks = @@ -890,6 +891,59 @@ printf HEADER "#define WINE_WGL_DRIVER_VERSION %u\n\n", $wgl_version + 1; print HEADER "struct wgl_context;\n"; print HEADER "struct wgl_pbuffer;\n\n";
+print HEADER "struct wgl_pixel_format\n"; +print HEADER "{\n"; +print HEADER " unsigned int id;\n"; +print HEADER " unsigned int draw_to_window:1;\n"; +print HEADER " unsigned int draw_to_bitmap:1;\n"; +print HEADER " unsigned int acceleration:2; /* 0=No, 1=Generic, 2=Full */\n"; +print HEADER " unsigned int need_palette:1;\n"; +print HEADER " unsigned int need_system_palette:1;\n"; +print HEADER " unsigned int swap_layer_buffers:1;\n"; +print HEADER " unsigned int swap_method:2; /* 0=Exchange, 1=Copy, 2=Undefined */\n"; +print HEADER " unsigned int number_overlays:8;\n"; +print HEADER " unsigned int number_underlays:8;\n"; +print HEADER " unsigned int transparent:1;\n"; +print HEADER " unsigned int support_gdi:1;\n"; +print HEADER " unsigned int support_opengl:1;\n"; +print HEADER " unsigned int double_buffer:1;\n"; +print HEADER " unsigned int stereo:1;\n"; +print HEADER " unsigned int pixel_type:2; /* 0=RGBA, 1=ColorIndex, 2=RGBA_UNSIGNED_FLOAT 3=RGBA_FLOAT */\n"; +print HEADER " unsigned int color_bits:11;\n"; +print HEADER " unsigned int red_bits:8;\n"; +print HEADER " unsigned int red_shift:8;\n"; +print HEADER " unsigned int green_bits:8;\n"; +print HEADER " unsigned int green_shift:8;\n"; +print HEADER " unsigned int blue_bits:8;\n"; +print HEADER " unsigned int blue_shift:8;\n"; +print HEADER " unsigned int alpha_bits:8;\n"; +print HEADER " unsigned int alpha_shift:8;\n"; +print HEADER " unsigned int accum_bits:8;\n"; +print HEADER " unsigned int accum_red_bits:8;\n"; +print HEADER " unsigned int accum_green_bits:8;\n"; +print HEADER " unsigned int accum_blue_bits:8;\n"; +print HEADER " unsigned int accum_alpha_bits:8;\n"; +print HEADER " unsigned int depth_bits:8;\n"; +print HEADER " unsigned int stencil_bits:8;\n"; +print HEADER " unsigned int aux_buffers:8;\n"; +print HEADER " unsigned int draw_to_pbuffer:1;\n"; +print HEADER " unsigned int max_pbuffer_pixels;\n"; +print HEADER " unsigned int max_pbuffer_width;\n"; +print HEADER " unsigned int max_pbuffer_height;\n"; +print HEADER " unsigned int transparent_red_value;\n"; +print HEADER " unsigned int transparent_green_value;\n"; +print HEADER " unsigned int transparent_blue_value;\n"; +print HEADER " unsigned int transparent_alpha_value;\n"; +print HEADER " unsigned int transparent_index_value;\n"; +print HEADER " unsigned int sample_buffers:1;\n"; +print HEADER " unsigned int samples:8;\n"; +print HEADER " unsigned int bind_to_texture_rgb:1;\n"; +print HEADER " unsigned int bind_to_texture_rgba:1;\n"; +print HEADER " unsigned int bind_to_texture_rectangle_rgb:1;\n"; +print HEADER " unsigned int bind_to_texture_rectangle_rgba:1;\n"; +print HEADER " unsigned int framebuffer_srgb_capable:1;\n"; +print HEADER "};\n\n"; + print HEADER "struct opengl_funcs\n{\n"; print HEADER " struct\n {\n"; foreach (sort keys %wgl_functions) @@ -899,6 +953,7 @@ foreach (sort keys %wgl_functions) my $func_ret = get_func_ret( $wgl_functions{$_}, 1 ); printf HEADER " %-10s (WINE_GLAPI *p_$_)($decl_args);\n", $func_ret; } +printf HEADER " %-10s (WINE_GLAPI *p_get_pixel_formats)( const struct wgl_pixel_format ** formats );\n", "UINT"; print HEADER " } wgl;\n\n";
print HEADER " struct\n {\n"; diff --git a/dlls/opengl32/unix_thunks.c b/dlls/opengl32/unix_thunks.c index a2889e7cd32..b8898d19d4e 100644 --- a/dlls/opengl32/unix_thunks.c +++ b/dlls/opengl32/unix_thunks.c @@ -41,6 +41,7 @@ extern NTSTATUS ext_wglCreateContextAttribsARB( void *args ); extern NTSTATUS ext_wglCreatePbufferARB( void *args ); extern NTSTATUS ext_wglDestroyPbufferARB( void *args ); extern NTSTATUS ext_wglGetPbufferDCARB( void *args ); +extern NTSTATUS ext_wglGetPixelFormatAttribivARB( void *args ); extern NTSTATUS ext_wglMakeContextCurrentARB( void *args ); extern NTSTATUS ext_wglQueryPbufferARB( void *args ); extern NTSTATUS ext_wglReleasePbufferDCARB( void *args ); @@ -24134,15 +24135,6 @@ static NTSTATUS ext_wglGetPixelFormatAttribfvARB( void *args ) return STATUS_SUCCESS; }
-static NTSTATUS ext_wglGetPixelFormatAttribivARB( void *args ) -{ - struct wglGetPixelFormatAttribivARB_params *params = args; - const struct opengl_funcs *funcs = get_dc_funcs( params->hdc ); - if (!funcs || !funcs->ext.p_wglGetPixelFormatAttribivARB) return STATUS_NOT_IMPLEMENTED; - params->ret = funcs->ext.p_wglGetPixelFormatAttribivARB( params->hdc, params->iPixelFormat, params->iLayerPlane, params->nAttributes, params->piAttributes, params->piValues ); - return STATUS_SUCCESS; -} - static NTSTATUS ext_wglGetSwapIntervalEXT( void *args ) { struct wglGetSwapIntervalEXT_params *params = args; diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index b75a940d1d6..eaafc7102cf 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -437,6 +437,134 @@ static BOOL check_extension_support( TEB *teb, const char *extension, const char return FALSE; }
+static BOOL wgl_attrib_uses_layer( int attrib ) +{ + switch (attrib) + { + case WGL_ACCELERATION_ARB: + case WGL_TRANSPARENT_ARB: + case WGL_SHARE_DEPTH_ARB: + case WGL_SHARE_STENCIL_ARB: + case WGL_SHARE_ACCUM_ARB: + case WGL_TRANSPARENT_RED_VALUE_ARB: + case WGL_TRANSPARENT_GREEN_VALUE_ARB: + case WGL_TRANSPARENT_BLUE_VALUE_ARB: + case WGL_TRANSPARENT_ALPHA_VALUE_ARB: + case WGL_TRANSPARENT_INDEX_VALUE_ARB: + case WGL_SUPPORT_OPENGL_ARB: + case WGL_DOUBLE_BUFFER_ARB: + case WGL_STEREO_ARB: + case WGL_PIXEL_TYPE_ARB: + case WGL_TYPE_COLORINDEX_ARB: + case WGL_COLOR_BITS_ARB: + case WGL_RED_BITS_ARB: + case WGL_RED_SHIFT_ARB: + case WGL_GREEN_BITS_ARB: + case WGL_GREEN_SHIFT_ARB: + case WGL_BLUE_BITS_ARB: + case WGL_BLUE_SHIFT_ARB: + case WGL_ALPHA_BITS_ARB: + case WGL_ALPHA_SHIFT_ARB: + case WGL_ACCUM_BITS_ARB: + case WGL_ACCUM_RED_BITS_ARB: + case WGL_ACCUM_GREEN_BITS_ARB: + case WGL_ACCUM_BLUE_BITS_ARB: + case WGL_ACCUM_ALPHA_BITS_ARB: + case WGL_DEPTH_BITS_ARB: + case WGL_STENCIL_BITS_ARB: + case WGL_AUX_BUFFERS_ARB: + return TRUE; + default: + return FALSE; + } +} + +static int wgl_pixel_format_get_attrib( const struct wgl_pixel_format *fmt, int attrib ) +{ + switch (attrib) + { + case WGL_DRAW_TO_WINDOW_ARB: return fmt->draw_to_window; + case WGL_DRAW_TO_BITMAP_ARB: return fmt->draw_to_bitmap; + case WGL_ACCELERATION_ARB: + switch (fmt->acceleration) + { + case 0: return WGL_NO_ACCELERATION_ARB; + case 1: return WGL_GENERIC_ACCELERATION_ARB; + case 2: return WGL_FULL_ACCELERATION_ARB; + } + break; + case WGL_NEED_PALETTE_ARB: return fmt->need_palette; + case WGL_NEED_SYSTEM_PALETTE_ARB: return fmt->need_system_palette; + case WGL_SWAP_LAYER_BUFFERS_ARB: return fmt->swap_layer_buffers; + case WGL_SWAP_METHOD_ARB: + switch (fmt->swap_method) + { + case 0: return WGL_SWAP_EXCHANGE_ARB; + case 1: return WGL_SWAP_COPY_ARB; + case 2: return WGL_SWAP_UNDEFINED_ARB; + } + break; + case WGL_NUMBER_OVERLAYS_ARB: return fmt->number_overlays; + case WGL_NUMBER_UNDERLAYS_ARB: return fmt->number_underlays; + case WGL_TRANSPARENT_ARB: return fmt->transparent; + case WGL_SHARE_DEPTH_ARB: + case WGL_SHARE_STENCIL_ARB: + case WGL_SHARE_ACCUM_ARB: + /* We support only a main plane at the moment which by definition + * shares the depth/stencil/accum buffers with itself. */ + return GL_TRUE; + case WGL_SUPPORT_GDI_ARB: return fmt->support_gdi; + case WGL_SUPPORT_OPENGL_ARB: return fmt->support_opengl; + case WGL_DOUBLE_BUFFER_ARB: return fmt->double_buffer; + case WGL_STEREO_ARB: return fmt->stereo; + case WGL_PIXEL_TYPE_ARB: + switch (fmt->pixel_type) + { + case 0: return WGL_TYPE_RGBA_ARB; + case 1: return WGL_TYPE_COLORINDEX_ARB; + case 2: return WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT; + case 3: return WGL_TYPE_RGBA_FLOAT_ARB; + } + break; + case WGL_COLOR_BITS_ARB: return fmt->color_bits; + case WGL_RED_BITS_ARB: return fmt->red_bits; + case WGL_RED_SHIFT_ARB: return fmt->red_shift; + case WGL_GREEN_BITS_ARB: return fmt->green_bits; + case WGL_GREEN_SHIFT_ARB: return fmt->green_shift; + case WGL_BLUE_BITS_ARB: return fmt->blue_bits; + case WGL_BLUE_SHIFT_ARB: return fmt->blue_shift; + case WGL_ALPHA_BITS_ARB: return fmt->alpha_bits; + case WGL_ALPHA_SHIFT_ARB: return fmt->alpha_shift; + case WGL_ACCUM_BITS_ARB: return fmt->accum_bits; + case WGL_ACCUM_RED_BITS_ARB: return fmt->accum_red_bits; + case WGL_ACCUM_GREEN_BITS_ARB: return fmt->accum_green_bits; + case WGL_ACCUM_BLUE_BITS_ARB: return fmt->accum_blue_bits; + case WGL_ACCUM_ALPHA_BITS_ARB: return fmt->accum_alpha_bits; + case WGL_DEPTH_BITS_ARB: return fmt->depth_bits; + case WGL_STENCIL_BITS_ARB: return fmt->stencil_bits; + case WGL_AUX_BUFFERS_ARB: return fmt->aux_buffers; + case WGL_DRAW_TO_PBUFFER_ARB: return fmt->draw_to_pbuffer; + case WGL_MAX_PBUFFER_PIXELS_ARB: return fmt->max_pbuffer_pixels; + case WGL_MAX_PBUFFER_WIDTH_ARB: return fmt->max_pbuffer_width; + case WGL_MAX_PBUFFER_HEIGHT_ARB: return fmt->max_pbuffer_height; + case WGL_TRANSPARENT_RED_VALUE_ARB: return fmt->transparent_red_value; + case WGL_TRANSPARENT_GREEN_VALUE_ARB: return fmt->transparent_green_value; + case WGL_TRANSPARENT_BLUE_VALUE_ARB: return fmt->transparent_blue_value; + case WGL_TRANSPARENT_ALPHA_VALUE_ARB: return fmt->transparent_alpha_value; + case WGL_TRANSPARENT_INDEX_VALUE_ARB: return fmt->transparent_index_value; + case WGL_SAMPLE_BUFFERS_ARB: return fmt->sample_buffers; + case WGL_SAMPLES_ARB: return fmt->samples; + case WGL_BIND_TO_TEXTURE_RGB_ARB: return fmt->bind_to_texture_rgb; + case WGL_BIND_TO_TEXTURE_RGBA_ARB: return fmt->bind_to_texture_rgba; + case WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV: return fmt->bind_to_texture_rectangle_rgb; + case WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV: return fmt->bind_to_texture_rectangle_rgba; + case WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB: return fmt->framebuffer_srgb_capable; + default: FIXME( "unsupported 0x%x WGL attribute\n", attrib ); + } + + return 0; +} + static void wrap_glGetIntegerv( TEB *teb, GLenum pname, GLint *data ) { const struct opengl_funcs *funcs = teb->glTable; @@ -828,6 +956,42 @@ static HDC wrap_wglGetPbufferDCARB( HPBUFFERARB handle ) return ptr->funcs->ext.p_wglGetPbufferDCARB( ptr->u.pbuffer ); }
+static BOOL wrap_wglGetPixelFormatAttribivARB( HDC hdc, int iPixelFormat, int iLayerPlane, + UINT nAttributes, const int *piAttributes, INT *piValues ) +{ + const struct opengl_funcs *funcs = get_dc_funcs( hdc ); + const struct wgl_pixel_format *formats, *format; + UINT num_formats; + UINT i; + + TRACE( "(%p, %d, %d, %d, %p, %p)\n", hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues ); + + num_formats = funcs->wgl.p_get_pixel_formats( &formats ); + + if (iPixelFormat > 0 && iPixelFormat - 1 < num_formats) + format = &formats[iPixelFormat - 1]; + else + format = NULL; + + for (i = 0; i < nAttributes; ++i) + { + int attrib = piAttributes[i]; + switch (attrib) + { + case WGL_NUMBER_PIXEL_FORMATS_ARB: + piValues[i] = num_formats; + break; + default: + if (format && (iLayerPlane == 0 || !wgl_attrib_uses_layer( attrib ))) + piValues[i] = wgl_pixel_format_get_attrib( format, attrib ); + else + return FALSE; + } + } + + return TRUE; +} + static BOOL wrap_wglMakeContextCurrentARB( TEB *teb, HDC draw_hdc, HDC read_hdc, HGLRC hglrc ) { BOOL ret = TRUE; @@ -1100,6 +1264,35 @@ NTSTATUS ext_wglGetPbufferDCARB( void *args ) return STATUS_SUCCESS; }
+NTSTATUS ext_wglGetPixelFormatAttribivARB( void *args ) +{ + struct wglGetPixelFormatAttribivARB_params *params = args; + const struct opengl_funcs *funcs = get_dc_funcs( params->hdc ); + + if (!funcs) return STATUS_NOT_IMPLEMENTED; + + if (funcs->ext.p_wglGetPixelFormatAttribivARB && + funcs->ext.p_wglGetPixelFormatAttribivARB != (void *)1) + { + params->ret = + funcs->ext.p_wglGetPixelFormatAttribivARB( params->hdc, params->iPixelFormat, + params->iLayerPlane, params->nAttributes, + params->piAttributes, params->piValues ); + } + else if (funcs->wgl.p_get_pixel_formats) + { + params->ret = wrap_wglGetPixelFormatAttribivARB( params->hdc, params->iPixelFormat, + params->iLayerPlane, params->nAttributes, + params->piAttributes, params->piValues ); + } + else + { + return STATUS_NOT_IMPLEMENTED; + } + + return STATUS_SUCCESS; +} + NTSTATUS ext_wglMakeContextCurrentARB( void *args ) { struct wglMakeContextCurrentARB_params *params = args; diff --git a/include/wine/wgl_driver.h b/include/wine/wgl_driver.h index 93ebe7d7f46..cb41e7c3a43 100644 --- a/include/wine/wgl_driver.h +++ b/include/wine/wgl_driver.h @@ -7,11 +7,64 @@ #define WINE_GLAPI #endif
-#define WINE_WGL_DRIVER_VERSION 23 +#define WINE_WGL_DRIVER_VERSION 24
struct wgl_context; struct wgl_pbuffer;
+struct wgl_pixel_format +{ + unsigned int id; + unsigned int draw_to_window:1; + unsigned int draw_to_bitmap:1; + unsigned int acceleration:2; /* 0=No, 1=Generic, 2=Full */ + unsigned int need_palette:1; + unsigned int need_system_palette:1; + unsigned int swap_layer_buffers:1; + unsigned int swap_method:2; /* 0=Exchange, 1=Copy, 2=Undefined */ + unsigned int number_overlays:8; + unsigned int number_underlays:8; + unsigned int transparent:1; + unsigned int support_gdi:1; + unsigned int support_opengl:1; + unsigned int double_buffer:1; + unsigned int stereo:1; + unsigned int pixel_type:2; /* 0=RGBA, 1=ColorIndex, 2=RGBA_UNSIGNED_FLOAT 3=RGBA_FLOAT */ + unsigned int color_bits:11; + unsigned int red_bits:8; + unsigned int red_shift:8; + unsigned int green_bits:8; + unsigned int green_shift:8; + unsigned int blue_bits:8; + unsigned int blue_shift:8; + unsigned int alpha_bits:8; + unsigned int alpha_shift:8; + unsigned int accum_bits:8; + unsigned int accum_red_bits:8; + unsigned int accum_green_bits:8; + unsigned int accum_blue_bits:8; + unsigned int accum_alpha_bits:8; + unsigned int depth_bits:8; + unsigned int stencil_bits:8; + unsigned int aux_buffers:8; + unsigned int draw_to_pbuffer:1; + unsigned int max_pbuffer_pixels; + unsigned int max_pbuffer_width; + unsigned int max_pbuffer_height; + unsigned int transparent_red_value; + unsigned int transparent_green_value; + unsigned int transparent_blue_value; + unsigned int transparent_alpha_value; + unsigned int transparent_index_value; + unsigned int sample_buffers:1; + unsigned int samples:8; + unsigned int bind_to_texture_rgb:1; + unsigned int bind_to_texture_rgba:1; + unsigned int bind_to_texture_rectangle_rgb:1; + unsigned int bind_to_texture_rectangle_rgba:1; + unsigned int framebuffer_srgb_capable:1; +}; + struct opengl_funcs { struct @@ -26,6 +79,7 @@ struct opengl_funcs BOOL (WINE_GLAPI *p_wglSetPixelFormat)( HDC hdc, int ipfd, const PIXELFORMATDESCRIPTOR *ppfd ); BOOL (WINE_GLAPI *p_wglShareLists)( struct wgl_context * hrcSrvShare, struct wgl_context * hrcSrvSource ); BOOL (WINE_GLAPI *p_wglSwapBuffers)( HDC hdc ); + UINT (WINE_GLAPI *p_get_pixel_formats)( const struct wgl_pixel_format ** formats ); } wgl;
struct
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/opengl32/make_opengl | 1 + dlls/opengl32/unix_thunks.c | 10 +----- dlls/opengl32/unix_wgl.c | 65 +++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 9 deletions(-)
diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index f3f669ddf93..e17b7aedc36 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -194,6 +194,7 @@ my %manual_unix_functions = "glGetStringi" => 1, "glGetIntegerv" => 1, "wglGetPixelFormatAttribivARB" => 1, + "wglGetPixelFormatAttribfvARB" => 1, "wglGetProcAddress" => 1, ); my %manual_wow64_thunks = diff --git a/dlls/opengl32/unix_thunks.c b/dlls/opengl32/unix_thunks.c index b8898d19d4e..eae1697617b 100644 --- a/dlls/opengl32/unix_thunks.c +++ b/dlls/opengl32/unix_thunks.c @@ -41,6 +41,7 @@ extern NTSTATUS ext_wglCreateContextAttribsARB( void *args ); extern NTSTATUS ext_wglCreatePbufferARB( void *args ); extern NTSTATUS ext_wglDestroyPbufferARB( void *args ); extern NTSTATUS ext_wglGetPbufferDCARB( void *args ); +extern NTSTATUS ext_wglGetPixelFormatAttribfvARB( void *args ); extern NTSTATUS ext_wglGetPixelFormatAttribivARB( void *args ); extern NTSTATUS ext_wglMakeContextCurrentARB( void *args ); extern NTSTATUS ext_wglQueryPbufferARB( void *args ); @@ -24126,15 +24127,6 @@ NTSTATUS ext_wglGetExtensionsStringEXT( void *args ) return STATUS_SUCCESS; }
-static NTSTATUS ext_wglGetPixelFormatAttribfvARB( void *args ) -{ - struct wglGetPixelFormatAttribfvARB_params *params = args; - const struct opengl_funcs *funcs = get_dc_funcs( params->hdc ); - if (!funcs || !funcs->ext.p_wglGetPixelFormatAttribfvARB) return STATUS_NOT_IMPLEMENTED; - params->ret = funcs->ext.p_wglGetPixelFormatAttribfvARB( params->hdc, params->iPixelFormat, params->iLayerPlane, params->nAttributes, params->piAttributes, params->pfValues ); - return STATUS_SUCCESS; -} - static NTSTATUS ext_wglGetSwapIntervalEXT( void *args ) { struct wglGetSwapIntervalEXT_params *params = args; diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index eaafc7102cf..4fc7eab18a8 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -992,6 +992,42 @@ static BOOL wrap_wglGetPixelFormatAttribivARB( HDC hdc, int iPixelFormat, int iL return TRUE; }
+static BOOL wrap_wglGetPixelFormatAttribfvARB( HDC hdc, int iPixelFormat, int iLayerPlane, + UINT nAttributes, const int *pfAttributes, FLOAT *pfValues ) +{ + const struct opengl_funcs *funcs = get_dc_funcs( hdc ); + const struct wgl_pixel_format *formats, *format; + UINT num_formats; + UINT i; + + TRACE( "(%p, %d, %d, %d, %p, %p)\n", hdc, iPixelFormat, iLayerPlane, nAttributes, pfAttributes, pfValues ); + + num_formats = funcs->wgl.p_get_pixel_formats( &formats ); + + if (iPixelFormat > 0 && iPixelFormat - 1 < num_formats) + format = &formats[iPixelFormat - 1]; + else + format = NULL; + + for (i = 0; i < nAttributes; ++i) + { + int attrib = pfAttributes[i]; + switch (attrib) + { + case WGL_NUMBER_PIXEL_FORMATS_ARB: + pfValues[i] = num_formats; + break; + default: + if (format && (iLayerPlane == 0 || !wgl_attrib_uses_layer( attrib ))) + pfValues[i] = wgl_pixel_format_get_attrib( format, attrib ); + else + return FALSE; + } + } + + return TRUE; +} + static BOOL wrap_wglMakeContextCurrentARB( TEB *teb, HDC draw_hdc, HDC read_hdc, HGLRC hglrc ) { BOOL ret = TRUE; @@ -1293,6 +1329,35 @@ NTSTATUS ext_wglGetPixelFormatAttribivARB( void *args ) return STATUS_SUCCESS; }
+NTSTATUS ext_wglGetPixelFormatAttribfvARB( void *args ) +{ + struct wglGetPixelFormatAttribfvARB_params *params = args; + const struct opengl_funcs *funcs = get_dc_funcs( params->hdc ); + + if (!funcs) return STATUS_NOT_IMPLEMENTED; + + if (funcs->ext.p_wglGetPixelFormatAttribfvARB && + funcs->ext.p_wglGetPixelFormatAttribfvARB != (void *)1) + { + params->ret = + funcs->ext.p_wglGetPixelFormatAttribfvARB( params->hdc, params->iPixelFormat, + params->iLayerPlane, params->nAttributes, + params->piAttributes, params->pfValues ); + } + else if (funcs->wgl.p_get_pixel_formats) + { + params->ret = wrap_wglGetPixelFormatAttribfvARB( params->hdc, params->iPixelFormat, + params->iLayerPlane, params->nAttributes, + params->piAttributes, params->pfValues ); + } + else + { + return STATUS_NOT_IMPLEMENTED; + } + + return STATUS_SUCCESS; +} + NTSTATUS ext_wglMakeContextCurrentARB( void *args ) { struct wglMakeContextCurrentARB_params *params = args;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/opengl32/make_opengl | 1 + dlls/opengl32/unix_thunks.c | 10 +- dlls/opengl32/unix_wgl.c | 257 ++++++++++++++++++++++++++++++++++++ 3 files changed, 259 insertions(+), 9 deletions(-)
diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index e17b7aedc36..342308d5eb1 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -193,6 +193,7 @@ my %manual_unix_functions = "glGetString" => 1, "glGetStringi" => 1, "glGetIntegerv" => 1, + "wglChoosePixelFormatARB" => 1, "wglGetPixelFormatAttribivARB" => 1, "wglGetPixelFormatAttribfvARB" => 1, "wglGetProcAddress" => 1, diff --git a/dlls/opengl32/unix_thunks.c b/dlls/opengl32/unix_thunks.c index eae1697617b..d8215718e06 100644 --- a/dlls/opengl32/unix_thunks.c +++ b/dlls/opengl32/unix_thunks.c @@ -37,6 +37,7 @@ extern NTSTATUS ext_glDebugMessageCallbackAMD( void *args ); extern NTSTATUS ext_glDebugMessageCallbackARB( void *args ); extern NTSTATUS ext_glGetStringi( void *args ); extern NTSTATUS ext_wglBindTexImageARB( void *args ); +extern NTSTATUS ext_wglChoosePixelFormatARB( void *args ); extern NTSTATUS ext_wglCreateContextAttribsARB( void *args ); extern NTSTATUS ext_wglCreatePbufferARB( void *args ); extern NTSTATUS ext_wglDestroyPbufferARB( void *args ); @@ -24085,15 +24086,6 @@ static NTSTATUS ext_wglAllocateMemoryNV( void *args ) return STATUS_SUCCESS; }
-static NTSTATUS ext_wglChoosePixelFormatARB( void *args ) -{ - struct wglChoosePixelFormatARB_params *params = args; - const struct opengl_funcs *funcs = get_dc_funcs( params->hdc ); - if (!funcs || !funcs->ext.p_wglChoosePixelFormatARB) return STATUS_NOT_IMPLEMENTED; - params->ret = funcs->ext.p_wglChoosePixelFormatARB( params->hdc, params->piAttribIList, params->pfAttribFList, params->nMaxFormats, params->piFormats, params->nNumFormats ); - return STATUS_SUCCESS; -} - static NTSTATUS ext_wglFreeMemoryNV( void *args ) { struct wglFreeMemoryNV_params *params = args; diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 4fc7eab18a8..257b91cbaf5 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -926,6 +926,234 @@ static HGLRC wrap_wglCreateContextAttribsARB( HDC hdc, HGLRC share, const int *a return ret; }
+enum attrib_match +{ + ATTRIB_MATCH_IGNORE, + ATTRIB_MATCH_EXACT, + ATTRIB_MATCH_MINIMUM, +}; + +static enum attrib_match wgl_attrib_match_criteria( int attrib ) +{ + switch (attrib) + { + case WGL_DRAW_TO_WINDOW_ARB: + case WGL_DRAW_TO_BITMAP_ARB: + case WGL_ACCELERATION_ARB: + case WGL_NEED_PALETTE_ARB: + case WGL_NEED_SYSTEM_PALETTE_ARB: + case WGL_SWAP_LAYER_BUFFERS_ARB: + case WGL_SWAP_METHOD_ARB: + case WGL_SHARE_DEPTH_ARB: + case WGL_SHARE_STENCIL_ARB: + case WGL_SHARE_ACCUM_ARB: + case WGL_SUPPORT_GDI_ARB: + case WGL_SUPPORT_OPENGL_ARB: + case WGL_DOUBLE_BUFFER_ARB: + case WGL_STEREO_ARB: + case WGL_PIXEL_TYPE_ARB: + return ATTRIB_MATCH_EXACT; + case WGL_NUMBER_OVERLAYS_ARB: + case WGL_NUMBER_UNDERLAYS_ARB: + case WGL_COLOR_BITS_ARB: + case WGL_RED_BITS_ARB: + case WGL_GREEN_BITS_ARB: + case WGL_BLUE_BITS_ARB: + case WGL_ALPHA_BITS_ARB: + case WGL_ACCUM_BITS_ARB: + case WGL_ACCUM_RED_BITS_ARB: + case WGL_ACCUM_GREEN_BITS_ARB: + case WGL_ACCUM_BLUE_BITS_ARB: + case WGL_ACCUM_ALPHA_BITS_ARB: + case WGL_DEPTH_BITS_ARB: + case WGL_STENCIL_BITS_ARB: + case WGL_AUX_BUFFERS_ARB: + return ATTRIB_MATCH_MINIMUM; + default: + return ATTRIB_MATCH_IGNORE; + } +} + +static void filter_format_array( const struct wgl_pixel_format **array, + UINT num_formats, int attrib, int value ) +{ + UINT i; + enum attrib_match match = wgl_attrib_match_criteria( attrib ); + + TRACE( "filtering formats for attrib=0x%x value=%d\n", attrib, value ); + + for (i = 0; i < num_formats; ++i) + { + int fmt_value; + if (!array[i]) continue; + fmt_value = wgl_pixel_format_get_attrib( array[i], attrib ); + if (match == ATTRIB_MATCH_EXACT) + { + if (fmt_value != value) + { + TRACE( " removing id=%d value=%d != %d\n", array[i]->id, fmt_value, value ); + array[i] = NULL; + } + } + else if (match == ATTRIB_MATCH_MINIMUM) + { + if (fmt_value < value) + { + TRACE( " removing id=%d value=%d < %d\n", array[i]->id, fmt_value, value ); + array[i] = NULL; + } + } + } +} + +struct compare_formats_ctx +{ + BOOL r, g, b, a, d; + BOOL accum_r, accum_g, accum_b, accum_a; +}; + +static void update_compare_formats_ctx( struct compare_formats_ctx *ctx, + int attrib, int value ) +{ + switch (attrib) + { + case WGL_RED_BITS_ARB: if (value > 0) ctx->r = TRUE; break; + case WGL_GREEN_BITS_ARB: if (value > 0) ctx->g = TRUE; break; + case WGL_BLUE_BITS_ARB: if (value > 0) ctx->b = TRUE; break; + case WGL_ALPHA_BITS_ARB: if (value > 0) ctx->a = TRUE; break; + case WGL_ACCUM_RED_BITS_ARB: if (value > 0) ctx->accum_r = TRUE; break; + case WGL_ACCUM_GREEN_BITS_ARB: if (value > 0) ctx->accum_g = TRUE; break; + case WGL_ACCUM_BLUE_BITS_ARB: if (value > 0) ctx->accum_b = TRUE; break; + case WGL_ACCUM_ALPHA_BITS_ARB: if (value > 0) ctx->accum_a = TRUE; break; + case WGL_DEPTH_BITS_ARB: if (value > 0) ctx->d = TRUE; break; + } +} + +static int compare_formats( const void *a, const void *b, void *arg ) +{ + const struct wgl_pixel_format *fmt_a = *(void**)a, *fmt_b = *(void**)b; + struct compare_formats_ctx *ctx = arg; + int bits_a = 0, bits_b = 0; + int accum_bits_a = 0, accum_bits_b = 0; + + if (!fmt_a) return 1; + if (!fmt_b) return -1; + +#define ORDER_BY_DECREASING(field) \ + do { if (fmt_a->field != fmt_b->field) return fmt_b->field - fmt_a->field; } while(0) +#define ORDER_BY_INCREASING(field) \ + do { if (fmt_a->field != fmt_b->field) return fmt_a->field - fmt_b->field; } while(0) +#define ORDER_BY_DECREASING_RELEVANT_BITS(p) \ + if (!ctx || ctx->p##r) { p##bits_a += fmt_a->p##red_bits; bits_b += fmt_b->p##red_bits; } \ + if (!ctx || ctx->p##g) { p##bits_a += fmt_a->p##green_bits; bits_b += fmt_b->p##green_bits; } \ + if (!ctx || ctx->p##b) { p##bits_a += fmt_a->p##blue_bits; bits_b += fmt_b->p##blue_bits; } \ + if (!ctx || ctx->p##a) { p##bits_a += fmt_a->p##alpha_bits; bits_b += fmt_b->p##alpha_bits; } \ + if (p##bits_a != p##bits_b) return p##bits_b - p##bits_a; + + /* Window renderable first. */ + ORDER_BY_DECREASING(draw_to_window); + /* Larger total number of relevant color bits first. */ + ORDER_BY_DECREASING_RELEVANT_BITS(); + /* Smaller buffer size first. */ + ORDER_BY_INCREASING(color_bits); + /* Smaller sample buffers size first. */ + ORDER_BY_INCREASING(sample_buffers); + /* Smaller samples size first. */ + ORDER_BY_INCREASING(samples); + /* GLX places larger depths first. EGL places smaller depths first. + * For now use what WineX11 does: larger depths first, except if no depth + * is specified in which case smaller depths first. */ + if (ctx && ctx->d) + ORDER_BY_DECREASING(depth_bits); + else + ORDER_BY_INCREASING(depth_bits); + /* Smaller stencil bits size first. */ + ORDER_BY_INCREASING(stencil_bits); + /* Larger total number of relevant accum bits first. */ + ORDER_BY_DECREASING_RELEVANT_BITS(accum_); + +#undef ORDER_BY_DECREASING +#undef ORDER_BY_INCREASING +#undef ORDER_BY_DECREASING_RELEVANT_BITS + + return fmt_a->id - fmt_b->id; +} + +#if defined(__FreeBSD__) && __FreeBSD__ < 14 +/* FreeBSD versions < 14 place the context argument first. */ +static int compare_formats_freebsd( void *arg, const void *a, const void *b ) +{ + return compare_formats( a, b, arg ); +} +#endif + +#if !defined(_GNU_SOURCE) && !defined(__FreeBSD__) +static int compare_formats_no_ctx( const void *a, const void *b ) +{ + return compare_formats( a, b, NULL ); +} +#endif + +static BOOL wrap_wglChoosePixelFormatARB( HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, + UINT nMaxFormats, int *piFormats, UINT *nNumFormats ) +{ + const struct opengl_funcs *funcs = get_dc_funcs( hdc ); + const struct wgl_pixel_format *formats; + UINT num_formats; + UINT i; + const int *attribi = piAttribIList; + const FLOAT *attribf = pfAttribFList; + const struct wgl_pixel_format **format_array; + struct compare_formats_ctx ctx = {0}; + + TRACE( "(%p, %p, %p, %d, %p, %p)\n", + hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats ); + + /* Initialize the format_array with (pointers to) all formats. */ + num_formats = funcs->wgl.p_get_pixel_formats( &formats ); + format_array = malloc( num_formats * sizeof(*format_array) ); + if (!format_array) return FALSE; + for (i = 0; i < num_formats; i++) format_array[i] = &formats[i]; + + /* Remove formats that are not acceptable. */ + for (; attribi && *attribi; attribi += 2) + { + filter_format_array( format_array, num_formats, attribi[0], attribi[1] ); + update_compare_formats_ctx( &ctx, attribi[0], attribi[1] ); + } + for (; attribf && *attribf; attribf += 2) + { + filter_format_array( format_array, num_formats, attribf[0], attribf[1] ); + update_compare_formats_ctx( &ctx, attribf[0], attribf[1] ); + } + + /* Sort formats based on attributes. */ +#if defined(_GNU_SOURCE) || __FreeBSD__ >= 14 + qsort_r( format_array, num_formats, sizeof(*format_array), compare_formats, &ctx ); +#elif defined(__FreeBSD__) + qsort_r( format_array, num_formats, sizeof(*format_array), ctx, compare_formats_freebsd ); +#else + qsort( format_array, num_formats, sizeof(*format_array), compare_formats_no_ctx ); +#endif + + TRACE( "Sorted formats (max=%d): ", nMaxFormats ); + for (i = 0; i < num_formats && format_array[i]; i++) + TRACE("%d, ", format_array[i]->id); + TRACE( "\n" ); + + /* Return the best nMaxFormats format ids. */ + *nNumFormats = 0; + for (i = 0; i < num_formats && i < nMaxFormats && format_array[i]; i++) + { + (*nNumFormats)++; + piFormats[i] = format_array[i]->id; + } + + free( format_array ); + + return TRUE; +} + static HPBUFFERARB wrap_wglCreatePbufferARB( HDC hdc, int format, int width, int height, const int *attribs ) { HPBUFFERARB ret; @@ -1264,6 +1492,35 @@ NTSTATUS ext_wglBindTexImageARB( void *args ) return STATUS_SUCCESS; }
+NTSTATUS ext_wglChoosePixelFormatARB( void *args ) +{ + struct wglChoosePixelFormatARB_params *params = args; + const struct opengl_funcs *funcs = get_dc_funcs( params->hdc ); + + if (!funcs) return STATUS_NOT_IMPLEMENTED; + + if (funcs->ext.p_wglChoosePixelFormatARB && + funcs->ext.p_wglChoosePixelFormatARB != (void *)1) + { + params->ret = + funcs->ext.p_wglChoosePixelFormatARB( params->hdc, params->piAttribIList, + params->pfAttribFList, params->nMaxFormats, + params->piFormats, params->nNumFormats ); + } + else if (funcs->wgl.p_get_pixel_formats) + { + params->ret = + wrap_wglChoosePixelFormatARB( params->hdc, params->piAttribIList, + params->pfAttribFList, params->nMaxFormats, + params->piFormats, params->nNumFormats ); + } + else + { + return STATUS_NOT_IMPLEMENTED; + } + return STATUS_SUCCESS; +} + NTSTATUS ext_wglCreateContextAttribsARB( void *args ) { struct wglCreateContextAttribsARB_params *params = args;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 103 +++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 8 deletions(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index f072b8063a1..ee2ad362aa6 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -48,6 +48,7 @@ static struct opengl_funcs opengl_funcs; static EGLDisplay egl_display; static char wgl_extensions[4096]; static EGLConfig *egl_configs; +static struct wgl_pixel_format *wgl_pixel_formats; static int num_egl_configs;
#define USE_GL_FUNC(name) #name, @@ -546,6 +547,7 @@ static BOOL wayland_wglDeleteContext(struct wgl_context *ctx)
static BOOL has_opengl(void);
+/* TODO: We can use the wgl_pixel_formats to implement this, possibly in opengl32 */ static int wayland_wglDescribePixelFormat(HDC hdc, int fmt, UINT size, PIXELFORMATDESCRIPTOR *pfd) { @@ -762,6 +764,12 @@ static BOOL wayland_wglSwapIntervalEXT(int interval) return ret; }
+static UINT wayland_get_pixel_formats(const struct wgl_pixel_format **formats) +{ + *formats = wgl_pixel_formats; + return num_egl_configs; +} + static BOOL has_extension(const char *list, const char *ext) { size_t len = strlen(ext); @@ -822,9 +830,75 @@ static BOOL init_opengl_funcs(void) opengl_funcs.ext.p_wglGetSwapIntervalEXT = wayland_wglGetSwapIntervalEXT; opengl_funcs.ext.p_wglSwapIntervalEXT = wayland_wglSwapIntervalEXT;
+ register_extension("WGL_ARB_pixel_format"); + register_extension("WGL_ARB_pixel_format_float"); + register_extension("WGL_ATI_pixel_format_float"); + /* We use the default implementation from opengl32 based on p_get_pixel_formats. + * We still need to mark these as non-NULL so that the extension is detected. */ + opengl_funcs.ext.p_wglChoosePixelFormatARB = (void *)1; + opengl_funcs.ext.p_wglGetPixelFormatAttribivARB = (void *)1; + opengl_funcs.ext.p_wglGetPixelFormatAttribfvARB = (void *)1; + return TRUE; }
+static void convert_egl_to_wgl_format(EGLConfig config, int id, + struct wgl_pixel_format *fmt) +{ + EGLint value; + + fmt->id = id; + fmt->draw_to_window = GL_TRUE; + fmt->acceleration = 2; /* Full acceleration */ + fmt->support_opengl = GL_TRUE; + fmt->double_buffer = GL_TRUE; + +#define SET_ATTRIB(wgl_field, attrib) \ + value = 0; \ + p_eglGetConfigAttrib(egl_display, config, attrib, &value); \ + fmt->wgl_field = value; + +#define SET_ATTRIB_VALUE(wgl_field, attrib, val) \ + value = 0; \ + p_eglGetConfigAttrib(egl_display, config, attrib, &value); \ + fmt->wgl_field = val; + + SET_ATTRIB_VALUE(transparent, EGL_TRANSPARENT_TYPE, (value == EGL_TRANSPARENT_RGB)); + SET_ATTRIB_VALUE(pixel_type, EGL_COLOR_COMPONENT_TYPE_EXT, + (value == EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT) ? 3 : 0); + + SET_ATTRIB(color_bits, EGL_BUFFER_SIZE); + SET_ATTRIB(red_bits, EGL_RED_SIZE); + SET_ATTRIB(green_bits, EGL_GREEN_SIZE); + SET_ATTRIB(blue_bits, EGL_BLUE_SIZE); + SET_ATTRIB(alpha_bits, 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. */ + fmt->blue_shift = 0; + fmt->green_shift = fmt->blue_bits; + fmt->red_shift = fmt->green_bits + fmt->blue_bits; + if (fmt->alpha_bits) + fmt->alpha_shift = fmt->red_bits + fmt->green_bits + fmt->blue_bits; + else + fmt->alpha_shift = 0; + + SET_ATTRIB(depth_bits, EGL_DEPTH_SIZE); + SET_ATTRIB(stencil_bits, EGL_STENCIL_SIZE); + SET_ATTRIB(transparent_red_value, EGL_TRANSPARENT_RED_VALUE); + SET_ATTRIB(transparent_green_value, EGL_TRANSPARENT_GREEN_VALUE); + SET_ATTRIB(transparent_blue_value, EGL_TRANSPARENT_BLUE_VALUE); + SET_ATTRIB(sample_buffers, EGL_SAMPLE_BUFFERS); + SET_ATTRIB(samples, EGL_SAMPLES); + SET_ATTRIB(bind_to_texture_rgb, EGL_BIND_TO_TEXTURE_RGB); + SET_ATTRIB(bind_to_texture_rgba, EGL_BIND_TO_TEXTURE_RGBA); + /* Rectangle? */ + + /* TODO: Advertise SRGB and support it for surface creation*/ + +#undef SET_ATTRIB +#undef SET_ATTRIB_VALUE +} + static BOOL init_egl_configs(void) { EGLint i; @@ -852,23 +926,35 @@ static BOOL init_egl_configs(void) return FALSE; }
- if (TRACE_ON(waylanddrv)) + if (!(wgl_pixel_formats = calloc(1, num_egl_configs * sizeof(*wgl_pixel_formats)))) + { + ERR("Failed to allocate memory for wgl_pixel_formats\n"); + free(egl_configs); + egl_configs = NULL; + return FALSE; + } + + for (i = 0; i < num_egl_configs; i++) { - for (i = 0; i < num_egl_configs; i++) + convert_egl_to_wgl_format(egl_configs[i], i + 1, &wgl_pixel_formats[i]); + + if (TRACE_ON(waylanddrv)) { EGLint id, type, visual_id, native, render, color, r, g, b, a, d, s; + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_NATIVE_VISUAL_ID, &visual_id); p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_SURFACE_TYPE, &type); p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_RENDERABLE_TYPE, &render); p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_CONFIG_ID, &id); p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_NATIVE_RENDERABLE, &native); p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_COLOR_BUFFER_TYPE, &color); - p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_RED_SIZE, &r); - p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_GREEN_SIZE, &g); - p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_BLUE_SIZE, &b); - p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_ALPHA_SIZE, &a); - p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_DEPTH_SIZE, &d); - p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_STENCIL_SIZE, &s); + r = wgl_pixel_formats[i].red_bits; + g = wgl_pixel_formats[i].green_bits; + b = wgl_pixel_formats[i].blue_bits; + a = wgl_pixel_formats[i].alpha_bits; + d = wgl_pixel_formats[i].depth_bits; + s = wgl_pixel_formats[i].stencil_bits; + 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", num_egl_configs, i, id, type, visual_id, native, render, @@ -986,6 +1072,7 @@ static struct opengl_funcs opengl_funcs = .p_wglSetPixelFormat = wayland_wglSetPixelFormat, .p_wglShareLists = wayland_wglShareLists, .p_wglSwapBuffers = wayland_wglSwapBuffers, + .p_get_pixel_formats = wayland_get_pixel_formats, } };
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Just an experiment to evaluate how the opengl32 wglChoosePixelFormatARB implementation based on wgl.get_pixel_formats compares to WineX11's implementation. --- dlls/opengl32/unix_wgl.c | 16 ++++- dlls/winex11.drv/opengl.c | 120 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 257b91cbaf5..b83c4e4cf70 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -1496,6 +1496,7 @@ NTSTATUS ext_wglChoosePixelFormatARB( void *args ) { struct wglChoosePixelFormatARB_params *params = args; const struct opengl_funcs *funcs = get_dc_funcs( params->hdc ); + UINT i;
if (!funcs) return STATUS_NOT_IMPLEMENTED;
@@ -1506,18 +1507,31 @@ NTSTATUS ext_wglChoosePixelFormatARB( void *args ) funcs->ext.p_wglChoosePixelFormatARB( params->hdc, params->piAttribIList, params->pfAttribFList, params->nMaxFormats, params->piFormats, params->nNumFormats ); + TRACE("Formats from driver impl (max=%d): ", params->nMaxFormats); + for (i = 0; i < *params->nNumFormats; i++) + TRACE("%d, ", params->piFormats[i]); + TRACE("\n"); } - else if (funcs->wgl.p_get_pixel_formats) + + + if (funcs->wgl.p_get_pixel_formats) { params->ret = wrap_wglChoosePixelFormatARB( params->hdc, params->piAttribIList, params->pfAttribFList, params->nMaxFormats, params->piFormats, params->nNumFormats ); + TRACE("Formats from opengl32 impl (max=%d): ", params->nMaxFormats); + for (i = 0; i < *params->nNumFormats; i++) + TRACE("%d, ", params->piFormats[i]); + TRACE("\n"); } + + /* else { return STATUS_NOT_IMPLEMENTED; } + */ return STATUS_SUCCESS; }
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 08b6d8f67e2..f80bcc15c4f 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -267,6 +267,7 @@ static XContext gl_pbuffer_context; static struct list context_list = LIST_INIT( context_list ); static struct list pbuffer_list = LIST_INIT( pbuffer_list ); static struct glx_pixel_format *pixel_formats; +static struct wgl_pixel_format *wgl_pixel_formats; static int nb_pixel_formats, nb_onscreen_formats; static BOOL use_render_texture_emulation = TRUE;
@@ -996,6 +997,109 @@ static BOOL check_fbconfig_bitmap_capability(Display *display, GLXFBConfig fbcon return !dbuf && (value & GLX_PIXMAP_BIT); }
+static void init_wgl_pixel_format(Display *display, int i) +{ + struct glx_pixel_format *glx = &pixel_formats[i]; + struct wgl_pixel_format *fmt = &wgl_pixel_formats[i]; + int value; + + fmt->id = i + 1; + fmt->support_opengl = GL_TRUE; + +#define SET_ATTRIB(wgl_field, attrib) \ + value = 0; \ + pglXGetFBConfigAttrib(display, glx->fbconfig, attrib, &value); \ + fmt->wgl_field = value; + +#define SET_ATTRIB_VALUE(wgl_field, attrib, val) \ + value = 0; \ + pglXGetFBConfigAttrib(display, glx->fbconfig, attrib, &value); \ + fmt->wgl_field = val; + + SET_ATTRIB_VALUE(draw_to_window, GLX_DRAWABLE_TYPE, !!(value & GLX_WINDOW_BIT)); + + fmt->draw_to_bitmap = !!(glx->dwFlags & PFD_DRAW_TO_BITMAP); + if (glx->dwFlags & PFD_GENERIC_FORMAT) + fmt->acceleration = 0; + else if (glx->dwFlags & PFD_GENERIC_ACCELERATED) + fmt->acceleration = 1; + else + fmt->acceleration = 2; + + value = 0; + pglXGetFBConfigAttrib(display, glx->fbconfig, GLX_SWAP_METHOD_OML, &value); + switch (value) + { + case GLX_SWAP_COPY_OML: + fmt->swap_method = 1; + break; + case GLX_SWAP_UNDEFINED_OML: + fmt->swap_method = 2; + break; + case GLX_SWAP_EXCHANGE_OML: + default: + fmt->swap_method = 0; + break; + } + + SET_ATTRIB_VALUE(transparent, GLX_TRANSPARENT_TYPE, (value != GLX_NONE)); + + fmt->support_gdi = !!(glx->dwFlags & PFD_SUPPORT_GDI); + SET_ATTRIB(double_buffer, GLX_DOUBLEBUFFER); + if (fmt->double_buffer) fmt->support_gdi = GL_FALSE; + SET_ATTRIB(stereo, GLX_STEREO); + + value = 0; + pglXGetFBConfigAttrib(display, glx->fbconfig, GLX_RENDER_TYPE, &value); + if (value & GLX_RGBA_BIT) { fmt->pixel_type = 0; } + else if (value & GLX_COLOR_INDEX_BIT) { fmt->pixel_type = 1; } + else if (value & GLX_RGBA_FLOAT_BIT) { fmt->pixel_type = 2; } + else if (value & GLX_RGBA_FLOAT_ATI_BIT) { fmt->pixel_type = 2; } + else if (value & GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT) { fmt->pixel_type = 3; } + + SET_ATTRIB(color_bits, GLX_BUFFER_SIZE); + SET_ATTRIB(red_bits, GLX_RED_SIZE); + SET_ATTRIB(green_bits, GLX_GREEN_SIZE); + SET_ATTRIB(blue_bits, GLX_BLUE_SIZE); + SET_ATTRIB(alpha_bits, GLX_ALPHA_SIZE); + /* Assume 0xARGB order */ + fmt->blue_shift = 0; + fmt->green_shift = fmt->blue_bits; + fmt->red_shift = fmt->green_bits + fmt->blue_bits; + if (fmt->alpha_bits) + fmt->alpha_shift = fmt->red_bits + fmt->green_bits + fmt->blue_bits; + else + fmt->alpha_shift = 0; + + SET_ATTRIB(accum_red_bits, GLX_ACCUM_RED_SIZE); + SET_ATTRIB(accum_green_bits, GLX_ACCUM_GREEN_SIZE); + SET_ATTRIB(accum_blue_bits, GLX_ACCUM_BLUE_SIZE); + SET_ATTRIB(accum_alpha_bits, GLX_ACCUM_ALPHA_SIZE); + fmt->accum_bits = fmt->accum_red_bits + fmt->accum_green_bits + + fmt->accum_blue_bits + fmt->accum_alpha_bits; + + SET_ATTRIB(depth_bits, GLX_DEPTH_SIZE); + SET_ATTRIB(stencil_bits, GLX_STENCIL_SIZE); + SET_ATTRIB(aux_buffers, GLX_AUX_BUFFERS); + SET_ATTRIB_VALUE(draw_to_pbuffer, GLX_DRAWABLE_TYPE, !!(value & GLX_PBUFFER_BIT)); + SET_ATTRIB(transparent_red_value, GLX_TRANSPARENT_RED_VALUE); + SET_ATTRIB(transparent_green_value, GLX_TRANSPARENT_GREEN_VALUE); + SET_ATTRIB(transparent_blue_value, GLX_TRANSPARENT_BLUE_VALUE); + SET_ATTRIB(transparent_alpha_value, GLX_TRANSPARENT_ALPHA_VALUE); + SET_ATTRIB(transparent_index_value, GLX_TRANSPARENT_INDEX_VALUE); + SET_ATTRIB(sample_buffers, GLX_SAMPLE_BUFFERS_ARB); + SET_ATTRIB(samples, GLX_SAMPLES_ARB); + if (use_render_texture_emulation && fmt->pixel_type != 1 && fmt->draw_to_pbuffer) + { + fmt->bind_to_texture_rgb = GL_TRUE; + fmt->bind_to_texture_rgba = GL_TRUE; + } + SET_ATTRIB(framebuffer_srgb_capable, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT); + +#undef SET_ATTRIB +#undef SET_ATTRIB_VALUE +} + static void init_pixel_formats( Display *display ) { struct glx_pixel_format *list; @@ -1105,6 +1209,10 @@ static void init_pixel_formats( Display *display ) pixel_formats = list; nb_pixel_formats = size; nb_onscreen_formats = onscreen_size; + + wgl_pixel_formats = calloc(nb_pixel_formats, sizeof(*wgl_pixel_formats)); + for (i = 0; i < nb_pixel_formats; ++i) + init_wgl_pixel_format(display, i); }
static inline BOOL is_valid_pixel_format( int format ) @@ -2680,6 +2788,11 @@ static BOOL X11DRV_wglChoosePixelFormatARB( HDC hdc, const int *piAttribIList, c
qsort(formats, format_count, sizeof(*formats), compare_formats);
+ TRACE("Sorted formats (max=%d): ", nMaxFormats); + for (i = 0; i < format_count ; i++) + TRACE("%d, ", formats[i].format); + TRACE("\n"); + *nNumFormats = min(nMaxFormats, format_count); for (i = 0; i < *nNumFormats; ++i) piFormats[i] = formats[i].format; @@ -3418,6 +3531,12 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) return TRUE; }
+UINT glxdrv_get_pixel_formats( const struct wgl_pixel_format **formats ) +{ + *formats = wgl_pixel_formats; + return nb_pixel_formats; +} + static struct opengl_funcs opengl_funcs = { { @@ -3431,6 +3550,7 @@ static struct opengl_funcs opengl_funcs = glxdrv_wglSetPixelFormat, /* p_wglSetPixelFormat */ glxdrv_wglShareLists, /* p_wglShareLists */ glxdrv_wglSwapBuffers, /* p_wglSwapBuffers */ + glxdrv_get_pixel_formats, } };
Sorry for the late feedback. Ofc there's a couple of comments here and there but IMO this looks quite nice already. Then let's explore some options to make it even better:
1) What about moving it even further to the PE side? Keeping only p_get_pixel_formats as a unix call, and pre-allocating a large-enough array to hold the pixel formats (or making two calls if it's not large enough), which could even be cached in some of the glReserved1 thread data - with the HDC to invalidate the cache when necessary.
2) Have you checked how these functions behave on Windows? Are they very different across drivers and hardware or can we find a pixels format subset that we could simply fake? How useful / likely is it to have some exotic formats exposed and used by applications?
On Thu Mar 28 17:02:44 2024 +0000, Rémi Bernon wrote:
Sorry for the late feedback. Ofc there's a couple of comments here and there but IMO this looks quite nice already. Then let's explore some options to make it even better:
- What about moving it even further to the PE side? Keeping only
p_get_pixel_formats as a unix call, and pre-allocating a large-enough array to hold the pixel formats (or making two calls if it's not large enough), which could even be cached in some of the glReserved1 thread data - with the HDC to invalidate the cache when necessary. 2) Have you checked how these functions behave on Windows? Are they very different across drivers and hardware or can we find a pixels format subset that we could simply fake? How useful / likely is it to have some exotic formats exposed and used by applications?
Thanks for the feedback!
1. Sure, I can experiment more in this direction. With a move towards the PE side, we would we still want to allow drivers to override the behavior (at least for now) and fall back to the existing GetPixelFormatAttrib*/ChoosePixelFormatARB unix calls, right?
Concerning per-HDC caching, is this to support the possibility of different drivers (e.g., normal vs offscreen) in the same process (because otherwise the pixel format data is constant)? Were you thinking about something along the lines of glReserved[2] = <format array ptr>, glReserved[4] = <num formats>, glReserved[4] = <hdc associated with format array> ?
2. Not yet, but I plan to (for now I am just following the glx+tweaks rules). I have a small program that allows me to exercise `wglChoosePixelFormatARB` and I would like to run it on a few different setups to see if I can infer anything from the results.
On Sat Mar 30 15:15:03 2024 +0000, Alexandros Frantzis wrote:
Thanks for the feedback!
- Sure, I can experiment more in this direction. With a move towards
the PE side, we would we still want to allow drivers to override the behavior (at least for now) and fall back to the existing GetPixelFormatAttrib*/ChoosePixelFormatARB unix calls, right? Concerning per-HDC caching, is this to support the possibility of different drivers (e.g., normal vs offscreen) in the same process (because otherwise the pixel format data is constant)? Were you thinking about something along the lines of glReserved[2] = <format array ptr>, glReserved[4] = <num formats>, glReserved[4] = <hdc associated with format array> ? 2. Not yet, but I plan to (for now I am just following the glx+tweaks rules). I have a small program that allows me to exercise `wglChoosePixelFormatARB` and I would like to run it on a few different setups to see if I can infer anything from the results.
Well... maybe it would be more complicated to support an override on the driver end if it lives on the PE side, but I think we can consider not supporting that fallback anymore if it works well enough by re-implementing the list ourselves.
Then maybe moving it to the unix side of opengl32 could be a first step to be able to validate that it does, and moving it to the PE side could come later, but that also means more work to get there. Not completely sure it's worth it.
Looking at how it behaves on Windows could tell us a bit more about that, and whether it seems better to delegate it to the host OpenGL or not.
Concerning per-HDC caching, is this to support the possibility of different drivers (e.g., normal vs offscreen) in the same process (because otherwise the pixel format data is constant)? Were you thinking about something along the lines of glReserved[2] = , glReserved[4] = , glReserved[4] = ?
Yes, something like that, and yes mostly because we have memory DCs handled separately. Of course if the list can be completely made up there's not much point caching anything.
@rbernon I have started exploring the behavior of `wglChoosePixelFormatARB` on real windows drivers. I created a tool to let me exercise the function from the command line: https://gitlab.collabora.com/alf/wglchoose, and used it on Win10 with Intel and AMD graphics.
I have attached the results ([amd.txt](/uploads/daa1fc7b3fc6f331bf48864390ae6154/amd.txt) and [intel.txt](/uploads/beeccb73ad6796b400d7b6bcefa62ec7/intel.txt) of running [wglchoose.ps1](https://gitlab.collabora.com/alf/wglchoose/-/raw/master/wglchoose.ps1) from the above repository, which just invokes `wglchoose.exe` with various attribute lists that I thought might be interesting. Unfortunately, I don't have access to NVIDIA graphics, so it would be great if someone could run the above tool on NVIDIA and provide some results to get a more complete picture.
Some terms: * **id order**: the pixel format ordered by increasing pixel format id * **nil order**: the pixel format order as returned by `wglChoosePixelFormatARB` with an empty attribute list.
The first results indicate that sort order and how attributes affect it is driver dependent. Here are some first notes after going through the logs:
AMD ---
The nil order is the same as the id order. Specifying attributes may change the relative order of pixel formats.
This seems to be the overall sorting precedence, and per-attribute sort order if the value for an attribute is not specified:
* supported surface: window(+bitmap) then bitmap-only (relative ordering with acceleration is unclear) * acceleration: fullaccel then noaccel * color bits: highest first * pixel type: rgba then colorindex (for fullaccel formats it seems this takes precedence over color bits) * alpha bits: lowest first * aux buffers: highest first (relative ordering with alpha bits uncertain) * depth: highest first * stencil: highest first * accum bits: lowest first * double buffer: single buffer then double * swap method: undefined then copy
Each specified attribute (at least the ones I tried: color bits, alpha, depth, stencil) re-sorts the list with *lowest* values for that attribute first, filtering out values that don't meet the minimum requirement, but keeps relative order otherwise. For multiple specified attributes the attribute precedence order mentioned above seems to be used. Also if any attribute is specified all swap_copy formats are removed.
Intel -----
The nil order is not the same as the id order. The nil order is used as the basis for all results: specifying attributes filters out pixel formats from that nil order, but never re-sorts the list.
I couldn't make much sense of either the id or nil orders.
Interesting.
I ran similar tests on a VM with NVIDIA GPU there: https://testbot.winehq.org/JobDetails.pl?Key=144923&f101=task.log#k101
ChoosePixelFormat really doesn't care much about the desired format, and seems to always return a 32bit pixel format. Does it even allow to select a R10G10B10 pixel format? It doesn't on NV. I can see some small variations depending on whether a depth buffer / double buffering is desired. If depth is requested and depth bits cannot be matched, it's simply maximized.
The results on NVIDIA look somewhat in between AMD and Intel, where the format list is partially sorted according to the filters, with exact matches ordered first, and the rest of the list put after, kept in its original order. The formats are also always filtered to drop any non-window format.
Overall it seems to me that using the host pixel format list, in its ID order, then implementing an AMD-like sorting on top is probably safe. That will differ a bit from Intel GPUs, but we can probably assume that it won't matter -or handle the problems if/when they appear.
The functionality was implemented by !5517 and !5933.
This merge request was closed by Alexandros Frantzis.