diff --git a/src/dxgi/dxgi_adapter.cpp b/src/dxgi/dxgi_adapter.cpp index b31d1e5d0..2058abe3c 100644 --- a/src/dxgi/dxgi_adapter.cpp +++ b/src/dxgi/dxgi_adapter.cpp @@ -59,17 +59,12 @@ namespace dxvk { if (ppOutput == nullptr) return DXGI_ERROR_INVALID_CALL; - int numDisplays = SDL_GetNumVideoDisplays(); - - if (numDisplays < 0) { - Logger::err("DxgiAdapter::EnumOutputs: Failed to query display count"); - return DXGI_ERROR_DRIVER_INTERNAL_ERROR; - } - - if (Output >= static_cast(numDisplays)) + if (Output > 0) return DXGI_ERROR_NOT_FOUND; - *ppOutput = ref(new DxgiOutput(this, Output)); + // TODO support multiple monitors + HMONITOR monitor = ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); + *ppOutput = ref(new DxgiOutput(this, monitor)); return S_OK; } diff --git a/src/dxgi/dxgi_output.cpp b/src/dxgi/dxgi_output.cpp index b94481eb5..da57e6de3 100644 --- a/src/dxgi/dxgi_output.cpp +++ b/src/dxgi/dxgi_output.cpp @@ -7,13 +7,15 @@ #include "dxgi_adapter.h" #include "dxgi_output.h" +#include "../dxvk/dxvk_format.h" + namespace dxvk { DxgiOutput::DxgiOutput( DxgiAdapter* adapter, - UINT display) - : m_adapter (adapter), - m_display (display) { + HMONITOR monitor) + : m_adapter(adapter), + m_monitor(monitor) { } @@ -53,34 +55,20 @@ namespace dxvk { if (pDesc == nullptr) return DXGI_ERROR_INVALID_CALL; - // Display name, Windows requires wide chars - const char* displayName = SDL_GetDisplayName(m_display); + ::MONITORINFOEX monInfo = { sizeof(monInfo) }; - if (displayName == nullptr) { - Logger::err("DxgiOutput::GetDesc: Failed to get display name"); - return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + if (!::GetMonitorInfo(m_monitor, &monInfo)) { + Logger::err("DxgiOutput: Failed to query monitor info"); + return E_FAIL; } std::memset(pDesc->DeviceName, 0, sizeof(pDesc->DeviceName)); - std::mbstowcs(pDesc->DeviceName, displayName, _countof(pDesc->DeviceName) - 1); + std::mbstowcs(pDesc->DeviceName, monInfo.szDevice, _countof(pDesc->DeviceName) - 1); - // Current desktop rect of the display - SDL_Rect rect; - - if (SDL_GetDisplayBounds(m_display, &rect)) { - Logger::err("DxgiOutput::GetDesc: Failed to get display bounds"); - return DXGI_ERROR_DRIVER_INTERNAL_ERROR; - } - - pDesc->DesktopCoordinates.left = rect.x; - pDesc->DesktopCoordinates.top = rect.y; - pDesc->DesktopCoordinates.right = rect.x + rect.w; - pDesc->DesktopCoordinates.bottom = rect.y + rect.h; - - // We don't have any info for these + pDesc->DesktopCoordinates = monInfo.rcMonitor; pDesc->AttachedToDesktop = 1; pDesc->Rotation = DXGI_MODE_ROTATION_UNSPECIFIED; - pDesc->Monitor = nullptr; + pDesc->Monitor = m_monitor; return S_OK; } @@ -92,89 +80,51 @@ namespace dxvk { DXGI_MODE_DESC *pDesc) { if (pNumModes == nullptr) return DXGI_ERROR_INVALID_CALL; - - // In order to check whether a display mode is 'centered' or - // 'streched' in DXGI terms, we compare its size to the desktop - // 'mode. If they are the same, we consider the mode to be - // 'centered', which most games will prefer over 'streched'. - SDL_DisplayMode desktopMode; - if (SDL_GetDesktopDisplayMode(m_display, &desktopMode)) { - Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); - return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + // Query monitor info to get the device name + ::MONITORINFOEX monInfo = { sizeof(monInfo) }; + + if (!::GetMonitorInfo(m_monitor, &monInfo)) { + Logger::err("DxgiOutput: Failed to query monitor info"); + return E_FAIL; } - // Create a list of suitable display modes. Because of the way DXGI - // swapchains are handled by DXVK, we can ignore the format constraints - // here and just pick whatever modes SDL returns for the current display. - std::vector modes; + // Walk over all modes that the display supports and + // return those that match the requested format etc. + DEVMODE devMode; - int numDisplayModes = SDL_GetNumDisplayModes(m_display); + uint32_t srcModeId = 0; + uint32_t dstModeId = 0; - if (numDisplayModes < 0) { - Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); - return DXGI_ERROR_DRIVER_INTERNAL_ERROR; - } - - for (int i = 0; i < numDisplayModes; i++) { - SDL_DisplayMode currMode; + while (::EnumDisplaySettings(monInfo.szDevice, srcModeId++, &devMode)) { + // Skip interlaced modes altogether + if (devMode.dmDisplayFlags & DM_INTERLACED) + continue; - if (SDL_GetDisplayMode(m_display, i, &currMode)) { - Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); - return DXGI_ERROR_DRIVER_INTERNAL_ERROR; - } + // Skip modes with incompatible formats + if (devMode.dmBitsPerPel != GetFormatBpp(EnumFormat)) + continue; - // We don't want duplicates, so we'll filter out modes - // with matching resolution and refresh rate. - bool hasMode = false; - - for (int j = 0; j < i && !hasMode; j++) { - SDL_DisplayMode testMode; + // Write back display mode + if (pDesc != nullptr) { + if (dstModeId >= *pNumModes) + return DXGI_ERROR_MORE_DATA; - if (SDL_GetDisplayMode(m_display, j, &testMode)) { - Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); - return DXGI_ERROR_DRIVER_INTERNAL_ERROR; - } - - hasMode = testMode.w == currMode.w - && testMode.h == currMode.h - && testMode.refresh_rate == currMode.refresh_rate; - } - - // Convert the SDL display mode to a DXGI display mode info - // structure and filter out any unwanted modes based on the - // supplied flags. - if (!hasMode) { DXGI_MODE_DESC mode; - mode.Width = currMode.w; - mode.Height = currMode.h; - mode.RefreshRate.Numerator = currMode.refresh_rate; - mode.RefreshRate.Denominator = 1; - mode.Format = EnumFormat; - mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; - mode.Scaling = DXGI_MODE_SCALING_CENTERED; - modes.push_back(mode); + mode.Width = devMode.dmPelsWidth; + mode.Height = devMode.dmPelsHeight; + mode.RefreshRate = { devMode.dmDisplayFrequency, 1 }; + mode.Format = EnumFormat; + mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; + mode.Scaling = DXGI_MODE_SCALING_CENTERED; + pDesc[dstModeId] = mode; } - } - - // Copy list of display modes to the application-provided - // destination buffer. The buffer may not be appropriately - // sized by the time this is called. - if (pDesc != nullptr) { - for (uint32_t i = 0; i < modes.size() && i < *pNumModes; i++) - pDesc[i] = modes.at(i); - } - - // If the buffer is too small, we shall ask the application - // to query the display mode list again by returning the - // appropriate DXGI error code. - if ((pDesc == nullptr) || (modes.size() <= *pNumModes)) { - *pNumModes = modes.size(); - return S_OK; - } else { - return DXGI_ERROR_MORE_DATA; - } + dstModeId += 1; + } + + *pNumModes = dstModeId; + return S_OK; } @@ -232,4 +182,10 @@ namespace dxvk { return S_OK; } + + uint32_t DxgiOutput::GetFormatBpp(DXGI_FORMAT Format) const { + DxgiFormatInfo formatInfo = m_adapter->LookupFormat(Format, DxgiFormatMode::Any); + return imageFormatInfo(formatInfo.format)->elementSize * 8; + } + } diff --git a/src/dxgi/dxgi_output.h b/src/dxgi/dxgi_output.h index d30ea7684..ce86047c8 100644 --- a/src/dxgi/dxgi_output.h +++ b/src/dxgi/dxgi_output.h @@ -12,7 +12,7 @@ namespace dxvk { DxgiOutput( DxgiAdapter* adapter, - UINT display); + HMONITOR monitor); ~DxgiOutput(); @@ -66,8 +66,10 @@ namespace dxvk { private: - Com m_adapter; - UINT m_display; + Com m_adapter = nullptr; + HMONITOR m_monitor = nullptr; + + uint32_t GetFormatBpp(DXGI_FORMAT Format) const; }; diff --git a/tests/dxgi/test_dxgi_factory.cpp b/tests/dxgi/test_dxgi_factory.cpp index 2573c5f5c..b9ff31eda 100644 --- a/tests/dxgi/test_dxgi_factory.cpp +++ b/tests/dxgi/test_dxgi_factory.cpp @@ -31,31 +31,48 @@ int WINAPI WinMain(HINSTANCE hInstance, return 1; } + DXGI_ADAPTER_DESC desc; + + if (adapter->GetDesc(&desc) != S_OK) { + std::cerr << "Failed to get DXGI adapter info" << std::endl; + return 1; + } + + std::array chars; + std::wcstombs(chars.data(), desc.Description, chars.size() - 1); + + std::cout << str::format("Adapter ", i, ":") << std::endl; + std::cout << str::format(" ", chars.data()) << std::endl; + std::cout << str::format(" Vendor: ", desc.VendorId) << std::endl; + std::cout << str::format(" Device: ", desc.DeviceId) << std::endl; + std::cout << str::format(" Dedicated RAM: ", desc.DedicatedVideoMemory) << std::endl; + std::cout << str::format(" Shared RAM: ", desc.SharedSystemMemory) << std::endl; + Com output; for (UINT j = 0; adapter->EnumOutputs(j, &output) == S_OK; j++) { std::vector modes; - HRESULT status = S_OK; - UINT displayModeCount = 0; + DXGI_OUTPUT_DESC desc; - std::cout << str::format("Adapter ", i, ":") << std::endl; - - DXGI_ADAPTER_DESC desc; - - if (adapter->GetDesc(&desc) != S_OK) { - std::cerr << "Failed to get DXGI adapter info" << std::endl; + if (output->GetDesc(&desc) != S_OK) { + std::cerr << "Failed to get DXGI output info" << std::endl; return 1; } std::array chars; - std::wcstombs(chars.data(), desc.Description, chars.size() - 1); + std::wcstombs(chars.data(), desc.DeviceName, chars.size() - 1); - std::cout << str::format(" ", chars.data()) << std::endl; - std::cout << str::format(" Vendor: ", desc.VendorId) << std::endl; - std::cout << str::format(" Device: ", desc.DeviceId) << std::endl; - std::cout << str::format(" Dedicated RAM: ", desc.DedicatedVideoMemory) << std::endl; - std::cout << str::format(" Shared RAM: ", desc.SharedSystemMemory) << std::endl; + std::cout << str::format(" Output ", j, ":") << std::endl; + std::cout << str::format(" ", chars.data()) << std::endl; + std::cout << str::format(" Coordinates: ", + desc.DesktopCoordinates.left, ",", + desc.DesktopCoordinates.top, ":", + desc.DesktopCoordinates.right - desc.DesktopCoordinates.left, "x", + desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top) << std::endl; + + HRESULT status = S_OK; + UINT displayModeCount = 0; do { if (output->GetDisplayModeList( @@ -79,7 +96,6 @@ int WINAPI WinMain(HINSTANCE hInstance, return 1; } - std::cout << str::format(" Output ", j, ":") << std::endl; for (auto mode : modes) { std::cout << str::format(" ", mode.Width, "x", mode.Height, " @ ",