-- v2: wined3d: Build the device list only once in wined3d_output_find_closest_matching_mode(). dxgi: Build the device list only once in dxgi_output_get_display_mode_list(). d3d8: Cache the output mode list. d3d9: Cache the output mode list. wined3d: Build a list of wined3d_display_mode structures in wined3d_output_get_mode[_count](). wined3d: Factor out mode_matches_filter().
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/wined3d/directx.c | 72 ++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 42 deletions(-)
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 85405eaa6b5..9eac1a04c42 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -1228,6 +1228,34 @@ HRESULT CDECL wined3d_output_get_desc(const struct wined3d_output *output, /* FIXME: GetAdapterModeCount and EnumAdapterModes currently only returns modes of the same bpp but different resolutions */
+static bool mode_matches_filter(const DEVMODEW *mode, const struct wined3d_format *format, + enum wined3d_scanline_ordering scanline_ordering) +{ + if (mode->dmFields & DM_DISPLAYFLAGS) + { + if (scanline_ordering == WINED3D_SCANLINE_ORDERING_PROGRESSIVE + && (mode->u2.dmDisplayFlags & DM_INTERLACED)) + return false; + + if (scanline_ordering == WINED3D_SCANLINE_ORDERING_INTERLACED + && !(mode->u2.dmDisplayFlags & DM_INTERLACED)) + return false; + } + + if (format->id == WINED3DFMT_UNKNOWN) + { + /* This is for d3d8, do not enumerate P8 here. */ + if (mode->dmBitsPerPel != 32 && mode->dmBitsPerPel != 16) + return false; + } + else if (mode->dmBitsPerPel != format->byte_count * CHAR_BIT) + { + return false; + } + + return true; +} + /* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */ unsigned int CDECL wined3d_output_get_mode_count(const struct wined3d_output *output, enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering) @@ -1236,7 +1264,6 @@ unsigned int CDECL wined3d_output_get_mode_count(const struct wined3d_output *ou const struct wined3d_format *format; unsigned int i = 0; unsigned int j = 0; - UINT format_bits; DEVMODEW mode;
TRACE("output %p, format %s, scanline_ordering %#x.\n", @@ -1244,33 +1271,14 @@ unsigned int CDECL wined3d_output_get_mode_count(const struct wined3d_output *ou
adapter = output->adapter; format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET); - format_bits = format->byte_count * CHAR_BIT;
memset(&mode, 0, sizeof(mode)); mode.dmSize = sizeof(mode);
while (EnumDisplaySettingsExW(output->device_name, j++, &mode, 0)) { - if (mode.dmFields & DM_DISPLAYFLAGS) - { - if (scanline_ordering == WINED3D_SCANLINE_ORDERING_PROGRESSIVE - && (mode.u2.dmDisplayFlags & DM_INTERLACED)) - continue; - - if (scanline_ordering == WINED3D_SCANLINE_ORDERING_INTERLACED - && !(mode.u2.dmDisplayFlags & DM_INTERLACED)) - continue; - } - - if (format_id == WINED3DFMT_UNKNOWN) - { - /* This is for d3d8, do not enumerate P8 here. */ - if (mode.dmBitsPerPel == 32 || mode.dmBitsPerPel == 16) ++i; - } - else if (mode.dmBitsPerPel == format_bits) - { + if (mode_matches_filter(&mode, format, scanline_ordering)) ++i; - } }
TRACE("Returning %u matching modes (out of %u total) for output %p.\n", i, j, output); @@ -1285,7 +1293,6 @@ HRESULT CDECL wined3d_output_get_mode(const struct wined3d_output *output, { const struct wined3d_adapter *adapter; const struct wined3d_format *format; - UINT format_bits; DEVMODEW m; UINT i = 0; int j = 0; @@ -1298,7 +1305,6 @@ HRESULT CDECL wined3d_output_get_mode(const struct wined3d_output *output,
adapter = output->adapter; format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET); - format_bits = format->byte_count * CHAR_BIT;
memset(&m, 0, sizeof(m)); m.dmSize = sizeof(m); @@ -1311,26 +1317,8 @@ HRESULT CDECL wined3d_output_get_mode(const struct wined3d_output *output, return WINED3DERR_INVALIDCALL; }
- if (m.dmFields & DM_DISPLAYFLAGS) - { - if (scanline_ordering == WINED3D_SCANLINE_ORDERING_PROGRESSIVE - && (m.u2.dmDisplayFlags & DM_INTERLACED)) - continue; - - if (scanline_ordering == WINED3D_SCANLINE_ORDERING_INTERLACED - && !(m.u2.dmDisplayFlags & DM_INTERLACED)) - continue; - } - - if (format_id == WINED3DFMT_UNKNOWN) - { - /* This is for d3d8, do not enumerate P8 here. */ - if (m.dmBitsPerPel == 32 || m.dmBitsPerPel == 16) ++i; - } - else if (m.dmBitsPerPel == format_bits) - { + if (mode_matches_filter(&m, format, scanline_ordering)) ++i; - } }
mode->width = m.dmPelsWidth;
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/wined3d/directx.c | 136 ++++++++++++++++++--------------- dlls/wined3d/wined3d_private.h | 3 + include/wine/wined3d.h | 8 +- 3 files changed, 83 insertions(+), 64 deletions(-)
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 9eac1a04c42..d90d6c6c52d 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -1228,43 +1228,78 @@ HRESULT CDECL wined3d_output_get_desc(const struct wined3d_output *output, /* FIXME: GetAdapterModeCount and EnumAdapterModes currently only returns modes of the same bpp but different resolutions */
-static bool mode_matches_filter(const DEVMODEW *mode, const struct wined3d_format *format, - enum wined3d_scanline_ordering scanline_ordering) +static void wined3d_output_update_modes(struct wined3d_output *output) { - if (mode->dmFields & DM_DISPLAYFLAGS) + struct wined3d_display_mode *wined3d_mode; + DEVMODEW mode = {.dmSize = sizeof(mode)}; + unsigned int i; + + output->mode_count = 0; + + for (i = 0; EnumDisplaySettingsExW(output->device_name, i, &mode, 0); ++i) { - if (scanline_ordering == WINED3D_SCANLINE_ORDERING_PROGRESSIVE - && (mode->u2.dmDisplayFlags & DM_INTERLACED)) - return false; + if (!wined3d_array_reserve((void **)&output->modes, &output->modes_size, + output->mode_count + 1, sizeof(*output->modes))) + return;
- if (scanline_ordering == WINED3D_SCANLINE_ORDERING_INTERLACED - && !(mode->u2.dmDisplayFlags & DM_INTERLACED)) - return false; + wined3d_mode = &output->modes[output->mode_count++]; + wined3d_mode->width = mode.dmPelsWidth; + wined3d_mode->height = mode.dmPelsHeight; + wined3d_mode->format_id = pixelformat_for_depth(mode.dmBitsPerPel); + + if (mode.dmFields & DM_DISPLAYFREQUENCY) + wined3d_mode->refresh_rate = mode.dmDisplayFrequency; + else + wined3d_mode->refresh_rate = DEFAULT_REFRESH_RATE; + + if (mode.dmFields & DM_DISPLAYFLAGS) + { + if (mode.u2.dmDisplayFlags & DM_INTERLACED) + wined3d_mode->scanline_ordering = WINED3D_SCANLINE_ORDERING_INTERLACED; + else + wined3d_mode->scanline_ordering = WINED3D_SCANLINE_ORDERING_PROGRESSIVE; + } + else + { + wined3d_mode->scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; + } } +} + +static bool mode_matches_filter(const struct wined3d_adapter *adapter, const struct wined3d_display_mode *mode, + const struct wined3d_format *format, enum wined3d_scanline_ordering scanline_ordering) +{ + if (scanline_ordering != WINED3D_SCANLINE_ORDERING_UNKNOWN + && mode->scanline_ordering != WINED3D_SCANLINE_ORDERING_UNKNOWN + && scanline_ordering != mode->scanline_ordering) + return false;
if (format->id == WINED3DFMT_UNKNOWN) { /* This is for d3d8, do not enumerate P8 here. */ - if (mode->dmBitsPerPel != 32 && mode->dmBitsPerPel != 16) + if (mode->format_id != WINED3DFMT_B5G6R5_UNORM && mode->format_id != WINED3DFMT_B8G8R8X8_UNORM) return false; } - else if (mode->dmBitsPerPel != format->byte_count * CHAR_BIT) + else { - return false; + const struct wined3d_format *mode_format = wined3d_get_format(adapter, + mode->format_id, WINED3D_BIND_RENDER_TARGET); + + if (format->byte_count != mode_format->byte_count) + return false; }
return true; }
/* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */ -unsigned int CDECL wined3d_output_get_mode_count(const struct wined3d_output *output, +unsigned int CDECL wined3d_output_get_mode_count(struct wined3d_output *output, enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering) { const struct wined3d_adapter *adapter; const struct wined3d_format *format; - unsigned int i = 0; - unsigned int j = 0; - DEVMODEW mode; + unsigned int count = 0; + SIZE_T i;
TRACE("output %p, format %s, scanline_ordering %#x.\n", output, debug_d3dformat(format_id), scanline_ordering); @@ -1272,30 +1307,27 @@ unsigned int CDECL wined3d_output_get_mode_count(const struct wined3d_output *ou adapter = output->adapter; format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET);
- memset(&mode, 0, sizeof(mode)); - mode.dmSize = sizeof(mode); + wined3d_output_update_modes(output);
- while (EnumDisplaySettingsExW(output->device_name, j++, &mode, 0)) + for (i = 0; i < output->mode_count; ++i) { - if (mode_matches_filter(&mode, format, scanline_ordering)) - ++i; + if (mode_matches_filter(adapter, &output->modes[i], format, scanline_ordering)) + ++count; }
- TRACE("Returning %u matching modes (out of %u total) for output %p.\n", i, j, output); + TRACE("Returning %u matching modes (out of %Iu total).\n", count, output->mode_count);
- return i; + return count; }
/* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */ -HRESULT CDECL wined3d_output_get_mode(const struct wined3d_output *output, +HRESULT CDECL wined3d_output_get_mode(struct wined3d_output *output, enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering, unsigned int mode_idx, struct wined3d_display_mode *mode) { const struct wined3d_adapter *adapter; const struct wined3d_format *format; - DEVMODEW m; - UINT i = 0; - int j = 0; + SIZE_T i, match_idx = 0;
TRACE("output %p, format %s, scanline_ordering %#x, mode_idx %u, mode %p.\n", output, debug_d3dformat(format_id), scanline_ordering, mode_idx, mode); @@ -1306,46 +1338,30 @@ HRESULT CDECL wined3d_output_get_mode(const struct wined3d_output *output, adapter = output->adapter; format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET);
- memset(&m, 0, sizeof(m)); - m.dmSize = sizeof(m); + wined3d_output_update_modes(output);
- while (i <= mode_idx) + for (i = 0; i < output->mode_count; ++i) { - if (!EnumDisplaySettingsExW(output->device_name, j++, &m, 0)) + const struct wined3d_display_mode *wined3d_mode = &output->modes[i]; + + if (mode_matches_filter(adapter, wined3d_mode, format, scanline_ordering) && match_idx++ == mode_idx) { - WARN("Invalid mode_idx %u.\n", mode_idx); - return WINED3DERR_INVALIDCALL; + *mode = *wined3d_mode; + if (format_id != WINED3DFMT_UNKNOWN) + mode->format_id = format_id; + + TRACE("%ux%u@%u %u bpp, %s %#x.\n", mode->width, mode->height, mode->refresh_rate, + wined3d_get_format(adapter, mode->format_id, WINED3D_BIND_RENDER_TARGET)->byte_count * CHAR_BIT, + debug_d3dformat(mode->format_id), mode->scanline_ordering); + return WINED3D_OK; } - - if (mode_matches_filter(&m, format, scanline_ordering)) - ++i; }
- mode->width = m.dmPelsWidth; - mode->height = m.dmPelsHeight; - mode->refresh_rate = DEFAULT_REFRESH_RATE; - if (m.dmFields & DM_DISPLAYFREQUENCY) - mode->refresh_rate = m.dmDisplayFrequency; - - if (format_id == WINED3DFMT_UNKNOWN) - mode->format_id = pixelformat_for_depth(m.dmBitsPerPel); - else - mode->format_id = format_id; - - if (!(m.dmFields & DM_DISPLAYFLAGS)) - mode->scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; - else if (m.u2.dmDisplayFlags & DM_INTERLACED) - mode->scanline_ordering = WINED3D_SCANLINE_ORDERING_INTERLACED; - else - mode->scanline_ordering = WINED3D_SCANLINE_ORDERING_PROGRESSIVE; - - TRACE("%ux%u@%u %u bpp, %s %#x.\n", mode->width, mode->height, mode->refresh_rate, - m.dmBitsPerPel, debug_d3dformat(mode->format_id), mode->scanline_ordering); - - return WINED3D_OK; + WARN("Invalid mode_idx %u.\n", mode_idx); + return WINED3DERR_INVALIDCALL; }
-HRESULT CDECL wined3d_output_find_closest_matching_mode(const struct wined3d_output *output, +HRESULT CDECL wined3d_output_find_closest_matching_mode(struct wined3d_output *output, struct wined3d_display_mode *mode) { unsigned int i, j, mode_count, matching_mode_count, closest; @@ -2158,7 +2174,7 @@ HRESULT CDECL wined3d_check_device_format_conversion(const struct wined3d_output }
HRESULT CDECL wined3d_check_device_type(const struct wined3d *wined3d, - const struct wined3d_output *output, enum wined3d_device_type device_type, + struct wined3d_output *output, enum wined3d_device_type device_type, enum wined3d_format_id display_format, enum wined3d_format_id backbuffer_format, BOOL windowed) { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 4e0879a3985..36274ee24bc 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3502,6 +3502,9 @@ struct wined3d_output
D3DKMT_HANDLE kmt_device; D3DDDI_VIDEO_PRESENT_SOURCE_ID vidpn_source_id; + + struct wined3d_display_mode *modes; + SIZE_T mode_count, modes_size; };
HRESULT wined3d_output_get_gamma_ramp(struct wined3d_output *output, struct wined3d_gamma_ramp *ramp) DECLSPEC_HIDDEN; diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index ce2da6e4c04..44e8c7d6546 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2346,7 +2346,7 @@ HRESULT __cdecl wined3d_check_device_multisample_type(const struct wined3d_adapt enum wined3d_device_type device_type, enum wined3d_format_id surface_format_id, BOOL windowed, enum wined3d_multisample_type multisample_type, unsigned int *quality_levels); HRESULT __cdecl wined3d_check_device_type(const struct wined3d *wined3d, - const struct wined3d_output *output, enum wined3d_device_type device_type, + struct wined3d_output *output, enum wined3d_device_type device_type, enum wined3d_format_id display_format_id, enum wined3d_format_id backbuffer_format_id, BOOL windowed); struct wined3d * __cdecl wined3d_create(DWORD flags); @@ -2586,17 +2586,17 @@ void __cdecl wined3d_device_context_update_sub_resource(struct wined3d_device_co struct wined3d_resource *resource, unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch, unsigned int depth_pitch, unsigned int flags);
-HRESULT __cdecl wined3d_output_find_closest_matching_mode(const struct wined3d_output *output, +HRESULT __cdecl wined3d_output_find_closest_matching_mode(struct wined3d_output *output, struct wined3d_display_mode *mode); struct wined3d_adapter * __cdecl wined3d_output_get_adapter(const struct wined3d_output *output); HRESULT __cdecl wined3d_output_get_desc(const struct wined3d_output *output, struct wined3d_output_desc *desc); HRESULT __cdecl wined3d_output_get_display_mode(const struct wined3d_output *output, struct wined3d_display_mode *mode, enum wined3d_display_rotation *rotation); -HRESULT __cdecl wined3d_output_get_mode(const struct wined3d_output *output, +HRESULT __cdecl wined3d_output_get_mode(struct wined3d_output *output, enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering, unsigned int mode_idx, struct wined3d_display_mode *mode); -unsigned int __cdecl wined3d_output_get_mode_count(const struct wined3d_output *output, +unsigned int __cdecl wined3d_output_get_mode_count(struct wined3d_output *output, enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering); HRESULT __cdecl wined3d_output_get_raster_status(const struct wined3d_output *output, struct wined3d_raster_status *raster_status);
From: Zebediah Figura zfigura@codeweavers.com
Garou: Mark of the Wolves calls IDirect3D9::GetAdapterModeCount() on every frame. This results in calling EnumDisplaySettingsExW() once per available mode, which is a very slow operation, both on Windows and Wine.
Manual testing shows that Windows caches the mode list (as well as the adapter list, which is already cached in Wine) in Direct3D 9 and lower. Calls to GetAdapterModeCount() and EnumAdapterDisplayModes() are fast, and they also do not change if monitors are added or removed.
DXGI behaves differently, however. The list of outputs attached to an adapter is cached—that is, calls to IDXGIAdapter::EnumOutputs() are fast, and return stale data. However, at least some other calls are slow and do not seem to be cached, including IDXGIOutput::GetDisplayModeList() and IDXGIOutput::GetDesc().
ddraw is also slow and uncached. Since all testing was done on Windows 10 (for lack of available older hardware to test with) it is not unlikely that ddraw was reimplemented over dxgi on newer Windows, and that older Windows versions would be fast and cached, but this is speculation. In any case I have not included patches to cache ddraw modes.
Tests were done on Windows 10 21H2, both on real hardware with NVidia drivers and on software drivers via qemu/KVM. In the latter case only speed could be tested, but this was consistent with the results from the NVidia machine. --- dlls/d3d8/directx.c | 4 ++-- dlls/d3d9/directx.c | 11 +++++------ dlls/ddraw/ddraw.c | 2 +- dlls/dxgi/output.c | 4 ++-- dlls/wined3d/directx.c | 21 +++++++++++++-------- dlls/wined3d/wined3d.spec | 4 ++-- dlls/wined3d/wined3d_private.h | 1 + include/wine/wined3d.h | 4 ++-- 8 files changed, 28 insertions(+), 23 deletions(-)
diff --git a/dlls/d3d8/directx.c b/dlls/d3d8/directx.c index 3818cb79952..6fcd53abbdd 100644 --- a/dlls/d3d8/directx.c +++ b/dlls/d3d8/directx.c @@ -152,7 +152,7 @@ static UINT WINAPI d3d8_GetAdapterModeCount(IDirect3D8 *iface, UINT adapter)
wined3d_mutex_lock(); count = wined3d_output_get_mode_count(d3d8->wined3d_outputs[output_idx], - WINED3DFMT_UNKNOWN, WINED3D_SCANLINE_ORDERING_UNKNOWN); + WINED3DFMT_UNKNOWN, WINED3D_SCANLINE_ORDERING_UNKNOWN, false); wined3d_mutex_unlock();
return count; @@ -174,7 +174,7 @@ static HRESULT WINAPI d3d8_EnumAdapterModes(IDirect3D8 *iface, UINT adapter, UIN
wined3d_mutex_lock(); hr = wined3d_output_get_mode(d3d8->wined3d_outputs[output_idx], WINED3DFMT_UNKNOWN, - WINED3D_SCANLINE_ORDERING_UNKNOWN, mode_idx, &wined3d_mode); + WINED3D_SCANLINE_ORDERING_UNKNOWN, mode_idx, &wined3d_mode, false); wined3d_mutex_unlock();
if (SUCCEEDED(hr)) diff --git a/dlls/d3d9/directx.c b/dlls/d3d9/directx.c index a1ebc986226..46cbd1fb174 100644 --- a/dlls/d3d9/directx.c +++ b/dlls/d3d9/directx.c @@ -178,7 +178,7 @@ static UINT WINAPI d3d9_GetAdapterModeCount(IDirect3D9Ex *iface, UINT adapter, D
wined3d_mutex_lock(); count = wined3d_output_get_mode_count(d3d9->wined3d_outputs[output_idx], - wined3dformat_from_d3dformat(format), WINED3D_SCANLINE_ORDERING_UNKNOWN); + wined3dformat_from_d3dformat(format), WINED3D_SCANLINE_ORDERING_UNKNOWN, true); wined3d_mutex_unlock();
return count; @@ -203,9 +203,8 @@ static HRESULT WINAPI d3d9_EnumAdapterModes(IDirect3D9Ex *iface, UINT adapter, return D3DERR_INVALIDCALL;
wined3d_mutex_lock(); - hr = wined3d_output_get_mode(d3d9->wined3d_outputs[output_idx], - wined3dformat_from_d3dformat(format), WINED3D_SCANLINE_ORDERING_UNKNOWN, mode_idx, - &wined3d_mode); + hr = wined3d_output_get_mode(d3d9->wined3d_outputs[output_idx], wined3dformat_from_d3dformat(format), + WINED3D_SCANLINE_ORDERING_UNKNOWN, mode_idx, &wined3d_mode, true); wined3d_mutex_unlock();
if (SUCCEEDED(hr)) @@ -524,7 +523,7 @@ static UINT WINAPI d3d9_GetAdapterModeCountEx(IDirect3D9Ex *iface,
wined3d_mutex_lock(); count = wined3d_output_get_mode_count(d3d9->wined3d_outputs[output_idx], - wined3dformat_from_d3dformat(filter->Format), wined3d_scanline_ordering_from_d3d(filter->ScanLineOrdering)); + wined3dformat_from_d3dformat(filter->Format), wined3d_scanline_ordering_from_d3d(filter->ScanLineOrdering), true); wined3d_mutex_unlock();
return count; @@ -550,7 +549,7 @@ static HRESULT WINAPI d3d9_EnumAdapterModesEx(IDirect3D9Ex *iface,
wined3d_mutex_lock(); hr = wined3d_output_get_mode(d3d9->wined3d_outputs[output_idx], wined3dformat_from_d3dformat(filter->Format), - wined3d_scanline_ordering_from_d3d(filter->ScanLineOrdering), mode_idx, &wined3d_mode); + wined3d_scanline_ordering_from_d3d(filter->ScanLineOrdering), mode_idx, &wined3d_mode, true); wined3d_mutex_unlock();
if (SUCCEEDED(hr)) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index f6770e59fb6..bb244222018 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -2447,7 +2447,7 @@ static HRESULT WINAPI ddraw7_EnumDisplayModes(IDirectDraw7 *iface, DWORD Flags, { modenum = 0; while (wined3d_output_get_mode(ddraw->wined3d_output, checkFormatList[fmt], - WINED3D_SCANLINE_ORDERING_UNKNOWN, modenum++, &mode) == WINED3D_OK) + WINED3D_SCANLINE_ORDERING_UNKNOWN, modenum++, &mode, false) == WINED3D_OK) { BOOL found = FALSE; unsigned i; diff --git a/dlls/dxgi/output.c b/dlls/dxgi/output.c index 797851c67f1..7c8431ffcd5 100644 --- a/dlls/dxgi/output.c +++ b/dlls/dxgi/output.c @@ -124,7 +124,7 @@ static HRESULT dxgi_output_get_display_mode_list(struct dxgi_output *output,
wined3d_mutex_lock(); max_count = wined3d_output_get_mode_count(output->wined3d_output, - wined3d_format, WINED3D_SCANLINE_ORDERING_UNKNOWN); + wined3d_format, WINED3D_SCANLINE_ORDERING_UNKNOWN, false);
if (!modes) { @@ -144,7 +144,7 @@ static HRESULT dxgi_output_get_display_mode_list(struct dxgi_output *output, for (i = 0; i < *mode_count; ++i) { if (FAILED(hr = wined3d_output_get_mode(output->wined3d_output, wined3d_format, - WINED3D_SCANLINE_ORDERING_UNKNOWN, i, &mode))) + WINED3D_SCANLINE_ORDERING_UNKNOWN, i, &mode, false))) { WARN("Failed to get output mode %u, hr %#lx.\n", i, hr); wined3d_mutex_unlock(); diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index d90d6c6c52d..4b3310d43fe 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -1228,12 +1228,15 @@ HRESULT CDECL wined3d_output_get_desc(const struct wined3d_output *output, /* FIXME: GetAdapterModeCount and EnumAdapterModes currently only returns modes of the same bpp but different resolutions */
-static void wined3d_output_update_modes(struct wined3d_output *output) +static void wined3d_output_update_modes(struct wined3d_output *output, bool cached) { struct wined3d_display_mode *wined3d_mode; DEVMODEW mode = {.dmSize = sizeof(mode)}; unsigned int i;
+ if (output->modes_valid && cached) + return; + output->mode_count = 0;
for (i = 0; EnumDisplaySettingsExW(output->device_name, i, &mode, 0); ++i) @@ -1264,6 +1267,8 @@ static void wined3d_output_update_modes(struct wined3d_output *output) wined3d_mode->scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; } } + + output->modes_valid = true; }
static bool mode_matches_filter(const struct wined3d_adapter *adapter, const struct wined3d_display_mode *mode, @@ -1294,7 +1299,7 @@ static bool mode_matches_filter(const struct wined3d_adapter *adapter, const str
/* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */ unsigned int CDECL wined3d_output_get_mode_count(struct wined3d_output *output, - enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering) + enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering, bool cached) { const struct wined3d_adapter *adapter; const struct wined3d_format *format; @@ -1307,7 +1312,7 @@ unsigned int CDECL wined3d_output_get_mode_count(struct wined3d_output *output, adapter = output->adapter; format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET);
- wined3d_output_update_modes(output); + wined3d_output_update_modes(output, cached);
for (i = 0; i < output->mode_count; ++i) { @@ -1323,7 +1328,7 @@ unsigned int CDECL wined3d_output_get_mode_count(struct wined3d_output *output, /* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */ HRESULT CDECL wined3d_output_get_mode(struct wined3d_output *output, enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering, - unsigned int mode_idx, struct wined3d_display_mode *mode) + unsigned int mode_idx, struct wined3d_display_mode *mode, bool cached) { const struct wined3d_adapter *adapter; const struct wined3d_format *format; @@ -1338,7 +1343,7 @@ HRESULT CDECL wined3d_output_get_mode(struct wined3d_output *output, adapter = output->adapter; format = wined3d_get_format(adapter, format_id, WINED3D_BIND_RENDER_TARGET);
- wined3d_output_update_modes(output); + wined3d_output_update_modes(output, cached);
for (i = 0; i < output->mode_count; ++i) { @@ -1372,7 +1377,7 @@ HRESULT CDECL wined3d_output_find_closest_matching_mode(struct wined3d_output *o TRACE("output %p, mode %p.\n", output, mode);
if (!(mode_count = wined3d_output_get_mode_count(output, mode->format_id, - WINED3D_SCANLINE_ORDERING_UNKNOWN))) + WINED3D_SCANLINE_ORDERING_UNKNOWN, false))) { WARN("Output has 0 matching modes.\n"); return E_FAIL; @@ -1389,7 +1394,7 @@ HRESULT CDECL wined3d_output_find_closest_matching_mode(struct wined3d_output *o for (i = 0; i < mode_count; ++i) { if (FAILED(hr = wined3d_output_get_mode(output, mode->format_id, - WINED3D_SCANLINE_ORDERING_UNKNOWN, i, &modes[i]))) + WINED3D_SCANLINE_ORDERING_UNKNOWN, i, &modes[i], false))) { heap_free(matching_modes); heap_free(modes); @@ -2204,7 +2209,7 @@ HRESULT CDECL wined3d_check_device_type(const struct wined3d *wined3d, { /* If the requested display format is not available, don't continue. */ if (!wined3d_output_get_mode_count(output, display_format, - WINED3D_SCANLINE_ORDERING_UNKNOWN)) + WINED3D_SCANLINE_ORDERING_UNKNOWN, false)) { TRACE("No available modes for display format %s.\n", debug_d3dformat(display_format)); return WINED3DERR_NOTAVAILABLE; diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 1f9c398a5c5..a5cf7eca22c 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -152,8 +152,8 @@ @ cdecl wined3d_output_get_adapter(ptr) @ cdecl wined3d_output_get_desc(ptr ptr) @ cdecl wined3d_output_get_display_mode(ptr ptr ptr) -@ cdecl wined3d_output_get_mode(ptr long long long ptr) -@ cdecl wined3d_output_get_mode_count(ptr long long) +@ cdecl wined3d_output_get_mode(ptr long long long ptr long) +@ cdecl wined3d_output_get_mode_count(ptr long long long) @ cdecl wined3d_output_get_raster_status(ptr ptr) @ cdecl wined3d_output_release_ownership(ptr) @ cdecl wined3d_output_set_display_mode(ptr ptr) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 36274ee24bc..95af2775dfe 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3505,6 +3505,7 @@ struct wined3d_output
struct wined3d_display_mode *modes; SIZE_T mode_count, modes_size; + bool modes_valid; };
HRESULT wined3d_output_get_gamma_ramp(struct wined3d_output *output, struct wined3d_gamma_ramp *ramp) DECLSPEC_HIDDEN; diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 44e8c7d6546..5d51de70863 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2595,9 +2595,9 @@ HRESULT __cdecl wined3d_output_get_display_mode(const struct wined3d_output *out struct wined3d_display_mode *mode, enum wined3d_display_rotation *rotation); HRESULT __cdecl wined3d_output_get_mode(struct wined3d_output *output, enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering, - unsigned int mode_idx, struct wined3d_display_mode *mode); + unsigned int mode_idx, struct wined3d_display_mode *mode, bool cached); unsigned int __cdecl wined3d_output_get_mode_count(struct wined3d_output *output, - enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering); + enum wined3d_format_id format_id, enum wined3d_scanline_ordering scanline_ordering, bool cached); HRESULT __cdecl wined3d_output_get_raster_status(const struct wined3d_output *output, struct wined3d_raster_status *raster_status); void __cdecl wined3d_output_release_ownership(const struct wined3d_output *output);
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/d3d8/directx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/d3d8/directx.c b/dlls/d3d8/directx.c index 6fcd53abbdd..365a99216aa 100644 --- a/dlls/d3d8/directx.c +++ b/dlls/d3d8/directx.c @@ -152,7 +152,7 @@ static UINT WINAPI d3d8_GetAdapterModeCount(IDirect3D8 *iface, UINT adapter)
wined3d_mutex_lock(); count = wined3d_output_get_mode_count(d3d8->wined3d_outputs[output_idx], - WINED3DFMT_UNKNOWN, WINED3D_SCANLINE_ORDERING_UNKNOWN, false); + WINED3DFMT_UNKNOWN, WINED3D_SCANLINE_ORDERING_UNKNOWN, true); wined3d_mutex_unlock();
return count; @@ -174,7 +174,7 @@ static HRESULT WINAPI d3d8_EnumAdapterModes(IDirect3D8 *iface, UINT adapter, UIN
wined3d_mutex_lock(); hr = wined3d_output_get_mode(d3d8->wined3d_outputs[output_idx], WINED3DFMT_UNKNOWN, - WINED3D_SCANLINE_ORDERING_UNKNOWN, mode_idx, &wined3d_mode, false); + WINED3D_SCANLINE_ORDERING_UNKNOWN, mode_idx, &wined3d_mode, true); wined3d_mutex_unlock();
if (SUCCEEDED(hr))
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/dxgi/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/dxgi/output.c b/dlls/dxgi/output.c index 7c8431ffcd5..067488399d2 100644 --- a/dlls/dxgi/output.c +++ b/dlls/dxgi/output.c @@ -144,7 +144,7 @@ static HRESULT dxgi_output_get_display_mode_list(struct dxgi_output *output, for (i = 0; i < *mode_count; ++i) { if (FAILED(hr = wined3d_output_get_mode(output->wined3d_output, wined3d_format, - WINED3D_SCANLINE_ORDERING_UNKNOWN, i, &mode, false))) + WINED3D_SCANLINE_ORDERING_UNKNOWN, i, &mode, true))) { WARN("Failed to get output mode %u, hr %#lx.\n", i, hr); wined3d_mutex_unlock();
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/wined3d/directx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 4b3310d43fe..0444f76a5c6 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -1394,7 +1394,7 @@ HRESULT CDECL wined3d_output_find_closest_matching_mode(struct wined3d_output *o for (i = 0; i < mode_count; ++i) { if (FAILED(hr = wined3d_output_get_mode(output, mode->format_id, - WINED3D_SCANLINE_ORDERING_UNKNOWN, i, &modes[i], false))) + WINED3D_SCANLINE_ORDERING_UNKNOWN, i, &modes[i], true))) { heap_free(matching_modes); heap_free(modes);
Jan Sikorski (@jsikorski) commented about dlls/wined3d/directx.c:
- output->modes_valid = true;
+}
+static bool mode_matches_filter(const struct wined3d_adapter *adapter, const struct wined3d_display_mode *mode,
const struct wined3d_format *format, enum wined3d_scanline_ordering scanline_ordering)
+{
- if (scanline_ordering != WINED3D_SCANLINE_ORDERING_UNKNOWN
&& mode->scanline_ordering != WINED3D_SCANLINE_ORDERING_UNKNOWN
&& scanline_ordering != mode->scanline_ordering)
return false;
- if (format->id == WINED3DFMT_UNKNOWN)
- {
/* This is for d3d8, do not enumerate P8 here. */
if (mode->format_id != WINED3DFMT_B5G6R5_UNORM && mode->format_id != WINED3DFMT_B8G8R8X8_UNORM)
return false;
Is this right, do we want only these 2 formats to pass the filter? It looks backwards, but if I'm wrong, it could use more explanation.
On 7/28/22 09:21, Jan Sikorski (@jsikorski) wrote:
Jan Sikorski (@jsikorski) commented about dlls/wined3d/directx.c:
- output->modes_valid = true;
+}
+static bool mode_matches_filter(const struct wined3d_adapter *adapter, const struct wined3d_display_mode *mode,
const struct wined3d_format *format, enum wined3d_scanline_ordering scanline_ordering)
+{
- if (scanline_ordering != WINED3D_SCANLINE_ORDERING_UNKNOWN
&& mode->scanline_ordering != WINED3D_SCANLINE_ORDERING_UNKNOWN
&& scanline_ordering != mode->scanline_ordering)
return false;
- if (format->id == WINED3DFMT_UNKNOWN)
- {
/* This is for d3d8, do not enumerate P8 here. */
if (mode->format_id != WINED3DFMT_B5G6R5_UNORM && mode->format_id != WINED3DFMT_B8G8R8X8_UNORM)
return false;
Is this right, do we want only these 2 formats to pass the filter? It looks backwards, but if I'm wrong, it could use more explanation.
It definitely looks backwards and doesn't match the comment—obviously we'd expect "mode->format_id == WINED3DFMT_P8". As stated this skips 15- and 24-bit display formats. This is all retained from previous code, though, and I didn't want to change it in this comment (or without testing first). Note also the limited set of formats that can be returned from pixelformat_for_depth().
On Fri Jul 29 18:39:02 2022 +0000, **** wrote:
Zebediah Figura (she/her) replied on the mailing list:
On 7/28/22 09:21, Jan Sikorski (@jsikorski) wrote: > Jan Sikorski (@jsikorski) commented about dlls/wined3d/directx.c: >> + output->modes_valid = true; >> +} >> + >> +static bool mode_matches_filter(const struct wined3d_adapter *adapter, const struct wined3d_display_mode *mode, >> + const struct wined3d_format *format, enum wined3d_scanline_ordering scanline_ordering) >> +{ >> + if (scanline_ordering != WINED3D_SCANLINE_ORDERING_UNKNOWN >> + && mode->scanline_ordering != WINED3D_SCANLINE_ORDERING_UNKNOWN >> + && scanline_ordering != mode->scanline_ordering) >> + return false; >> + >> + if (format->id == WINED3DFMT_UNKNOWN) >> + { >> + /* This is for d3d8, do not enumerate P8 here. */ >> + if (mode->format_id != WINED3DFMT_B5G6R5_UNORM && mode->format_id != WINED3DFMT_B8G8R8X8_UNORM) >> + return false; > Is this right, do we want only these 2 formats to pass the filter? It looks backwards, but if I'm wrong, it could use more explanation. > It definitely looks backwards and doesn't match the comment���obviously we'd expect "mode->format_id == WINED3DFMT_P8". As stated this skips 15- and 24-bit display formats. This is all retained from previous code, though, and I didn't want to change it in this comment (or without testing first). Note also the limited set of formats that can be returned from pixelformat_for_depth(). _______________________________________________ wine-gitlab mailing list -- wine-gitlab@winehq.org To unsubscribe send an email to wine-gitlab-leave@winehq.org
It was introduced some time ago by commit 8a5b6df483fcd02734df77046b757957bbcbbbfc. I think at the time 16 bpp and 32 bpp formats were the only other reported formats.
Note that d3d9 has similar checks in the callers; only reporting these two formats for d3d8 and d3d9 is probably correct, but the comment has become confusing.
This merge request was approved by Jan Sikorski.