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..7f6aef43e2f 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; + unsigned int i; + DEVMODEW mode; + + 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 7f6aef43e2f..6a59955b513 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; unsigned int i; DEVMODEW mode;
+ 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 6a59955b513..830d3ecae7d 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);
Zhiyi Zhang (@zhiyi) commented about dlls/wined3d/directx.c:
/* 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;
- unsigned int i;
- DEVMODEW mode;
- output->mode_count = 0;
- for (i = 0; EnumDisplaySettingsExW(output->device_name, i, &mode, 0); ++i)
DEVMODEW.dmSize and DEVMODEW.dmDriverExtra is not initialized before calling EnumDisplaySettingsExW().
On 7/26/22 20:51, Zhiyi Zhang (@zhiyi) wrote:
Zhiyi Zhang (@zhiyi) commented about dlls/wined3d/directx.c:
/* 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;
- unsigned int i;
- DEVMODEW mode;
- output->mode_count = 0;
- for (i = 0; EnumDisplaySettingsExW(output->device_name, i, &mode, 0); ++i)
DEVMODEW.dmSize and DEVMODEW.dmDriverExtra is not initialized before calling EnumDisplaySettingsExW().
Thanks for catching that; resent.
FWIW I intend to introduce a display mode cache in win32u (except for the current mode) in https://gitlab.winehq.org/wine/wine/-/merge_requests/406 and later patches to support display modes in nulldrv. I'm not sure if that would change our solve anything here.
On 7/27/22 06:07, Rémi Bernon (@rbernon) wrote:
FWIW I intend to introduce a display mode cache in win32u (except for the current mode) in https://gitlab.winehq.org/wine/wine/-/merge_requests/406 and later patches to support display modes in nulldrv. I'm not sure if that would change our solve anything here.
Possibly, although IIRC the modes are already cached in some sense, and that it's the registry queries themselves that are slow. We're currently making 3 calls per mode, and I was debugging this issue on a machine that exposes over 500 unique modes, which sums to way too many server calls per frame. Maybe it's possible to cache modes without needing the registry, though.
Even if we did, though, EnumDisplaySettings() is still slow on Windows, and inasmuch as we support d3d9 on Windows I think it makes sense to still apply this patch.