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;