You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/XRenderD3D9/DeviceInfo.inl

800 lines
27 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#if defined(SUPPORT_DEVICE_INFO)
#include <AzFramework/API/ApplicationAPI.h>
enum
{
#if defined(WIN32) || defined(WIN64)
DefaultBufferCount = 3
#else
DefaultBufferCount = 2
#endif
};
static void InitSwapChain(DXGI_SWAP_CHAIN_DESC& desc, UINT width, UINT height, HWND hWnd, BOOL windowed)
{
desc.BufferDesc.Width = width;
desc.BufferDesc.Height = height;
desc.BufferDesc.RefreshRate.Numerator = 0;
desc.BufferDesc.RefreshRate.Denominator = 0;
#ifdef ANDROID
desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM;
#else
static ICVar* DolbyCvar = gEnv->pConsole->GetCVar("r_HDRDolby");
if (DolbyCvar->GetIVal() == 1)
{
// Dolby Maui HDR PQ output format (10 bits)
desc.BufferDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
}
else
{
// Conventional SDR RGBA8 output buffer
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
}
#endif
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = gRenDev->CV_r_minimizeLatency > 0 ? 2 : DefaultBufferCount;
desc.OutputWindow = hWnd;
desc.Windowed = windowed ? 1 : 0;
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
#ifdef CRY_INTEGRATE_DX12
desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
#endif
}
DeviceInfo::DeviceInfo()
: m_pFactory(0)
, m_pAdapter(0)
, m_pOutput(0)
, m_pDevice(0)
, m_pContext(0)
, m_pSwapChain(0)
, m_adapterFlag(DXGI_ADAPTER_FLAG_NONE)
, m_driverType(D3D_DRIVER_TYPE_NULL)
, m_creationFlags(0)
, m_featureLevel(D3D_FEATURE_LEVEL_9_1)
#ifdef CRY_USE_METAL
, m_autoDepthStencilFmt(DXGI_FORMAT_R32G8X24_TYPELESS)
#else
, m_autoDepthStencilFmt(DXGI_FORMAT_R24G8_TYPELESS)
#endif
, m_outputIndex(0)
, m_syncInterval(0)
, m_presentFlags(0)
, m_activated(true)
, m_activatedMT(true)
#if defined(SUPPORT_DEVICE_INFO_MSG_PROCESSING)
, m_msgQueueLock()
, m_msgQueue()
#endif
{
memset(&m_adapterDesc, 0, sizeof(m_adapterDesc));
memset(&m_swapChainDesc, 0, sizeof(m_swapChainDesc));
memset(&m_refreshRate, 0, sizeof(m_refreshRate));
memset(&m_desktopRefreshRate, 0, sizeof(m_desktopRefreshRate));
}
void DeviceInfo::Release()
{
memset(&m_adapterDesc, 0, sizeof(m_adapterDesc));
memset(&m_swapChainDesc, 0, sizeof(m_swapChainDesc));
memset(&m_refreshRate, 0, sizeof(m_refreshRate));
memset(&m_desktopRefreshRate, 0, sizeof(m_desktopRefreshRate));
for (unsigned int b = 0; b < m_pBackbufferRTVs.size(); ++b)
{
SAFE_RELEASE(m_pBackbufferRTVs[b]);
}
if (m_pSwapChain)
{
m_pSwapChain->SetFullscreenState(FALSE, 0);
}
SAFE_RELEASE(m_pSwapChain);
SAFE_RELEASE(m_pContext);
SAFE_RELEASE(m_pDevice);
SAFE_RELEASE(m_pOutput);
SAFE_RELEASE(m_pAdapter);
SAFE_RELEASE(m_pFactory);
}
static void SetupPreferredMonitorDimensions(HMONITOR hMonitor)
{
#if defined(WIN32) || defined(WIN64)
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfo(hMonitor, &monitorInfo))
{
gcpRendD3D->m_prefMonX = monitorInfo.rcMonitor.left;
gcpRendD3D->m_prefMonY = monitorInfo.rcMonitor.top;
gcpRendD3D->m_prefMonWidth = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
gcpRendD3D->m_prefMonHeight = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
}
#endif
}
static void SetupMonitorAndGetAdapterDesc(IDXGIOutput* pOutput, IDXGIAdapter1* pAdapter, DXGI_ADAPTER_DESC1& adapterDesc)
{
DXGI_OUTPUT_DESC outputDesc;
if (SUCCEEDED(pOutput->GetDesc(&outputDesc)))
{
SetupPreferredMonitorDimensions(outputDesc.Monitor);
}
pAdapter->GetDesc1(&adapterDesc);
}
static int GetDXGIAdapterOverride()
{
#if defined(WIN32) || defined(WIN64)
ICVar* pCVar = gEnv->pConsole ? gEnv->pConsole->GetCVar("r_overrideDXGIAdapter") : 0;
return pCVar ? pCVar->GetIVal() : -1;
#else
return -1;
#endif
}
static void ProcessWindowMessages([[maybe_unused]] HWND hWnd)
{
#if defined(WIN32) || defined(WIN64)
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::PumpSystemEventLoopUntilEmpty);
#endif
}
#if defined(OPENGL)
static int GetMultithreaded()
{
ICVar* pCVar = gEnv->pConsole ? gEnv->pConsole->GetCVar("r_multithreaded") : 0;
return pCVar ? pCVar->GetIVal() : -1;
}
#endif
#if !defined(_RELEASE)
bool GetForcedFeatureLevel(D3D_FEATURE_LEVEL* pForcedFeatureLevel)
{
struct FeatureLevel
{
const char* m_szName;
D3D_FEATURE_LEVEL m_eValue;
};
static FeatureLevel s_aLevels[] =
{
{"10.0", D3D_FEATURE_LEVEL_10_0},
{"10.1", D3D_FEATURE_LEVEL_10_1},
{"11.0", D3D_FEATURE_LEVEL_11_0},
#if SUPPORTS_WINDOWS_10_SDK
{"11.1", D3D_FEATURE_LEVEL_11_1}
#endif
};
const char* szForcedName(gcpRendD3D->CV_d3d11_forcedFeatureLevel->GetString());
if (szForcedName == NULL || strlen(szForcedName) == 0)
{
return false;
}
FeatureLevel* pLevel;
for (pLevel = s_aLevels; pLevel < s_aLevels + SIZEOF_ARRAY(s_aLevels); ++pLevel)
{
if (strcmp(pLevel->m_szName, szForcedName) == 0)
{
*pForcedFeatureLevel = pLevel->m_eValue;
return true;
}
}
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, "Invalid value for d3d11_forcedFeatureLevel %s - using available feature level", szForcedName);
return false;
}
#endif // !defined(_RELEASE)
bool DeviceInfo::CreateDevice(bool windowed, [[maybe_unused]] int width, [[maybe_unused]] int height, int backbufferWidth, int backbufferHeight, int zbpp, OnCreateDeviceCallback pCreateDeviceCallback, CreateWindowCallback pCreateWindowCallback)
{
#ifndef CRY_USE_METAL
m_autoDepthStencilFmt = zbpp == 32 ? DXGI_FORMAT_R32G8X24_TYPELESS : DXGI_FORMAT_R24G8_TYPELESS;
#endif
#if defined(OPENGL)
HWND hWnd = pCreateWindowCallback ? pCreateWindowCallback() : 0;
if (!hWnd)
{
Release();
return false;
}
const int r_overrideDXGIAdapter = GetDXGIAdapterOverride();
const int r_multithreaded = GetMultithreaded();
unsigned int nAdapterOrdinal = r_overrideDXGIAdapter >= 0 ? r_overrideDXGIAdapter : 0;
InitSwapChain(m_swapChainDesc, backbufferWidth, backbufferHeight, hWnd, windowed);
if (!SUCCEEDED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**) &m_pFactory)) || !m_pFactory)
{
Release();
return false;
}
while (m_pFactory->EnumAdapters1(nAdapterOrdinal, &m_pAdapter) != DXGI_ERROR_NOT_FOUND)
{
if (m_pAdapter)
{
m_driverType = D3D_DRIVER_TYPE_HARDWARE;
m_creationFlags = 0;
D3D_FEATURE_LEVEL* aFeatureLevels(NULL);
unsigned int uNumFeatureLevels(0);
#if !defined(_RELEASE)
D3D_FEATURE_LEVEL eForcedFeatureLevel(D3D_FEATURE_LEVEL_11_0);
if (GetForcedFeatureLevel(&eForcedFeatureLevel))
{
aFeatureLevels = &eForcedFeatureLevel;
uNumFeatureLevels = 1;
}
#endif //!defined(_RELEASE)
const D3D_DRIVER_TYPE driverType = m_driverType == D3D_DRIVER_TYPE_HARDWARE ? D3D_DRIVER_TYPE_UNKNOWN : m_driverType;
HRESULT hr = D3D11CreateDeviceAndSwapChain(m_pAdapter, driverType, 0, m_creationFlags, aFeatureLevels, uNumFeatureLevels, D3D11_SDK_VERSION, &m_swapChainDesc, &m_pSwapChain, &m_pDevice, &m_featureLevel, &m_pContext);
if (SUCCEEDED(hr) && m_pDevice && m_pSwapChain)
{
#if defined(SUPPORT_DEVICE_INFO_USER_DISPLAY_OVERRIDES)
const uint32 outputIdx = gRenDev->CV_r_overrideDXGIOutput > 0 ? gRenDev->CV_r_overrideDXGIOutput : 0;
if (outputIdx)
{
if (SUCCEEDED(m_pAdapter->EnumOutputs(outputIdx, &m_pOutput)) && m_pOutput)
{
SetupMonitorAndGetAdapterDesc(m_pOutput, m_pAdapter, m_adapterDesc);
break;
}
SAFE_RELEASE(m_pOutput);
CryLogAlways("Failed to resolve DXGI display for override index %d. Falling back to primary display.", outputIdx);
}
#endif
if (SUCCEEDED(m_pAdapter->EnumOutputs(0, &m_pOutput)) && m_pOutput)
{
SetupMonitorAndGetAdapterDesc(m_pOutput, m_pAdapter, m_adapterDesc);
break;
}
else if (r_overrideDXGIAdapter >= 0)
{
CryLogAlways("No display connected to DXGI adapter override %d. Adapter cannot be used for rendering.", r_overrideDXGIAdapter);
}
}
SAFE_RELEASE(m_pOutput);
SAFE_RELEASE(m_pContext);
SAFE_RELEASE(m_pDevice);
SAFE_RELEASE(m_pSwapChain);
SAFE_RELEASE(m_pAdapter);
}
}
if (!m_pDevice || !m_pSwapChain)
{
Release();
return false;
}
m_pFactory->MakeWindowAssociation(m_swapChainDesc.OutputWindow, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
if (pCreateDeviceCallback)
{
pCreateDeviceCallback(m_pDevice);
}
#if !DXGL_FULL_EMULATION && !defined(CRY_USE_METAL)
if (r_multithreaded)
{
DXGLReserveContext(m_pDevice);
}
DXGLBindDeviceContext(m_pContext, !r_multithreaded);
#endif //!DXGL_FULL_EMULATION
bool bSuccess = CreateViews();
if (!bSuccess)
{
Release();
}
return IsOk();
#elif defined(WIN32) || defined(WIN64)
typedef HRESULT (WINAPI * FP_CreateDXGIFactory1)(REFIID, void**);
FP_CreateDXGIFactory1 pCDXGIF =
#if defined(CRY_USE_DX12)
(FP_CreateDXGIFactory1) DX12CreateDXGIFactory1;
#else
(FP_CreateDXGIFactory1) GetProcAddress(LoadLibraryA("dxgi.dll"), "CreateDXGIFactory1");
#endif
IDXGIAdapter1* pAdapter = nullptr;
IDXGIOutput* pOutput = nullptr;
ID3D11Device* pDevice = nullptr;
ID3D11DeviceContext* pContext = nullptr;
if (pCDXGIF && SUCCEEDED(pCDXGIF(__uuidof(IDXGIFactory1), (void**) &m_pFactory)) && m_pFactory)
{
typedef HRESULT (WINAPI * CreateDeviceCallback)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
CreateDeviceCallback createDeviceCallback =
#if defined(CRY_USE_DX12)
(CreateDeviceCallback)DX12CreateDevice;
#else
(CreateDeviceCallback)GetProcAddress(LoadLibraryA("d3d11.dll"), "D3D11CreateDevice");
#endif
if (createDeviceCallback)
{
const int r_overrideDXGIAdapter = GetDXGIAdapterOverride();
unsigned int nAdapterOrdinal = r_overrideDXGIAdapter >= 0 ? r_overrideDXGIAdapter : 0;
while (m_pFactory->EnumAdapters1(nAdapterOrdinal, &pAdapter) != DXGI_ERROR_NOT_FOUND)
{
if (pAdapter)
{
// Promote interfaces to the required level
pAdapter->QueryInterface(__uuidof(DXGIAdapter), (void**)&m_pAdapter);
#if defined(SUPPORT_D3D_DEBUG_RUNTIME)
const unsigned int debugRTFlag = gcpRendD3D->CV_d3d11_debugruntime ? D3D11_CREATE_DEVICE_DEBUG : 0;
#else
const unsigned int debugRTFlag = 0;
#endif
m_driverType = D3D_DRIVER_TYPE_HARDWARE;
m_creationFlags = debugRTFlag;
#if defined(WIN32) || defined(WIN64)
// CRY DX12 DISABLED TEMPORARILY if (gcpRendD3D->CV_d3d11_preventDriverThreading)
// m_creationFlags |= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS;
#endif
D3D_FEATURE_LEVEL arrFeatureLevels[] = {
#if SUPPORTS_WINDOWS_10_SDK
D3D_FEATURE_LEVEL_11_1,
#endif
D3D_FEATURE_LEVEL_11_0
};
D3D_FEATURE_LEVEL* pFeatureLevels(arrFeatureLevels);
unsigned int uNumFeatureLevels(sizeof(arrFeatureLevels) / sizeof(D3D_FEATURE_LEVEL));
#if !defined(_RELEASE)
D3D_FEATURE_LEVEL eForcedFeatureLevel;
if (GetForcedFeatureLevel(&eForcedFeatureLevel))
{
pFeatureLevels = &eForcedFeatureLevel;
uNumFeatureLevels = 1;
}
#endif //!defined(_RELEASE)
DXGI_ADAPTER_DESC1 adapterDesc1;
if (SUCCEEDED(m_pAdapter->GetDesc1(&adapterDesc1)))
{
// We need to know if this is a software adapter (e.g., WARP) which may not have any outputs
m_adapterFlag = static_cast<DXGI_ADAPTER_FLAG>(adapterDesc1.Flags);
}
const D3D_DRIVER_TYPE driverType = m_driverType == D3D_DRIVER_TYPE_HARDWARE ? D3D_DRIVER_TYPE_UNKNOWN : m_driverType;
HRESULT hr = createDeviceCallback(pAdapter, driverType, 0, m_creationFlags, pFeatureLevels, uNumFeatureLevels, D3D11_SDK_VERSION, &pDevice, &m_featureLevel, &pContext);
if (SUCCEEDED(hr) && pDevice)
{
// Promote interfaces to the required level
pDevice->QueryInterface(__uuidof(D3DDevice), (void**)&m_pDevice);
pContext->QueryInterface(__uuidof(D3DDeviceContext), (void**)&m_pContext);
{
DXGIDevice* pDXGIDevice = 0;
if (SUCCEEDED(pDevice->QueryInterface(__uuidof(DXGIDevice), (void**) &pDXGIDevice)) && pDXGIDevice)
{
// SetMaximumFrameLatency as 3 in editor mode to avoid waiting GPU during Present.
// Because there might be multiple Presents in one update loop (main render present, material editor present...),
// setting it as 1 is not enough in this case, during the same update loop, the 2nd present can wait significant time for 1st presented GPU draw.
pDXGIDevice->SetMaximumFrameLatency(gcpRendD3D->IsEditorMode() ? 3 : 1);
}
SAFE_RELEASE(pDXGIDevice);
}
#if defined(SUPPORT_DEVICE_INFO_USER_DISPLAY_OVERRIDES)
m_outputIndex = gRenDev->CV_r_overrideDXGIOutput > 0 ? gRenDev->CV_r_overrideDXGIOutput : 0;
if (m_outputIndex)
{
if (SUCCEEDED(pAdapter->EnumOutputs(m_outputIndex, &pOutput)) && pOutput)
{
// Promote interfaces to the required level
pOutput->QueryInterface(__uuidof(DXGIOutput), (void**)&m_pOutput);
SetupMonitorAndGetAdapterDesc(m_pOutput, m_pAdapter, m_adapterDesc);
break;
}
SAFE_RELEASE(pOutput);
CryLogAlways("Failed to resolve DXGI display for override index %d. Falling back to primary display.", m_outputIndex);
m_outputIndex = 0;
}
#endif
if (SUCCEEDED(pAdapter->EnumOutputs(0, &pOutput)) && pOutput)
{
// Promote interfaces to the required level
pOutput->QueryInterface(__uuidof(DXGIOutput), (void**)&m_pOutput);
SetupMonitorAndGetAdapterDesc(m_pOutput, m_pAdapter, m_adapterDesc);
break;
}
else if (m_adapterFlag == DXGI_ADAPTER_FLAG_SOFTWARE || m_driverType == D3D_DRIVER_TYPE_WARP)
{
break;
}
else if (r_overrideDXGIAdapter >= 0)
{
CryLogAlways("No display connected to DXGI adapter override %d. Adapter cannot be used for rendering.", r_overrideDXGIAdapter);
}
}
// Decrement QueryInterface() increment
SAFE_RELEASE(m_pOutput);
SAFE_RELEASE(m_pContext);
SAFE_RELEASE(m_pDevice);
SAFE_RELEASE(m_pAdapter);
// Decrement Create() increment
SAFE_RELEASE(pOutput);
SAFE_RELEASE(pContext);
SAFE_RELEASE(pDevice);
SAFE_RELEASE(pAdapter);
}
if (r_overrideDXGIAdapter >= 0)
{
break;
}
++nAdapterOrdinal;
}
}
}
if (!m_pFactory || !m_pAdapter || !m_pDevice || !m_pContext)
{
Release();
return false;
}
if (!m_pOutput && m_adapterFlag != DXGI_ADAPTER_FLAG_SOFTWARE && m_driverType != D3D_DRIVER_TYPE_WARP)
{
Release();
return false;
}
// Decrement Create() increment
SAFE_RELEASE(pOutput);
SAFE_RELEASE(pContext);
SAFE_RELEASE(pDevice);
SAFE_RELEASE(pAdapter);
// Get SDK level D3D device pointer
#ifdef CRY_INTEGRATE_DX12
IUnknown* d3dDevice = static_cast<CCryDX12Device*>(m_pDevice)->GetD3D12Device();
#else
IUnknown* d3dDevice = m_pDevice;
#endif
#if defined(WIN32) || defined(WIN64)
{
DXGI_MODE_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Width = gcpRendD3D->m_prefMonWidth;
desc.Height = gcpRendD3D->m_prefMonHeight;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
DXGI_MODE_DESC match;
if (m_pOutput && SUCCEEDED(m_pOutput->FindClosestMatchingMode(&desc, &match, d3dDevice)))
{
m_desktopRefreshRate = match.RefreshRate;
}
}
#endif
HWND hWnd = pCreateWindowCallback ? pCreateWindowCallback() : 0;
if (!hWnd)
{
Release();
return false;
}
ProcessWindowMessages(hWnd);
{
InitSwapChain(m_swapChainDesc, backbufferWidth, backbufferHeight, hWnd, windowed);
if (!windowed)
{
DXGI_MODE_DESC match;
if (m_pOutput && SUCCEEDED(m_pOutput->FindClosestMatchingMode(&m_swapChainDesc.BufferDesc, &match, d3dDevice)))
{
m_swapChainDesc.BufferDesc = match;
}
}
m_refreshRate = !windowed ? m_swapChainDesc.BufferDesc.RefreshRate : m_desktopRefreshRate;
IDXGISwapChain* pSwapChain;
HRESULT hr = m_pFactory->CreateSwapChain(m_pDevice, &m_swapChainDesc, &pSwapChain);
if (FAILED(hr) || !pSwapChain)
{
Release();
return false;
}
// Promote interfaces to the required level
hr = pSwapChain->QueryInterface(__uuidof(DXGISwapChain), (void**)&m_pSwapChain);
if (FAILED(hr) || !m_pSwapChain)
{
Release();
return false;
}
#ifdef CRY_INTEGRATE_DX12
m_pSwapChain->SetMaximumFrameLatency(1);
m_frameLatencyWaitableObject = m_pSwapChain->GetFrameLatencyWaitableObject();
#endif
// Decrement Create() increment
SAFE_RELEASE(pSwapChain);
}
{
m_pFactory->MakeWindowAssociation(m_swapChainDesc.OutputWindow, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
if (pCreateDeviceCallback)
{
pCreateDeviceCallback(m_pDevice);
}
}
if (!CreateViews())
{
Release();
}
ProcessWindowMessages(hWnd);
return IsOk();
#else
#pragma message("DeviceInfo::CreateDevice not implemented on this platform")
return false;
#endif
}
bool DeviceInfo::CreateViews()
{
DXGI_SWAP_CHAIN_DESC scDesc;
m_pSwapChain->GetDesc(&scDesc);
AZ::u32 bufferCount = scDesc.BufferCount;
#if !defined(CRY_USE_DX12)
bufferCount = 1;
#endif
m_pBackbufferRTVs.resize(bufferCount);
for (unsigned int b = 0; b < bufferCount; ++b)
{
D3DTexture* pBackBuffer = 0;
HRESULT hr = m_pSwapChain->GetBuffer(b, __uuidof(D3DTexture), (void**) &pBackBuffer);
if (SUCCEEDED(hr) && pBackBuffer)
{
{
assert(!m_pBackbufferRTVs[b]);
hr = m_pDevice->CreateRenderTargetView(pBackBuffer, 0, &m_pBackbufferRTVs[b]);
}
#if !defined(RELEASE) && defined(WIN64)
char str[32] = "";
azsprintf(str, "Swap-Chain back buffer %d", b);
pBackBuffer->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(str), str);
#endif
}
SAFE_RELEASE(pBackBuffer);
}
m_pCurrentBackBufferRTVIndex = CD3D9Renderer::GetCurrentBackBufferIndex(m_pSwapChain);
return true;
}
void DeviceInfo::SnapSettings()
{
if (m_swapChainDesc.Windowed)
{
m_swapChainDesc.BufferDesc.RefreshRate.Denominator = 0;
m_swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
m_swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
m_swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
m_refreshRate = m_desktopRefreshRate;
}
else
{
DXGI_MODE_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Width = m_swapChainDesc.BufferDesc.Width;
desc.Height = m_swapChainDesc.BufferDesc.Height;
desc.Format = m_swapChainDesc.BufferDesc.Format;
DXGI_MODE_DESC match;
#ifdef CRY_INTEGRATE_DX12
IUnknown* d3dDevice = static_cast<CCryDX12Device*>(m_pDevice)->GetD3D12Device();
#else
IUnknown* d3dDevice = m_pDevice;
#endif
if (m_pOutput && SUCCEEDED(m_pOutput->FindClosestMatchingMode(&desc, &match, d3dDevice)))
{
m_swapChainDesc.BufferDesc = match;
m_refreshRate = match.RefreshRate;
}
}
}
void DeviceInfo::ResizeDXGIBuffers()
{
for (unsigned int b = 0; b < m_pBackbufferRTVs.size(); ++b)
{
SAFE_RELEASE(m_pBackbufferRTVs[b]);
}
UINT flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
#ifdef CRY_INTEGRATE_DX12
flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
#endif
m_pSwapChain->ResizeBuffers(0, m_swapChainDesc.BufferDesc.Width, m_swapChainDesc.BufferDesc.Height, m_swapChainDesc.BufferDesc.Format, flags);
CreateViews();
}
#if defined(SUPPORT_DEVICE_INFO_MSG_PROCESSING)
void DeviceInfo::OnActivate(UINT_PTR wParam, UINT_PTR lParam)
{
const bool activate = LOWORD(wParam) != 0;
if (m_activatedMT != activate)
{
if (gcpRendD3D->IsFullscreen())
{
HWND hWnd = (HWND) gcpRendD3D->GetHWND();
ShowWindow(hWnd, activate ? SW_RESTORE : SW_MINIMIZE);
}
m_activatedMT = activate;
}
PushSystemEvent(ESYSTEM_EVENT_ACTIVATE, wParam, lParam);
}
void DeviceInfo::PushSystemEvent(ESystemEvent event, UINT_PTR wParam, UINT_PTR lParam)
{
#if !defined(_RELEASE) && !defined(STRIP_RENDER_THREAD)
if (gcpRendD3D->m_pRT && !gcpRendD3D->m_pRT->IsMainThread())
{
__debugbreak();
}
#endif
CryAutoCriticalSection lock(m_msgQueueLock);
m_msgQueue.push_back(DeviceInfoInternal::MsgQueueItem(event, wParam, lParam));
}
void DeviceInfo::ProcessSystemEventQueue()
{
#if !defined(_RELEASE)
if (gcpRendD3D->m_pRT && !gcpRendD3D->m_pRT->IsRenderThread())
{
__debugbreak();
}
#endif
m_msgQueueLock.Lock();
DeviceInfoInternal::MsgQueue localQueue;
localQueue.swap(m_msgQueue);
m_msgQueueLock.Unlock();
for (size_t i = 0; i < localQueue.size(); ++i)
{
const DeviceInfoInternal::MsgQueueItem& item = localQueue[i];
ProcessSystemEvent(item.event, item.wParam, item.lParam);
}
}
void DeviceInfo::ProcessSystemEvent(ESystemEvent event, UINT_PTR wParam, [[maybe_unused]] UINT_PTR lParam)
{
#if !defined(_RELEASE)
if (gcpRendD3D->m_pRT && !gcpRendD3D->m_pRT->IsRenderThread())
{
__debugbreak();
}
#endif
switch (event)
{
case ESYSTEM_EVENT_ACTIVATE:
{
#if defined(WIN32)
// disable floating point exceptions due to driver bug with floating point exceptions
SCOPED_DISABLE_FLOAT_EXCEPTIONS;
#endif
const bool activate = LOWORD(wParam) != 0;
if (m_activated != activate)
{
const bool isFullscreen = gcpRendD3D->IsFullscreen();
if (isFullscreen && !activate)
{
gcpRendD3D->GetS3DRend().ReleaseBuffers();
m_pSwapChain->SetFullscreenState(FALSE, 0);
ResizeDXGIBuffers();
gcpRendD3D->OnD3D11PostCreateDevice(m_pDevice);
}
else if (isFullscreen && activate)
{
gcpRendD3D->GetS3DRend().ReleaseBuffers();
m_pSwapChain->SetFullscreenState(TRUE, 0);
ResizeDXGIBuffers();
gcpRendD3D->GetS3DRend().OnResolutionChanged();
gcpRendD3D->OnD3D11PostCreateDevice(m_pDevice);
}
m_activated = activate;
}
}
break;
default:
assert(0);
break;
}
}
#endif // #if defined(SUPPORT_DEVICE_INFO_MSG_PROCESSING)
#if defined(WIN32) || defined(WIN64)
void DeviceInfo::EnforceFullscreenPreemption()
{
if (gRenDev->CV_r_FullscreenPreemption && gcpRendD3D->IsFullscreen())
{
HRESULT hr = m_pSwapChain->Present(0, DXGI_PRESENT_TEST);
if (hr == DXGI_STATUS_OCCLUDED)
{
HWND hWnd = (HWND) gcpRendD3D->GetHWND();
if (m_activated)
{
BringWindowToTop(hWnd);
}
}
}
}
#ifdef CRY_INTEGRATE_DX12
void DeviceInfo::WaitForGPUFrames()
{
FUNCTION_PROFILER_RENDER_FLAT
WaitForSingleObjectEx(
m_frameLatencyWaitableObject,
1000, // 1 second timeout (shouldn't ever occur)
true
);
}
#endif
#endif // #if defined(WIN32) || defined(WIN64)
#endif // #if defined(SUPPORT_DEVICE_INFO)