#include #include #include #include #include "dxgi_adapter.h" #include "dxgi_output.h" namespace dxvk { DxgiOutput::DxgiOutput( DxgiAdapter* adapter, UINT display) : m_adapter (adapter), m_display (display) { TRACE(this, adapter); } DxgiOutput::~DxgiOutput() { TRACE(this); } HRESULT DxgiOutput::QueryInterface( REFIID riid, void **ppvObject) { COM_QUERY_IFACE(riid, ppvObject, IDXGIOutput); Logger::warn("DxgiOutput::QueryInterface: Unknown interface query"); return E_NOINTERFACE; } HRESULT DxgiOutput::GetParent( REFIID riid, void **ppParent) { return m_adapter->QueryInterface(riid, ppParent); } HRESULT DxgiOutput::FindClosestMatchingMode( const DXGI_MODE_DESC *pModeToMatch, DXGI_MODE_DESC *pClosestMatch, IUnknown *pConcernedDevice) { Logger::err("DxgiOutput::FindClosestMatchingMode: Not implemented"); return E_NOTIMPL; } HRESULT DxgiOutput::GetDesc(DXGI_OUTPUT_DESC *pDesc) { if (pDesc == nullptr) return DXGI_ERROR_INVALID_CALL; // Display name, Windows requires wide chars const char* displayName = SDL_GetDisplayName(m_display); if (displayName == nullptr) { Logger::err("DxgiOutput::GetDesc: Failed to get display name"); return DXGI_ERROR_DRIVER_INTERNAL_ERROR; } std::memset(pDesc->DeviceName, 0, sizeof(pDesc->DeviceName)); std::mbstowcs(pDesc->DeviceName, displayName, _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->AttachedToDesktop = 1; pDesc->Rotation = DXGI_MODE_ROTATION_UNSPECIFIED; pDesc->Monitor = nullptr; return S_OK; } HRESULT DxgiOutput::GetDisplayModeList( DXGI_FORMAT EnumFormat, UINT Flags, UINT *pNumModes, DXGI_MODE_DESC *pDesc) { TRACE(this, EnumFormat, Flags, pNumModes, 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; } // 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; int numDisplayModes = SDL_GetNumDisplayModes(m_display); 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; if (SDL_GetDisplayMode(m_display, i, &currMode)) { Logger::err("DxgiOutput::GetDisplayModeList: Failed to list display modes"); return DXGI_ERROR_DRIVER_INTERNAL_ERROR; } // 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; 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) { bool isNativeMode = (currMode.w == desktopMode.w) && (currMode.h == desktopMode.h); if (isNativeMode || (Flags & DXGI_ENUM_MODES_SCALING)) { 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 = isNativeMode ? DXGI_MODE_SCALING_CENTERED : DXGI_MODE_SCALING_STRETCHED; modes.push_back(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; } } HRESULT DxgiOutput::GetDisplaySurfaceData(IDXGISurface *pDestination) { Logger::err("DxgiOutput::GetDisplaySurfaceData: Not implemented"); return E_NOTIMPL; } HRESULT DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS *pStats) { Logger::err("DxgiOutput::GetFrameStatistics: Not implemented"); return E_NOTIMPL; } HRESULT DxgiOutput::GetGammaControl(DXGI_GAMMA_CONTROL *pArray) { Logger::err("DxgiOutput::GetGammaControl: Not implemented"); return E_NOTIMPL; } HRESULT DxgiOutput::GetGammaControlCapabilities(DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps) { Logger::err("DxgiOutput::GetGammaControlCapabilities: Not implemented"); return E_NOTIMPL; } void DxgiOutput::ReleaseOwnership() { Logger::warn("DxgiOutput::ReleaseOwnership: Stub"); } HRESULT DxgiOutput::SetDisplaySurface(IDXGISurface *pScanoutSurface) { Logger::err("DxgiOutput::SetDisplaySurface: Not implemented"); return E_NOTIMPL; } HRESULT DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL *pArray) { Logger::err("DxgiOutput::SetGammaControl: Not implemented"); return E_NOTIMPL; } HRESULT DxgiOutput::TakeOwnership( IUnknown *pDevice, BOOL Exclusive) { Logger::warn("DxgiOutput::TakeOwnership: Stub"); return S_OK; } HRESULT DxgiOutput::WaitForVBlank() { Logger::warn("DxgiOutput::WaitForVBlank: Stub"); return S_OK; } }