Update HDR support for PC to avoid GetContainingOutput (#36)
This commit is contained in:
Родитель
26d73c1ce2
Коммит
187562b015
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// DeviceResources.cpp - A wrapper for the Direct3D 11 device and swapchain
|
||||
// (requires DirectX 11.1 Runtime)
|
||||
//
|
||||
|
@ -11,11 +11,13 @@ using namespace DX;
|
|||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
namespace
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
// Check for SDK Layer support.
|
||||
inline bool SdkLayersAvailable()
|
||||
inline bool SdkLayersAvailable() noexcept
|
||||
{
|
||||
HRESULT hr = D3D11CreateDevice(
|
||||
nullptr,
|
||||
|
@ -34,7 +36,7 @@ namespace
|
|||
}
|
||||
#endif
|
||||
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt)
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt) noexcept
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
|
@ -44,26 +46,38 @@ namespace
|
|||
default: return fmt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline long ComputeIntersectionArea(
|
||||
long ax1, long ay1, long ax2, long ay2,
|
||||
long bx1, long by1, long bx2, long by2) noexcept
|
||||
{
|
||||
return std::max(0l, std::min(ax2, bx2) - std::max(ax1, bx1)) * std::max(0l, std::min(ay2, by2) - std::max(ay1, by1));
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for DeviceResources.
|
||||
DeviceResources::DeviceResources(DXGI_FORMAT backBufferFormat, DXGI_FORMAT depthBufferFormat, UINT backBufferCount, D3D_FEATURE_LEVEL minFeatureLevel, unsigned int flags) :
|
||||
m_screenViewport{},
|
||||
m_backBufferFormat(backBufferFormat),
|
||||
m_depthBufferFormat(depthBufferFormat),
|
||||
m_backBufferCount(backBufferCount),
|
||||
m_d3dMinFeatureLevel(minFeatureLevel),
|
||||
m_window(nullptr),
|
||||
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1),
|
||||
m_outputSize{0, 0, 1, 1},
|
||||
m_colorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709),
|
||||
m_options(flags | c_FlipPresent),
|
||||
m_deviceNotify(nullptr)
|
||||
DeviceResources::DeviceResources(
|
||||
DXGI_FORMAT backBufferFormat,
|
||||
DXGI_FORMAT depthBufferFormat,
|
||||
UINT backBufferCount,
|
||||
D3D_FEATURE_LEVEL minFeatureLevel,
|
||||
unsigned int flags) noexcept :
|
||||
m_screenViewport{},
|
||||
m_backBufferFormat(backBufferFormat),
|
||||
m_depthBufferFormat(depthBufferFormat),
|
||||
m_backBufferCount(backBufferCount),
|
||||
m_d3dMinFeatureLevel(minFeatureLevel),
|
||||
m_window(nullptr),
|
||||
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1),
|
||||
m_outputSize{0, 0, 1, 1},
|
||||
m_colorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709),
|
||||
m_options(flags | c_FlipPresent),
|
||||
m_deviceNotify(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// Configures the Direct3D device, and stores handles to it and the device context.
|
||||
void DeviceResources::CreateDeviceResources()
|
||||
void DeviceResources::CreateDeviceResources()
|
||||
{
|
||||
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||
|
||||
|
@ -184,7 +198,7 @@ void DeviceResources::CreateDeviceResources()
|
|||
if (FAILED(hr))
|
||||
{
|
||||
// If the initialization fails, fall back to the WARP device.
|
||||
// For more information on WARP, see:
|
||||
// For more information on WARP, see:
|
||||
// http://go.microsoft.com/fwlink/?LinkId=286690
|
||||
hr = D3D11CreateDevice(
|
||||
nullptr,
|
||||
|
@ -237,7 +251,7 @@ void DeviceResources::CreateDeviceResources()
|
|||
}
|
||||
|
||||
// These resources need to be recreated every time the window size is changed.
|
||||
void DeviceResources::CreateWindowSizeDependentResources()
|
||||
void DeviceResources::CreateWindowSizeDependentResources()
|
||||
{
|
||||
if (!m_window)
|
||||
{
|
||||
|
@ -245,8 +259,7 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// Clear the previous window size specific context.
|
||||
ID3D11RenderTargetView* nullViews[] = {nullptr};
|
||||
m_d3dContext->OMSetRenderTargets(_countof(nullViews), nullViews, nullptr);
|
||||
m_d3dContext->OMSetRenderTargets(0, nullptr, nullptr);
|
||||
m_d3dRenderTargetView.Reset();
|
||||
m_d3dDepthStencilView.Reset();
|
||||
m_renderTarget.Reset();
|
||||
|
@ -254,9 +267,9 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
m_d3dContext->Flush();
|
||||
|
||||
// Determine the render target size in pixels.
|
||||
UINT backBufferWidth = std::max<UINT>(m_outputSize.right - m_outputSize.left, 1);
|
||||
UINT backBufferHeight = std::max<UINT>(m_outputSize.bottom - m_outputSize.top, 1);
|
||||
DXGI_FORMAT backBufferFormat = (m_options & (c_FlipPresent | c_AllowTearing | c_EnableHDR)) ? NoSRGB(m_backBufferFormat) : m_backBufferFormat;
|
||||
const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);
|
||||
const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);
|
||||
const DXGI_FORMAT backBufferFormat = (m_options & (c_FlipPresent | c_AllowTearing | c_EnableHDR)) ? NoSRGB(m_backBufferFormat) : m_backBufferFormat;
|
||||
|
||||
if (m_swapChain)
|
||||
{
|
||||
|
@ -273,13 +286,14 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
// If the device was removed for any reason, a new device and swap chain will need to be created.
|
||||
HandleDeviceLost();
|
||||
|
||||
// Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
|
||||
// Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
|
||||
// and correctly set up the new device.
|
||||
return;
|
||||
}
|
||||
|
@ -358,7 +372,7 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
m_d3dDepthStencilView.ReleaseAndGetAddressOf()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
// Set the 3D rendering viewport to target the entire window.
|
||||
m_screenViewport = CD3D11_VIEWPORT(
|
||||
0.0f,
|
||||
|
@ -369,7 +383,7 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// This method is called when the Win32 window is created (or re-created).
|
||||
void DeviceResources::SetWindow(HWND window, int width, int height)
|
||||
void DeviceResources::SetWindow(HWND window, int width, int height) noexcept
|
||||
{
|
||||
m_window = window;
|
||||
|
||||
|
@ -437,9 +451,9 @@ void DeviceResources::HandleDeviceLost()
|
|||
}
|
||||
|
||||
// Present the contents of the swap chain to the screen.
|
||||
void DeviceResources::Present()
|
||||
void DeviceResources::Present()
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr = E_FAIL;
|
||||
if (m_options & c_AllowTearing)
|
||||
{
|
||||
// Recommended to always use tearing if supported when using a sync interval of 0.
|
||||
|
@ -464,13 +478,14 @@ void DeviceResources::Present()
|
|||
m_d3dContext->DiscardView(m_d3dDepthStencilView.Get());
|
||||
}
|
||||
|
||||
// If the device was removed either by a disconnection or a driver upgrade, we
|
||||
// If the device was removed either by a disconnection or a driver upgrade, we
|
||||
// must recreate all device resources.
|
||||
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
HandleDeviceLost();
|
||||
|
@ -481,8 +496,7 @@ void DeviceResources::Present()
|
|||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
CreateFactory();
|
||||
UpdateColorSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -501,6 +515,15 @@ void DeviceResources::CreateFactory()
|
|||
|
||||
dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);
|
||||
dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);
|
||||
|
||||
DXGI_INFO_QUEUE_MESSAGE_ID hide[] =
|
||||
{
|
||||
80 /* IDXGISwapChain::GetContainingOutput: The swapchain's adapter does not control the output on which the swapchain's window resides. */,
|
||||
};
|
||||
DXGI_INFO_QUEUE_FILTER filter = {};
|
||||
filter.DenyList.NumIDs = _countof(hide);
|
||||
filter.DenyList.pIDList = hide;
|
||||
dxgiInfoQueue->AddStorageFilterEntries(DXGI_DEBUG_DXGI, &filter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -517,24 +540,63 @@ void DeviceResources::GetHardwareAdapter(IDXGIAdapter1** ppAdapter)
|
|||
*ppAdapter = nullptr;
|
||||
|
||||
ComPtr<IDXGIAdapter1> adapter;
|
||||
for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != m_dxgiFactory->EnumAdapters1(adapterIndex, adapter.ReleaseAndGetAddressOf()); adapterIndex++)
|
||||
{
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
adapter->GetDesc1(&desc);
|
||||
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
|
||||
#if defined(__dxgi1_6_h__) && defined(NTDDI_WIN10_RS4)
|
||||
ComPtr<IDXGIFactory6> factory6;
|
||||
HRESULT hr = m_dxgiFactory.As(&factory6);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(factory6->EnumAdapterByGpuPreference(
|
||||
adapterIndex,
|
||||
DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
|
||||
IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf())));
|
||||
adapterIndex++)
|
||||
{
|
||||
// Don't select the Basic Render Driver adapter.
|
||||
continue;
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
ThrowIfFailed(adapter->GetDesc1(&desc));
|
||||
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
|
||||
{
|
||||
// Don't select the Basic Render Driver adapter.
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
wchar_t buff[256] = {};
|
||||
swprintf_s(buff, L"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\n", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);
|
||||
OutputDebugStringW(buff);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!adapter)
|
||||
{
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(m_dxgiFactory->EnumAdapters1(
|
||||
adapterIndex,
|
||||
adapter.ReleaseAndGetAddressOf()));
|
||||
adapterIndex++)
|
||||
{
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
ThrowIfFailed(adapter->GetDesc1(&desc));
|
||||
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
|
||||
{
|
||||
// Don't select the Basic Render Driver adapter.
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
wchar_t buff[256] = {};
|
||||
swprintf_s(buff, L"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\n", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);
|
||||
OutputDebugStringW(buff);
|
||||
wchar_t buff[256] = {};
|
||||
swprintf_s(buff, L"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\n", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);
|
||||
OutputDebugStringW(buff);
|
||||
#endif
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*ppAdapter = adapter.Detach();
|
||||
|
@ -543,6 +605,15 @@ void DeviceResources::GetHardwareAdapter(IDXGIAdapter1** ppAdapter)
|
|||
// Sets the color space for the swap chain in order to handle HDR output.
|
||||
void DeviceResources::UpdateColorSpace()
|
||||
{
|
||||
if (!m_dxgiFactory)
|
||||
return;
|
||||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
CreateFactory();
|
||||
}
|
||||
|
||||
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
bool isDisplayHDR10 = false;
|
||||
|
@ -550,11 +621,52 @@ void DeviceResources::UpdateColorSpace()
|
|||
#if defined(NTDDI_WIN10_RS2)
|
||||
if (m_swapChain)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
if (SUCCEEDED(m_swapChain->GetContainingOutput(output.GetAddressOf())))
|
||||
// To detect HDR support, we will need to check the color space in the primary
|
||||
// DXGI output associated with the app at this point in time
|
||||
// (using window/display intersection).
|
||||
|
||||
// Get the retangle bounds of the app window.
|
||||
RECT windowBounds;
|
||||
if (!GetWindowRect(m_window, &windowBounds))
|
||||
throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), "GetWindowRect");
|
||||
|
||||
const long ax1 = windowBounds.left;
|
||||
const long ay1 = windowBounds.top;
|
||||
const long ax2 = windowBounds.right;
|
||||
const long ay2 = windowBounds.bottom;
|
||||
|
||||
ComPtr<IDXGIOutput> bestOutput;
|
||||
long bestIntersectArea = -1;
|
||||
|
||||
ComPtr<IDXGIAdapter> adapter;
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(m_dxgiFactory->EnumAdapters(adapterIndex, adapter.ReleaseAndGetAddressOf()));
|
||||
++adapterIndex)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
for (UINT outputIndex = 0;
|
||||
SUCCEEDED(adapter->EnumOutputs(outputIndex, output.ReleaseAndGetAddressOf()));
|
||||
++outputIndex)
|
||||
{
|
||||
// Get the rectangle bounds of current output.
|
||||
DXGI_OUTPUT_DESC desc;
|
||||
ThrowIfFailed(output->GetDesc(&desc));
|
||||
const auto& r = desc.DesktopCoordinates;
|
||||
|
||||
// Compute the intersection
|
||||
const long intersectArea = ComputeIntersectionArea(ax1, ay1, ax2, ay2, r.left, r.top, r.right, r.bottom);
|
||||
if (intersectArea > bestIntersectArea)
|
||||
{
|
||||
bestOutput.Swap(output);
|
||||
bestIntersectArea = intersectArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestOutput)
|
||||
{
|
||||
ComPtr<IDXGIOutput6> output6;
|
||||
if (SUCCEEDED(output.As(&output6)))
|
||||
if (SUCCEEDED(bestOutput.As(&output6)))
|
||||
{
|
||||
DXGI_OUTPUT_DESC1 desc;
|
||||
ThrowIfFailed(output6->GetDesc1(&desc));
|
||||
|
@ -591,7 +703,7 @@ void DeviceResources::UpdateColorSpace()
|
|||
m_colorSpace = colorSpace;
|
||||
|
||||
ComPtr<IDXGISwapChain3> swapChain3;
|
||||
if (SUCCEEDED(m_swapChain.As(&swapChain3)))
|
||||
if (m_swapChain && SUCCEEDED(m_swapChain.As(&swapChain3)))
|
||||
{
|
||||
UINT colorSpaceSupport = 0;
|
||||
if (SUCCEEDED(swapChain3->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// DeviceResources.h - A wrapper for the Direct3D 11 device and swapchain
|
||||
//
|
||||
|
||||
|
@ -28,34 +28,44 @@ namespace DX
|
|||
DXGI_FORMAT depthBufferFormat = DXGI_FORMAT_D32_FLOAT,
|
||||
UINT backBufferCount = 2,
|
||||
D3D_FEATURE_LEVEL minFeatureLevel = D3D_FEATURE_LEVEL_10_0,
|
||||
unsigned int flags = c_FlipPresent);
|
||||
unsigned int flags = c_FlipPresent) noexcept;
|
||||
~DeviceResources() = default;
|
||||
|
||||
DeviceResources(DeviceResources&&) = default;
|
||||
DeviceResources& operator= (DeviceResources&&) = default;
|
||||
|
||||
DeviceResources(DeviceResources const&) = delete;
|
||||
DeviceResources& operator= (DeviceResources const&) = delete;
|
||||
|
||||
void CreateDeviceResources();
|
||||
void CreateWindowSizeDependentResources();
|
||||
void SetWindow(HWND window, int width, int height);
|
||||
void SetWindow(HWND window, int width, int height) noexcept;
|
||||
bool WindowSizeChanged(int width, int height);
|
||||
void HandleDeviceLost();
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) { m_deviceNotify = deviceNotify; }
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) noexcept { m_deviceNotify = deviceNotify; }
|
||||
void Present();
|
||||
void UpdateColorSpace();
|
||||
|
||||
// Device Accessors.
|
||||
RECT GetOutputSize() const { return m_outputSize; }
|
||||
RECT GetOutputSize() const noexcept { return m_outputSize; }
|
||||
|
||||
// Direct3D Accessors.
|
||||
ID3D11Device1* GetD3DDevice() const { return m_d3dDevice.Get(); }
|
||||
ID3D11DeviceContext1* GetD3DDeviceContext() const { return m_d3dContext.Get(); }
|
||||
IDXGISwapChain1* GetSwapChain() const { return m_swapChain.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; }
|
||||
ID3D11Texture2D* GetRenderTarget() const { return m_renderTarget.Get(); }
|
||||
ID3D11Texture2D* GetDepthStencil() const { return m_depthStencil.Get(); }
|
||||
ID3D11RenderTargetView* GetRenderTargetView() const { return m_d3dRenderTargetView.Get(); }
|
||||
ID3D11DepthStencilView* GetDepthStencilView() const { return m_d3dDepthStencilView.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const { return m_depthBufferFormat; }
|
||||
D3D11_VIEWPORT GetScreenViewport() const { return m_screenViewport; }
|
||||
UINT GetBackBufferCount() const { return m_backBufferCount; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const { return m_options; }
|
||||
auto GetD3DDevice() const noexcept { return m_d3dDevice.Get(); }
|
||||
auto GetD3DDeviceContext() const noexcept { return m_d3dContext.Get(); }
|
||||
auto GetSwapChain() const noexcept { return m_swapChain.Get(); }
|
||||
auto GetDXGIFactory() const noexcept { return m_dxgiFactory.Get(); }
|
||||
HWND GetWindow() const noexcept { return m_window; }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const noexcept { return m_d3dFeatureLevel; }
|
||||
ID3D11Texture2D* GetRenderTarget() const noexcept { return m_renderTarget.Get(); }
|
||||
ID3D11Texture2D* GetDepthStencil() const noexcept { return m_depthStencil.Get(); }
|
||||
ID3D11RenderTargetView* GetRenderTargetView() const noexcept { return m_d3dRenderTargetView.Get(); }
|
||||
ID3D11DepthStencilView* GetDepthStencilView() const noexcept { return m_d3dDepthStencilView.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const noexcept { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const noexcept { return m_depthBufferFormat; }
|
||||
D3D11_VIEWPORT GetScreenViewport() const noexcept { return m_screenViewport; }
|
||||
UINT GetBackBufferCount() const noexcept { return m_backBufferCount; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const noexcept { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const noexcept { return m_options; }
|
||||
|
||||
// Performance events
|
||||
void PIXBeginEvent(_In_z_ const wchar_t* name)
|
||||
|
@ -76,7 +86,6 @@ namespace DX
|
|||
private:
|
||||
void CreateFactory();
|
||||
void GetHardwareAdapter(IDXGIAdapter1** ppAdapter);
|
||||
void UpdateColorSpace();
|
||||
|
||||
// Direct3D objects.
|
||||
Microsoft::WRL::ComPtr<IDXGIFactory2> m_dxgiFactory;
|
||||
|
@ -112,4 +121,4 @@ namespace DX
|
|||
// The IDeviceNotify can be held directly as it owns the DeviceResources.
|
||||
IDeviceNotify* m_deviceNotify;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,14 +12,17 @@
|
|||
|
||||
using namespace DirectX;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unique_ptr<Sample> g_sample;
|
||||
};
|
||||
}
|
||||
|
||||
LPCWSTR g_szAppName = L"SimpleHDR_PC";
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
void ExitGame() noexcept;
|
||||
|
||||
// Indicates to hybrid graphics systems to prefer the discrete part by default
|
||||
extern "C"
|
||||
|
@ -46,17 +49,14 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
|||
// Register class and create window
|
||||
{
|
||||
// Register class
|
||||
WNDCLASSEXW wcex;
|
||||
WNDCLASSEXW wcex = {};
|
||||
wcex.cbSize = sizeof(WNDCLASSEXW);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInstance;
|
||||
wcex.hIcon = LoadIconW(hInstance, L"IDI_ICON");
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
||||
wcex.lpszMenuName = nullptr;
|
||||
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
|
||||
wcex.lpszClassName = L"SimpleHDR_PCWindowClass";
|
||||
wcex.hIconSm = LoadIconW(wcex.hInstance, L"IDI_ICON");
|
||||
if (!RegisterClassExW(&wcex))
|
||||
|
@ -79,7 +79,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
|||
|
||||
ShowWindow(hwnd, nCmdShow);
|
||||
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_sample.get()) );
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_sample.get()));
|
||||
|
||||
GetClientRect(hwnd, &rc);
|
||||
|
||||
|
@ -105,15 +105,12 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
|||
|
||||
CoUninitialize();
|
||||
|
||||
return (int) msg.wParam;
|
||||
return static_cast<int>(msg.wParam);
|
||||
}
|
||||
|
||||
// Windows procedure
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc;
|
||||
|
||||
static bool s_in_sizemove = false;
|
||||
static bool s_in_suspend = false;
|
||||
static bool s_minimized = false;
|
||||
|
@ -131,11 +128,19 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
else
|
||||
{
|
||||
hdc = BeginPaint(hWnd, &ps);
|
||||
PAINTSTRUCT ps;
|
||||
(void)BeginPaint(hWnd, &ps);
|
||||
EndPaint(hWnd, &ps);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DISPLAYCHANGE:
|
||||
if (sample)
|
||||
{
|
||||
sample->OnDisplayChange();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_MOVE:
|
||||
if (sample)
|
||||
{
|
||||
|
@ -183,6 +188,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
break;
|
||||
|
||||
case WM_GETMINMAXINFO:
|
||||
if (lParam)
|
||||
{
|
||||
auto info = reinterpret_cast<MINMAXINFO*>(lParam);
|
||||
info->ptMinTrackSize.x = 320;
|
||||
|
@ -272,7 +278,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
else
|
||||
{
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, 0);
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP);
|
||||
SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST);
|
||||
|
||||
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
|
|
|
@ -779,6 +779,13 @@ void Sample::OnResuming()
|
|||
|
||||
void Sample::OnWindowMoved()
|
||||
{
|
||||
auto r = m_deviceResources->GetOutputSize();
|
||||
m_deviceResources->WindowSizeChanged(r.right, r.bottom);
|
||||
}
|
||||
|
||||
void Sample::OnDisplayChange()
|
||||
{
|
||||
m_deviceResources->UpdateColorSpace();
|
||||
}
|
||||
|
||||
void Sample::OnWindowSizeChanged(int width, int height)
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
void OnSuspending();
|
||||
void OnResuming();
|
||||
void OnWindowMoved();
|
||||
void OnDisplayChange();
|
||||
void OnWindowSizeChanged(int width, int height);
|
||||
|
||||
// Properties
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <WinSDKVer.h>
|
||||
#include <winsdkver.h>
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0601
|
||||
#include <SDKDDKVer.h>
|
||||
#endif
|
||||
#include <sdkddkver.h>
|
||||
|
||||
// Use the C++ standard templated min/max
|
||||
#define NOMINMAX
|
||||
|
@ -31,7 +33,7 @@
|
|||
#define NOHELP
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include <wrl/client.h>
|
||||
|
||||
|
@ -47,11 +49,14 @@
|
|||
#include <DirectXColors.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cwchar>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <system_error>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <dxgidebug.h>
|
||||
|
@ -97,4 +102,4 @@ namespace DX
|
|||
throw com_exception(hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ using namespace DX;
|
|||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
namespace
|
||||
{
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt)
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt) noexcept
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
|
@ -22,26 +24,38 @@ namespace
|
|||
default: return fmt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline long ComputeIntersectionArea(
|
||||
long ax1, long ay1, long ax2, long ay2,
|
||||
long bx1, long by1, long bx2, long by2) noexcept
|
||||
{
|
||||
return std::max(0l, std::min(ax2, bx2) - std::max(ax1, bx1)) * std::max(0l, std::min(ay2, by2) - std::max(ay1, by1));
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for DeviceResources.
|
||||
DeviceResources::DeviceResources(DXGI_FORMAT backBufferFormat, DXGI_FORMAT depthBufferFormat, UINT backBufferCount, D3D_FEATURE_LEVEL minFeatureLevel, unsigned int flags) :
|
||||
m_backBufferIndex(0),
|
||||
m_fenceValues{},
|
||||
m_rtvDescriptorSize(0),
|
||||
m_screenViewport{},
|
||||
m_scissorRect{},
|
||||
m_backBufferFormat(backBufferFormat),
|
||||
m_depthBufferFormat(depthBufferFormat),
|
||||
m_backBufferCount(backBufferCount),
|
||||
m_d3dMinFeatureLevel(minFeatureLevel),
|
||||
m_window(nullptr),
|
||||
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_11_0),
|
||||
m_dxgiFactoryFlags(0),
|
||||
m_outputSize{0, 0, 1, 1},
|
||||
m_colorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709),
|
||||
m_options(flags),
|
||||
m_deviceNotify(nullptr)
|
||||
DeviceResources::DeviceResources(
|
||||
DXGI_FORMAT backBufferFormat,
|
||||
DXGI_FORMAT depthBufferFormat,
|
||||
UINT backBufferCount,
|
||||
D3D_FEATURE_LEVEL minFeatureLevel,
|
||||
unsigned int flags) noexcept(false) :
|
||||
m_backBufferIndex(0),
|
||||
m_fenceValues{},
|
||||
m_rtvDescriptorSize(0),
|
||||
m_screenViewport{},
|
||||
m_scissorRect{},
|
||||
m_backBufferFormat(backBufferFormat),
|
||||
m_depthBufferFormat(depthBufferFormat),
|
||||
m_backBufferCount(backBufferCount),
|
||||
m_d3dMinFeatureLevel(minFeatureLevel),
|
||||
m_window(nullptr),
|
||||
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_11_0),
|
||||
m_dxgiFactoryFlags(0),
|
||||
m_outputSize{0, 0, 1, 1},
|
||||
m_colorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709),
|
||||
m_options(flags),
|
||||
m_deviceNotify(nullptr)
|
||||
{
|
||||
if (backBufferCount < 2 || backBufferCount > MAX_BACK_BUFFER_COUNT)
|
||||
{
|
||||
|
@ -62,7 +76,7 @@ DeviceResources::~DeviceResources()
|
|||
}
|
||||
|
||||
// Configures the Direct3D device, and stores handles to it and the device context.
|
||||
void DeviceResources::CreateDeviceResources()
|
||||
void DeviceResources::CreateDeviceResources()
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
||||
|
@ -86,6 +100,15 @@ void DeviceResources::CreateDeviceResources()
|
|||
|
||||
dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);
|
||||
dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);
|
||||
|
||||
DXGI_INFO_QUEUE_MESSAGE_ID hide[] =
|
||||
{
|
||||
80 /* IDXGISwapChain::GetContainingOutput: The swapchain's adapter does not control the output on which the swapchain's window resides. */,
|
||||
};
|
||||
DXGI_INFO_QUEUE_FILTER filter = {};
|
||||
filter.DenyList.NumIDs = _countof(hide);
|
||||
filter.DenyList.pIDList = hide;
|
||||
dxgiInfoQueue->AddStorageFilterEntries(DXGI_DEBUG_DXGI, &filter);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -117,11 +140,14 @@ void DeviceResources::CreateDeviceResources()
|
|||
GetAdapter(adapter.GetAddressOf());
|
||||
|
||||
// Create the DX12 API device object.
|
||||
ThrowIfFailed(D3D12CreateDevice(
|
||||
HRESULT hr = D3D12CreateDevice(
|
||||
adapter.Get(),
|
||||
m_d3dMinFeatureLevel,
|
||||
IID_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf())
|
||||
));
|
||||
);
|
||||
ThrowIfFailed(hr);
|
||||
|
||||
m_d3dDevice->SetName(L"DeviceResources");
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Configure debug device (if active).
|
||||
|
@ -150,6 +176,9 @@ void DeviceResources::CreateDeviceResources()
|
|||
// Determine maximum supported feature level for this device
|
||||
static const D3D_FEATURE_LEVEL s_featureLevels[] =
|
||||
{
|
||||
#if defined(NTDDI_WIN10_FE) || defined(USING_D3D12_AGILITY_SDK)
|
||||
D3D_FEATURE_LEVEL_12_2,
|
||||
#endif
|
||||
D3D_FEATURE_LEVEL_12_1,
|
||||
D3D_FEATURE_LEVEL_12_0,
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
|
@ -161,7 +190,7 @@ void DeviceResources::CreateDeviceResources()
|
|||
_countof(s_featureLevels), s_featureLevels, D3D_FEATURE_LEVEL_11_0
|
||||
};
|
||||
|
||||
HRESULT hr = m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &featLevels, sizeof(featLevels));
|
||||
hr = m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &featLevels, sizeof(featLevels));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_d3dFeatureLevel = featLevels.MaxSupportedFeatureLevel;
|
||||
|
@ -178,6 +207,8 @@ void DeviceResources::CreateDeviceResources()
|
|||
|
||||
ThrowIfFailed(m_d3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(m_commandQueue.ReleaseAndGetAddressOf())));
|
||||
|
||||
m_commandQueue->SetName(L"DeviceResources");
|
||||
|
||||
// Create descriptor heaps for render target views and depth stencil views.
|
||||
D3D12_DESCRIPTOR_HEAP_DESC rtvDescriptorHeapDesc = {};
|
||||
rtvDescriptorHeapDesc.NumDescriptors = m_backBufferCount;
|
||||
|
@ -204,12 +235,18 @@ void DeviceResources::CreateDeviceResources()
|
|||
for (UINT n = 0; n < m_backBufferCount; n++)
|
||||
{
|
||||
ThrowIfFailed(m_d3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(m_commandAllocators[n].ReleaseAndGetAddressOf())));
|
||||
|
||||
wchar_t name[25] = {};
|
||||
swprintf_s(name, L"Render target %u", n);
|
||||
m_commandAllocators[n]->SetName(name);
|
||||
}
|
||||
|
||||
// Create a command list for recording graphics commands.
|
||||
ThrowIfFailed(m_d3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[0].Get(), nullptr, IID_PPV_ARGS(m_commandList.ReleaseAndGetAddressOf())));
|
||||
ThrowIfFailed(m_commandList->Close());
|
||||
|
||||
m_commandList->SetName(L"DeviceResources");
|
||||
|
||||
// Create a fence for tracking GPU execution progress.
|
||||
ThrowIfFailed(m_d3dDevice->CreateFence(m_fenceValues[m_backBufferIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(m_fence.ReleaseAndGetAddressOf())));
|
||||
m_fenceValues[m_backBufferIndex]++;
|
||||
|
@ -224,7 +261,7 @@ void DeviceResources::CreateDeviceResources()
|
|||
}
|
||||
|
||||
// These resources need to be recreated every time the window size is changed.
|
||||
void DeviceResources::CreateWindowSizeDependentResources()
|
||||
void DeviceResources::CreateWindowSizeDependentResources()
|
||||
{
|
||||
if (!m_window)
|
||||
{
|
||||
|
@ -242,9 +279,9 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// Determine the render target size in pixels.
|
||||
UINT backBufferWidth = std::max<UINT>(m_outputSize.right - m_outputSize.left, 1);
|
||||
UINT backBufferHeight = std::max<UINT>(m_outputSize.bottom - m_outputSize.top, 1);
|
||||
DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);
|
||||
const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);
|
||||
const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);
|
||||
const DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);
|
||||
|
||||
// If the swap chain already exists, resize it, otherwise create one.
|
||||
if (m_swapChain)
|
||||
|
@ -262,13 +299,14 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
// If the device was removed for any reason, a new device and swap chain will need to be created.
|
||||
HandleDeviceLost();
|
||||
|
||||
// Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
|
||||
// Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
|
||||
// and correctly set up the new device.
|
||||
return;
|
||||
}
|
||||
|
@ -330,7 +368,9 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
rtvDesc.Format = m_backBufferFormat;
|
||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor(m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), n, m_rtvDescriptorSize);
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor(
|
||||
m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||
static_cast<INT>(n), m_rtvDescriptorSize);
|
||||
m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor);
|
||||
}
|
||||
|
||||
|
@ -383,12 +423,12 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
m_screenViewport.MaxDepth = D3D12_MAX_DEPTH;
|
||||
|
||||
m_scissorRect.left = m_scissorRect.top = 0;
|
||||
m_scissorRect.right = backBufferWidth;
|
||||
m_scissorRect.bottom = backBufferHeight;
|
||||
m_scissorRect.right = static_cast<LONG>(backBufferWidth);
|
||||
m_scissorRect.bottom = static_cast<LONG>(backBufferHeight);
|
||||
}
|
||||
|
||||
// This method is called when the Win32 window is created (or re-created).
|
||||
void DeviceResources::SetWindow(HWND window, int width, int height)
|
||||
void DeviceResources::SetWindow(HWND window, int width, int height) noexcept
|
||||
{
|
||||
m_window = window;
|
||||
|
||||
|
@ -464,16 +504,17 @@ void DeviceResources::HandleDeviceLost()
|
|||
}
|
||||
|
||||
// Prepare the command list and render target for rendering.
|
||||
void DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState)
|
||||
void DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState, D3D12_RESOURCE_STATES afterState)
|
||||
{
|
||||
// Reset command list and allocator.
|
||||
ThrowIfFailed(m_commandAllocators[m_backBufferIndex]->Reset());
|
||||
ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_backBufferIndex].Get(), nullptr));
|
||||
|
||||
if (beforeState != D3D12_RESOURCE_STATE_RENDER_TARGET)
|
||||
if (beforeState != afterState)
|
||||
{
|
||||
// Transition the render target into the correct state to allow for drawing into it.
|
||||
D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(), beforeState, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(),
|
||||
beforeState, afterState);
|
||||
m_commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +553,8 @@ void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
HandleDeviceLost();
|
||||
|
@ -525,8 +567,7 @@ void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)
|
|||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
|
||||
UpdateColorSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -580,26 +621,69 @@ void DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter)
|
|||
*ppAdapter = nullptr;
|
||||
|
||||
ComPtr<IDXGIAdapter1> adapter;
|
||||
for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != m_dxgiFactory->EnumAdapters1(adapterIndex, adapter.ReleaseAndGetAddressOf()); ++adapterIndex)
|
||||
|
||||
#if defined(__dxgi1_6_h__) && defined(NTDDI_WIN10_RS4)
|
||||
ComPtr<IDXGIFactory6> factory6;
|
||||
HRESULT hr = m_dxgiFactory.As(&factory6);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
ThrowIfFailed(adapter->GetDesc1(&desc));
|
||||
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(factory6->EnumAdapterByGpuPreference(
|
||||
adapterIndex,
|
||||
DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
|
||||
IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf())));
|
||||
adapterIndex++)
|
||||
{
|
||||
// Don't select the Basic Render Driver adapter.
|
||||
continue;
|
||||
}
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
ThrowIfFailed(adapter->GetDesc1(&desc));
|
||||
|
||||
// Check to see if the adapter supports Direct3D 12, but don't create the actual device yet.
|
||||
if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), m_d3dMinFeatureLevel, _uuidof(ID3D12Device), nullptr)))
|
||||
{
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
|
||||
{
|
||||
// Don't select the Basic Render Driver adapter.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if the adapter supports Direct3D 12, but don't create the actual device yet.
|
||||
if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), m_d3dMinFeatureLevel, _uuidof(ID3D12Device), nullptr)))
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
wchar_t buff[256] = {};
|
||||
swprintf_s(buff, L"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\n", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);
|
||||
OutputDebugStringW(buff);
|
||||
wchar_t buff[256] = {};
|
||||
swprintf_s(buff, L"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\n", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);
|
||||
OutputDebugStringW(buff);
|
||||
#endif
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!adapter)
|
||||
{
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(m_dxgiFactory->EnumAdapters1(
|
||||
adapterIndex,
|
||||
adapter.ReleaseAndGetAddressOf()));
|
||||
++adapterIndex)
|
||||
{
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
ThrowIfFailed(adapter->GetDesc1(&desc));
|
||||
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
|
||||
{
|
||||
// Don't select the Basic Render Driver adapter.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if the adapter supports Direct3D 12, but don't create the actual device yet.
|
||||
if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), m_d3dMinFeatureLevel, _uuidof(ID3D12Device), nullptr)))
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
wchar_t buff[256] = {};
|
||||
swprintf_s(buff, L"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\n", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);
|
||||
OutputDebugStringW(buff);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -627,6 +711,15 @@ void DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter)
|
|||
// Sets the color space for the swap chain in order to handle HDR output.
|
||||
void DeviceResources::UpdateColorSpace()
|
||||
{
|
||||
if (!m_dxgiFactory)
|
||||
return;
|
||||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
|
||||
}
|
||||
|
||||
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
bool isDisplayHDR10 = false;
|
||||
|
@ -634,11 +727,52 @@ void DeviceResources::UpdateColorSpace()
|
|||
#if defined(NTDDI_WIN10_RS2)
|
||||
if (m_swapChain)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
if (SUCCEEDED(m_swapChain->GetContainingOutput(output.GetAddressOf())))
|
||||
// To detect HDR support, we will need to check the color space in the primary
|
||||
// DXGI output associated with the app at this point in time
|
||||
// (using window/display intersection).
|
||||
|
||||
// Get the retangle bounds of the app window.
|
||||
RECT windowBounds;
|
||||
if (!GetWindowRect(m_window, &windowBounds))
|
||||
throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), "GetWindowRect");
|
||||
|
||||
const long ax1 = windowBounds.left;
|
||||
const long ay1 = windowBounds.top;
|
||||
const long ax2 = windowBounds.right;
|
||||
const long ay2 = windowBounds.bottom;
|
||||
|
||||
ComPtr<IDXGIOutput> bestOutput;
|
||||
long bestIntersectArea = -1;
|
||||
|
||||
ComPtr<IDXGIAdapter> adapter;
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(m_dxgiFactory->EnumAdapters(adapterIndex, adapter.ReleaseAndGetAddressOf()));
|
||||
++adapterIndex)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
for (UINT outputIndex = 0;
|
||||
SUCCEEDED(adapter->EnumOutputs(outputIndex, output.ReleaseAndGetAddressOf()));
|
||||
++outputIndex)
|
||||
{
|
||||
// Get the rectangle bounds of current output.
|
||||
DXGI_OUTPUT_DESC desc;
|
||||
ThrowIfFailed(output->GetDesc(&desc));
|
||||
const auto& r = desc.DesktopCoordinates;
|
||||
|
||||
// Compute the intersection
|
||||
const long intersectArea = ComputeIntersectionArea(ax1, ay1, ax2, ay2, r.left, r.top, r.right, r.bottom);
|
||||
if (intersectArea > bestIntersectArea)
|
||||
{
|
||||
bestOutput.Swap(output);
|
||||
bestIntersectArea = intersectArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestOutput)
|
||||
{
|
||||
ComPtr<IDXGIOutput6> output6;
|
||||
if (SUCCEEDED(output.As(&output6)))
|
||||
if (SUCCEEDED(bestOutput.As(&output6)))
|
||||
{
|
||||
DXGI_OUTPUT_DESC1 desc;
|
||||
ThrowIfFailed(output6->GetDesc1(&desc));
|
||||
|
@ -674,14 +808,11 @@ void DeviceResources::UpdateColorSpace()
|
|||
|
||||
m_colorSpace = colorSpace;
|
||||
|
||||
ComPtr<IDXGISwapChain3> swapChain3;
|
||||
if (SUCCEEDED(m_swapChain.As(&swapChain3)))
|
||||
UINT colorSpaceSupport = 0;
|
||||
if (m_swapChain
|
||||
&& SUCCEEDED(m_swapChain->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
&& (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
|
||||
{
|
||||
UINT colorSpaceSupport = 0;
|
||||
if (SUCCEEDED(swapChain3->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
&& (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
|
||||
{
|
||||
ThrowIfFailed(swapChain3->SetColorSpace1(colorSpace));
|
||||
}
|
||||
ThrowIfFailed(m_swapChain->SetColorSpace1(colorSpace));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// DeviceResources.h - A wrapper for the Direct3D 12 device and swapchain
|
||||
//
|
||||
|
||||
|
@ -20,52 +20,64 @@ namespace DX
|
|||
class DeviceResources
|
||||
{
|
||||
public:
|
||||
static const unsigned int c_AllowTearing = 0x1;
|
||||
static const unsigned int c_EnableHDR = 0x2;
|
||||
static constexpr unsigned int c_AllowTearing = 0x1;
|
||||
static constexpr unsigned int c_EnableHDR = 0x2;
|
||||
|
||||
DeviceResources(DXGI_FORMAT backBufferFormat = DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
DXGI_FORMAT depthBufferFormat = DXGI_FORMAT_D32_FLOAT,
|
||||
UINT backBufferCount = 2,
|
||||
D3D_FEATURE_LEVEL minFeatureLevel = D3D_FEATURE_LEVEL_11_0,
|
||||
unsigned int flags = 0);
|
||||
unsigned int flags = 0) noexcept(false);
|
||||
~DeviceResources();
|
||||
|
||||
DeviceResources(DeviceResources&&) = default;
|
||||
DeviceResources& operator= (DeviceResources&&) = default;
|
||||
|
||||
DeviceResources(DeviceResources const&) = delete;
|
||||
DeviceResources& operator= (DeviceResources const&) = delete;
|
||||
|
||||
void CreateDeviceResources();
|
||||
void CreateWindowSizeDependentResources();
|
||||
void SetWindow(HWND window, int width, int height);
|
||||
void SetWindow(HWND window, int width, int height) noexcept;
|
||||
bool WindowSizeChanged(int width, int height);
|
||||
void HandleDeviceLost();
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) { m_deviceNotify = deviceNotify; }
|
||||
void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT);
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) noexcept { m_deviceNotify = deviceNotify; }
|
||||
void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT,
|
||||
D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
void Present(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
void WaitForGpu() noexcept;
|
||||
void UpdateColorSpace();
|
||||
|
||||
// Device Accessors.
|
||||
RECT GetOutputSize() const { return m_outputSize; }
|
||||
RECT GetOutputSize() const noexcept { return m_outputSize; }
|
||||
|
||||
// Direct3D Accessors.
|
||||
ID3D12Device* GetD3DDevice() const { return m_d3dDevice.Get(); }
|
||||
IDXGISwapChain3* GetSwapChain() const { return m_swapChain.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; }
|
||||
ID3D12Resource* GetRenderTarget() const { return m_renderTargets[m_backBufferIndex].Get(); }
|
||||
ID3D12Resource* GetDepthStencil() const { return m_depthStencil.Get(); }
|
||||
ID3D12CommandQueue* GetCommandQueue() const { return m_commandQueue.Get(); }
|
||||
ID3D12CommandAllocator* GetCommandAllocator() const { return m_commandAllocators[m_backBufferIndex].Get(); }
|
||||
ID3D12GraphicsCommandList* GetCommandList() const { return m_commandList.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const { return m_depthBufferFormat; }
|
||||
D3D12_VIEWPORT GetScreenViewport() const { return m_screenViewport; }
|
||||
D3D12_RECT GetScissorRect() const { return m_scissorRect; }
|
||||
UINT GetCurrentFrameIndex() const { return m_backBufferIndex; }
|
||||
UINT GetBackBufferCount() const { return m_backBufferCount; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const { return m_options; }
|
||||
auto GetD3DDevice() const noexcept { return m_d3dDevice.Get(); }
|
||||
auto GetSwapChain() const noexcept { return m_swapChain.Get(); }
|
||||
auto GetDXGIFactory() const noexcept { return m_dxgiFactory.Get(); }
|
||||
HWND GetWindow() const noexcept { return m_window; }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const noexcept { return m_d3dFeatureLevel; }
|
||||
ID3D12Resource* GetRenderTarget() const noexcept { return m_renderTargets[m_backBufferIndex].Get(); }
|
||||
ID3D12Resource* GetDepthStencil() const noexcept { return m_depthStencil.Get(); }
|
||||
ID3D12CommandQueue* GetCommandQueue() const noexcept { return m_commandQueue.Get(); }
|
||||
ID3D12CommandAllocator* GetCommandAllocator() const noexcept { return m_commandAllocators[m_backBufferIndex].Get(); }
|
||||
auto GetCommandList() const noexcept { return m_commandList.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const noexcept { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const noexcept { return m_depthBufferFormat; }
|
||||
D3D12_VIEWPORT GetScreenViewport() const noexcept { return m_screenViewport; }
|
||||
D3D12_RECT GetScissorRect() const noexcept { return m_scissorRect; }
|
||||
UINT GetCurrentFrameIndex() const noexcept { return m_backBufferIndex; }
|
||||
UINT GetBackBufferCount() const noexcept { return m_backBufferCount; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const noexcept { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const noexcept { return m_options; }
|
||||
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const noexcept
|
||||
{
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), m_backBufferIndex, m_rtvDescriptorSize);
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(
|
||||
m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||
static_cast<INT>(m_backBufferIndex), m_rtvDescriptorSize);
|
||||
}
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const noexcept
|
||||
{
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
|
@ -73,16 +85,15 @@ namespace DX
|
|||
private:
|
||||
void MoveToNextFrame();
|
||||
void GetAdapter(IDXGIAdapter1** ppAdapter);
|
||||
void UpdateColorSpace();
|
||||
|
||||
static const size_t MAX_BACK_BUFFER_COUNT = 3;
|
||||
static constexpr size_t MAX_BACK_BUFFER_COUNT = 3;
|
||||
|
||||
UINT m_backBufferIndex;
|
||||
|
||||
// Direct3D objects.
|
||||
Microsoft::WRL::ComPtr<ID3D12Device> m_d3dDevice;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> m_commandList;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_commandAllocators[MAX_BACK_BUFFER_COUNT];
|
||||
|
||||
// Swap chain objects.
|
||||
|
|
|
@ -12,21 +12,17 @@
|
|||
|
||||
using namespace DirectX;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unique_ptr<Sample> g_sample;
|
||||
};
|
||||
}
|
||||
|
||||
LPCWSTR g_szAppName = L"SimpleHDR_PC12";
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
// Indicates to hybrid graphics systems to prefer the discrete part by default
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
}
|
||||
void ExitGame() noexcept;
|
||||
|
||||
// Entry point
|
||||
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
|
||||
|
@ -46,17 +42,14 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
|||
// Register class and create window
|
||||
{
|
||||
// Register class
|
||||
WNDCLASSEXW wcex;
|
||||
WNDCLASSEXW wcex = {};
|
||||
wcex.cbSize = sizeof(WNDCLASSEXW);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInstance;
|
||||
wcex.hIcon = LoadIconW(hInstance, L"IDI_ICON");
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
||||
wcex.lpszMenuName = nullptr;
|
||||
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
|
||||
wcex.lpszClassName = L"SimpleHDR_PC12WindowClass";
|
||||
wcex.hIconSm = LoadIconW(wcex.hInstance, L"IDI_ICON");
|
||||
if (!RegisterClassExW(&wcex))
|
||||
|
@ -79,7 +72,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
|||
|
||||
ShowWindow(hwnd, nCmdShow);
|
||||
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_sample.get()) );
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_sample.get()));
|
||||
|
||||
GetClientRect(hwnd, &rc);
|
||||
|
||||
|
@ -105,15 +98,12 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
|||
|
||||
CoUninitialize();
|
||||
|
||||
return (int) msg.wParam;
|
||||
return static_cast<int>(msg.wParam);
|
||||
}
|
||||
|
||||
// Windows procedure
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc;
|
||||
|
||||
static bool s_in_sizemove = false;
|
||||
static bool s_in_suspend = false;
|
||||
static bool s_minimized = false;
|
||||
|
@ -131,11 +121,19 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
else
|
||||
{
|
||||
hdc = BeginPaint(hWnd, &ps);
|
||||
PAINTSTRUCT ps;
|
||||
(void)BeginPaint(hWnd, &ps);
|
||||
EndPaint(hWnd, &ps);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DISPLAYCHANGE:
|
||||
if (sample)
|
||||
{
|
||||
sample->OnDisplayChange();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_MOVE:
|
||||
if (sample)
|
||||
{
|
||||
|
@ -183,6 +181,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
break;
|
||||
|
||||
case WM_GETMINMAXINFO:
|
||||
if (lParam)
|
||||
{
|
||||
auto info = reinterpret_cast<MINMAXINFO*>(lParam);
|
||||
info->ptMinTrackSize.x = 320;
|
||||
|
@ -272,7 +271,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
else
|
||||
{
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, 0);
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP);
|
||||
SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST);
|
||||
|
||||
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
|
|
|
@ -779,6 +779,13 @@ void Sample::OnResuming()
|
|||
|
||||
void Sample::OnWindowMoved()
|
||||
{
|
||||
auto r = m_deviceResources->GetOutputSize();
|
||||
m_deviceResources->WindowSizeChanged(r.right, r.bottom);
|
||||
}
|
||||
|
||||
void Sample::OnDisplayChange()
|
||||
{
|
||||
m_deviceResources->UpdateColorSpace();
|
||||
}
|
||||
|
||||
void Sample::OnWindowSizeChanged(int width, int height)
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
void OnSuspending();
|
||||
void OnResuming();
|
||||
void OnWindowMoved();
|
||||
void OnDisplayChange();
|
||||
void OnWindowSizeChanged(int width, int height);
|
||||
|
||||
// Properties
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <WinSDKVer.h>
|
||||
#include <winsdkver.h>
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#include <SDKDDKVer.h>
|
||||
#endif
|
||||
#include <sdkddkver.h>
|
||||
|
||||
// Use the C++ standard templated min/max
|
||||
#define NOMINMAX
|
||||
|
@ -31,7 +33,7 @@
|
|||
#define NOHELP
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include <wrl/client.h>
|
||||
#include <wrl/event.h>
|
||||
|
@ -50,18 +52,23 @@
|
|||
#include "d3dx12.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <dxgidebug.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// To use graphics and CPU markup events with the latest version of PIX, change this to include <pix3.h>
|
||||
// then add the NuGet package WinPixEventRuntime to the project.
|
||||
// To use graphics and CPU markup events with the latest version of PIX, change this to include <pix3.h>
|
||||
// then add the NuGet package WinPixEventRuntime to the project.
|
||||
#include <pix.h>
|
||||
|
||||
#include "CommonStates.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// DeviceResources.cpp - A wrapper for the Direct3D 11 device and swapchain
|
||||
// (requires DirectX 11.3 Runtime)
|
||||
//
|
||||
|
@ -12,11 +12,15 @@ using namespace DX;
|
|||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
extern void GetWindowBounds(_In_ IUnknown* window, _Out_ RECT* rect);
|
||||
|
||||
namespace
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
// Check for SDK Layer support.
|
||||
inline bool SdkLayersAvailable()
|
||||
inline bool SdkLayersAvailable() noexcept
|
||||
{
|
||||
HRESULT hr = D3D11CreateDevice(
|
||||
nullptr,
|
||||
|
@ -35,7 +39,7 @@ namespace
|
|||
}
|
||||
#endif
|
||||
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt)
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt) noexcept
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
|
@ -45,7 +49,14 @@ namespace
|
|||
default: return fmt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline long ComputeIntersectionArea(
|
||||
long ax1, long ay1, long ax2, long ay2,
|
||||
long bx1, long by1, long bx2, long by2) noexcept
|
||||
{
|
||||
return std::max(0l, std::min(ax2, bx2) - std::max(ax1, bx1)) * std::max(0l, std::min(ay2, by2) - std::max(ay1, by1));
|
||||
}
|
||||
}
|
||||
|
||||
// Constants used to calculate screen rotations
|
||||
namespace ScreenRotation
|
||||
|
@ -81,7 +92,7 @@ namespace ScreenRotation
|
|||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// Constructor for DeviceResources.
|
||||
DeviceResources::DeviceResources(
|
||||
|
@ -287,8 +298,7 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// Clear the previous window size specific context.
|
||||
ID3D11RenderTargetView* nullViews[] = {nullptr};
|
||||
m_d3dContext->OMSetRenderTargets(_countof(nullViews), nullViews, nullptr);
|
||||
m_d3dContext->OMSetRenderTargets(0, nullptr, nullptr);
|
||||
m_d3dRenderTargetView.Reset();
|
||||
m_d3dDepthStencilView.Reset();
|
||||
m_renderTarget.Reset();
|
||||
|
@ -296,9 +306,9 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
m_d3dContext->Flush();
|
||||
|
||||
// Determine the render target size in pixels.
|
||||
UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);
|
||||
UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);
|
||||
DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);
|
||||
const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);
|
||||
const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);
|
||||
const DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);
|
||||
|
||||
if (m_swapChain)
|
||||
{
|
||||
|
@ -315,7 +325,8 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
// If the device was removed for any reason, a new device and swap chain will need to be created.
|
||||
|
@ -438,7 +449,7 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// This method is called when the CoreWindow is created (or re-created).
|
||||
void DeviceResources::SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation)
|
||||
void DeviceResources::SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation) noexcept
|
||||
{
|
||||
m_window = window;
|
||||
|
||||
|
@ -549,7 +560,7 @@ void DeviceResources::HandleDeviceLost()
|
|||
|
||||
// Call this method when the app suspends. It provides a hint to the driver that the app
|
||||
// is entering an idle state and that temporary buffers can be reclaimed for use by other apps.
|
||||
void DeviceResources::Trim()
|
||||
void DeviceResources::Trim() noexcept
|
||||
{
|
||||
ComPtr<IDXGIDevice3> dxgiDevice;
|
||||
if (SUCCEEDED(m_d3dDevice.As(&dxgiDevice)))
|
||||
|
@ -561,7 +572,7 @@ void DeviceResources::Trim()
|
|||
// Present the contents of the swap chain to the screen.
|
||||
void DeviceResources::Present()
|
||||
{
|
||||
HRESULT hr;
|
||||
HRESULT hr = E_FAIL;
|
||||
if (m_options & c_AllowTearing)
|
||||
{
|
||||
// Recommended to always use tearing if supported when using a sync interval of 0.
|
||||
|
@ -592,7 +603,8 @@ void DeviceResources::Present()
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
HandleDeviceLost();
|
||||
|
@ -603,8 +615,7 @@ void DeviceResources::Present()
|
|||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
|
||||
UpdateColorSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -648,6 +659,7 @@ void DeviceResources::GetHardwareAdapter(IDXGIAdapter1** ppAdapter)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!adapter)
|
||||
{
|
||||
for (UINT adapterIndex = 0;
|
||||
|
@ -681,6 +693,15 @@ void DeviceResources::GetHardwareAdapter(IDXGIAdapter1** ppAdapter)
|
|||
// Sets the color space for the swap chain in order to handle HDR output.
|
||||
void DeviceResources::UpdateColorSpace()
|
||||
{
|
||||
if (!m_dxgiFactory)
|
||||
return;
|
||||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
|
||||
}
|
||||
|
||||
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
bool isDisplayHDR10 = false;
|
||||
|
@ -688,11 +709,51 @@ void DeviceResources::UpdateColorSpace()
|
|||
#if defined(NTDDI_WIN10_RS2)
|
||||
if (m_swapChain)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
if (SUCCEEDED(m_swapChain->GetContainingOutput(output.GetAddressOf())))
|
||||
// To detect HDR support, we will need to check the color space in the primary
|
||||
// DXGI output associated with the app at this point in time
|
||||
// (using window/display intersection).
|
||||
|
||||
// Get the retangle bounds of the app window.
|
||||
RECT windowBounds;
|
||||
GetWindowBounds(m_window, &windowBounds);
|
||||
|
||||
const long ax1 = windowBounds.left;
|
||||
const long ay1 = windowBounds.top;
|
||||
const long ax2 = windowBounds.right;
|
||||
const long ay2 = windowBounds.bottom;
|
||||
|
||||
ComPtr<IDXGIOutput> bestOutput;
|
||||
long bestIntersectArea = -1;
|
||||
|
||||
ComPtr<IDXGIAdapter> adapter;
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(m_dxgiFactory->EnumAdapters(adapterIndex, adapter.ReleaseAndGetAddressOf()));
|
||||
++adapterIndex)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
for (UINT outputIndex = 0;
|
||||
SUCCEEDED(adapter->EnumOutputs(outputIndex, output.ReleaseAndGetAddressOf()));
|
||||
++outputIndex)
|
||||
{
|
||||
// Get the rectangle bounds of current output.
|
||||
DXGI_OUTPUT_DESC desc;
|
||||
ThrowIfFailed(output->GetDesc(&desc));
|
||||
const auto& r = desc.DesktopCoordinates;
|
||||
|
||||
// Compute the intersection
|
||||
const long intersectArea = ComputeIntersectionArea(ax1, ay1, ax2, ay2, r.left, r.top, r.right, r.bottom);
|
||||
if (intersectArea > bestIntersectArea)
|
||||
{
|
||||
bestOutput.Swap(output);
|
||||
bestIntersectArea = intersectArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestOutput)
|
||||
{
|
||||
ComPtr<IDXGIOutput6> output6;
|
||||
if (SUCCEEDED(output.As(&output6)))
|
||||
if (SUCCEEDED(bestOutput.As(&output6)))
|
||||
{
|
||||
DXGI_OUTPUT_DESC1 desc;
|
||||
ThrowIfFailed(output6->GetDesc1(&desc));
|
||||
|
@ -729,7 +790,8 @@ void DeviceResources::UpdateColorSpace()
|
|||
m_colorSpace = colorSpace;
|
||||
|
||||
UINT colorSpaceSupport = 0;
|
||||
if (SUCCEEDED(m_swapChain->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
if (m_swapChain
|
||||
&& SUCCEEDED(m_swapChain->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
&& (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
|
||||
{
|
||||
ThrowIfFailed(m_swapChain->SetColorSpace1(colorSpace));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// DeviceResources.h - A wrapper for the Direct3D 11 device and swapchain
|
||||
//
|
||||
|
||||
|
@ -28,41 +28,49 @@ namespace DX
|
|||
UINT backBufferCount = 2,
|
||||
D3D_FEATURE_LEVEL minFeatureLevel = D3D_FEATURE_LEVEL_9_3,
|
||||
unsigned int flags = 0) noexcept;
|
||||
~DeviceResources() = default;
|
||||
|
||||
DeviceResources(DeviceResources&&) = default;
|
||||
DeviceResources& operator= (DeviceResources&&) = default;
|
||||
|
||||
DeviceResources(DeviceResources const&) = delete;
|
||||
DeviceResources& operator= (DeviceResources const&) = delete;
|
||||
|
||||
void CreateDeviceResources();
|
||||
void CreateWindowSizeDependentResources();
|
||||
void SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation) noexcept;
|
||||
bool WindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void ValidateDevice();
|
||||
void HandleDeviceLost();
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) { m_deviceNotify = deviceNotify; }
|
||||
void Trim();
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) noexcept { m_deviceNotify = deviceNotify; }
|
||||
void Trim() noexcept;
|
||||
void Present();
|
||||
void UpdateColorSpace();
|
||||
|
||||
// Device Accessors.
|
||||
RECT GetOutputSize() const { return m_outputSize; }
|
||||
DXGI_MODE_ROTATION GetRotation() const { return m_rotation; }
|
||||
RECT GetOutputSize() const noexcept { return m_outputSize; }
|
||||
DXGI_MODE_ROTATION GetRotation() const noexcept { return m_rotation; }
|
||||
|
||||
// Direct3D Accessors.
|
||||
ID3D11Device3* GetD3DDevice() const { return m_d3dDevice.Get(); }
|
||||
ID3D11DeviceContext2* GetD3DDeviceContext() const { return m_d3dContext.Get(); }
|
||||
IDXGISwapChain3* GetSwapChain() const { return m_swapChain.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; }
|
||||
ID3D11Texture2D* GetRenderTarget() const { return m_renderTarget.Get(); }
|
||||
ID3D11Texture2D* GetDepthStencil() const { return m_depthStencil.Get(); }
|
||||
ID3D11RenderTargetView* GetRenderTargetView() const { return m_d3dRenderTargetView.Get(); }
|
||||
ID3D11DepthStencilView* GetDepthStencilView() const { return m_d3dDepthStencilView.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const { return m_depthBufferFormat; }
|
||||
D3D11_VIEWPORT GetScreenViewport() const { return m_screenViewport; }
|
||||
UINT GetBackBufferCount() const { return m_backBufferCount; }
|
||||
DirectX::XMFLOAT4X4 GetOrientationTransform3D() const { return m_orientationTransform3D; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const { return m_options; }
|
||||
auto GetD3DDevice() const noexcept { return m_d3dDevice.Get(); }
|
||||
auto GetD3DDeviceContext() const noexcept { return m_d3dContext.Get(); }
|
||||
auto GetSwapChain() const noexcept { return m_swapChain.Get(); }
|
||||
auto GetDXGIFactory() const noexcept { return m_dxgiFactory.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const noexcept { return m_d3dFeatureLevel; }
|
||||
ID3D11Texture2D* GetRenderTarget() const noexcept { return m_renderTarget.Get(); }
|
||||
ID3D11Texture2D* GetDepthStencil() const noexcept { return m_depthStencil.Get(); }
|
||||
ID3D11RenderTargetView* GetRenderTargetView() const noexcept { return m_d3dRenderTargetView.Get(); }
|
||||
ID3D11DepthStencilView* GetDepthStencilView() const noexcept { return m_d3dDepthStencilView.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const noexcept { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const noexcept { return m_depthBufferFormat; }
|
||||
D3D11_VIEWPORT GetScreenViewport() const noexcept { return m_screenViewport; }
|
||||
UINT GetBackBufferCount() const noexcept { return m_backBufferCount; }
|
||||
DirectX::XMFLOAT4X4 GetOrientationTransform3D() const noexcept { return m_orientationTransform3D; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const noexcept { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const noexcept { return m_options; }
|
||||
|
||||
private:
|
||||
void GetHardwareAdapter(IDXGIAdapter1** ppAdapter);
|
||||
void UpdateColorSpace();
|
||||
|
||||
// Direct3D objects.
|
||||
Microsoft::WRL::ComPtr<IDXGIFactory2> m_dxgiFactory;
|
||||
|
@ -102,4 +110,4 @@ namespace DX
|
|||
// The IDeviceNotify can be held directly as it owns the DeviceResources.
|
||||
IDeviceNotify* m_deviceNotify;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,24 @@ using namespace Windows::Foundation;
|
|||
using namespace Windows::Graphics::Display;
|
||||
using namespace DirectX;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
void ExitGame() noexcept;
|
||||
void GetWindowBounds(_In_ IUnknown* window, _Out_ RECT* rect);
|
||||
|
||||
namespace
|
||||
{
|
||||
inline int ConvertDipsToPixels(float dips, float dpi) noexcept
|
||||
{
|
||||
return int(dips * dpi / 96.f + 0.5f);
|
||||
}
|
||||
|
||||
inline float ConvertPixelsToDips(int pixels, float dpi) noexcept
|
||||
{
|
||||
return (float(pixels) * 96.f / dpi);
|
||||
}
|
||||
}
|
||||
|
||||
ref class ViewProvider sealed : public IFrameworkView
|
||||
{
|
||||
public:
|
||||
|
@ -135,8 +153,8 @@ public:
|
|||
m_nativeOrientation = currentDisplayInformation->NativeOrientation;
|
||||
m_currentOrientation = currentDisplayInformation->CurrentOrientation;
|
||||
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight);
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth, m_DPI);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight, m_DPI);
|
||||
|
||||
DXGI_MODE_ROTATION rotation = ComputeDisplayRotation();
|
||||
|
||||
|
@ -196,13 +214,13 @@ protected:
|
|||
ApplicationView::PreferredLaunchWindowingMode = ApplicationViewWindowingMode::PreferredLaunchViewSize;
|
||||
// Change to ApplicationViewWindowingMode::FullScreen to default to full screen
|
||||
|
||||
auto desiredSize = Size(ConvertPixelsToDips(w), ConvertPixelsToDips(h));
|
||||
auto desiredSize = Size(ConvertPixelsToDips(w, m_DPI), ConvertPixelsToDips(h, m_DPI));
|
||||
|
||||
ApplicationView::PreferredLaunchViewSize = desiredSize;
|
||||
|
||||
auto view = ApplicationView::GetForCurrentView();
|
||||
|
||||
auto minSize = Size(ConvertPixelsToDips(320), ConvertPixelsToDips(200));
|
||||
auto minSize = Size(ConvertPixelsToDips(320, m_DPI), ConvertPixelsToDips(200, m_DPI));
|
||||
|
||||
view->SetPreferredMinSize(minSize);
|
||||
|
||||
|
@ -319,6 +337,7 @@ protected:
|
|||
void OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args)
|
||||
{
|
||||
m_sample->ValidateDevice();
|
||||
m_sample->OnDisplayChange();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -333,17 +352,7 @@ private:
|
|||
Windows::Graphics::Display::DisplayOrientations m_nativeOrientation;
|
||||
Windows::Graphics::Display::DisplayOrientations m_currentOrientation;
|
||||
|
||||
inline int ConvertDipsToPixels(float dips) const
|
||||
{
|
||||
return int(dips * m_DPI / 96.f + 0.5f);
|
||||
}
|
||||
|
||||
inline float ConvertPixelsToDips(int pixels) const
|
||||
{
|
||||
return (float(pixels) * 96.f / m_DPI);
|
||||
}
|
||||
|
||||
DXGI_MODE_ROTATION ComputeDisplayRotation() const
|
||||
DXGI_MODE_ROTATION ComputeDisplayRotation() const noexcept
|
||||
{
|
||||
DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
|
||||
|
||||
|
@ -367,6 +376,9 @@ private:
|
|||
case DisplayOrientations::PortraitFlipped:
|
||||
rotation = DXGI_MODE_ROTATION_ROTATE90;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -388,8 +400,14 @@ private:
|
|||
case DisplayOrientations::PortraitFlipped:
|
||||
rotation = DXGI_MODE_ROTATION_ROTATE180;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rotation;
|
||||
|
@ -397,8 +415,8 @@ private:
|
|||
|
||||
void HandleWindowSizeChanged()
|
||||
{
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight);
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth, m_DPI);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight, m_DPI);
|
||||
|
||||
DXGI_MODE_ROTATION rotation = ComputeDisplayRotation();
|
||||
|
||||
|
@ -441,3 +459,32 @@ void ExitSample() noexcept
|
|||
{
|
||||
Windows::ApplicationModel::Core::CoreApplication::Exit();
|
||||
}
|
||||
|
||||
|
||||
// Window size helper
|
||||
_Use_decl_annotations_
|
||||
void GetWindowBounds(IUnknown* window, RECT* rect)
|
||||
{
|
||||
if (!rect)
|
||||
return;
|
||||
|
||||
*rect = {};
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
auto b = reinterpret_cast<CoreWindow^>(window)->Bounds;
|
||||
|
||||
auto currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||
float dpi = currentDisplayInformation->LogicalDpi;
|
||||
|
||||
const int x = ConvertDipsToPixels(b.X, dpi);
|
||||
const int y = ConvertDipsToPixels(b.Y, dpi);
|
||||
const int w = ConvertDipsToPixels(b.Width, dpi);
|
||||
const int h = ConvertDipsToPixels(b.Height, dpi);
|
||||
|
||||
rect->left = static_cast<long>(x);
|
||||
rect->top = static_cast<long>(y);
|
||||
rect->right = static_cast<long>(x + w);
|
||||
rect->bottom = static_cast<long>(y + h);
|
||||
}
|
|
@ -790,6 +790,11 @@ void Sample::OnResuming()
|
|||
m_keyboardButtons.Reset();
|
||||
}
|
||||
|
||||
void Sample::OnDisplayChange()
|
||||
{
|
||||
m_deviceResources->UpdateColorSpace();
|
||||
}
|
||||
|
||||
void Sample::OnWindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation)
|
||||
{
|
||||
if (!m_deviceResources->WindowSizeChanged(width, height, rotation))
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
void OnDeactivated();
|
||||
void OnSuspending();
|
||||
void OnResuming();
|
||||
void OnDisplayChange();
|
||||
void OnWindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void ValidateDevice();
|
||||
|
||||
|
@ -57,7 +58,7 @@ private:
|
|||
|
||||
void CreateDeviceDependentResources();
|
||||
void CreateWindowSizeDependentResources();
|
||||
|
||||
|
||||
// Device resources.
|
||||
std::unique_ptr<DX::DeviceResources> m_deviceResources;
|
||||
|
||||
|
|
|
@ -29,11 +29,15 @@
|
|||
#include <DirectXColors.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cwchar>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pix.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
|
|
@ -10,6 +10,10 @@ using namespace DX;
|
|||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
extern void GetWindowBounds(_In_ IUnknown* window, _Out_ RECT* rect);
|
||||
|
||||
// Constants used to calculate screen rotations
|
||||
namespace ScreenRotation
|
||||
{
|
||||
|
@ -44,11 +48,11 @@ namespace ScreenRotation
|
|||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt)
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt) noexcept
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
|
@ -58,7 +62,14 @@ namespace
|
|||
default: return fmt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline long ComputeIntersectionArea(
|
||||
long ax1, long ay1, long ax2, long ay2,
|
||||
long bx1, long by1, long bx2, long by2) noexcept
|
||||
{
|
||||
return std::max(0l, std::min(ax2, bx2) - std::max(ax1, bx1)) * std::max(0l, std::min(ay2, by2) - std::max(ay1, by1));
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for DeviceResources.
|
||||
DeviceResources::DeviceResources(
|
||||
|
@ -204,6 +215,9 @@ void DeviceResources::CreateDeviceResources()
|
|||
// Determine maximum supported feature level for this device
|
||||
static const D3D_FEATURE_LEVEL s_featureLevels[] =
|
||||
{
|
||||
#if defined(NTDDI_WIN10_FE) && (NTDDI_VERSION >= NTDDI_WIN10_FE)
|
||||
D3D_FEATURE_LEVEL_12_2,
|
||||
#endif
|
||||
D3D_FEATURE_LEVEL_12_1,
|
||||
D3D_FEATURE_LEVEL_12_0,
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
|
@ -304,9 +318,9 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// Determine the render target size in pixels.
|
||||
UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);
|
||||
UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);
|
||||
DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);
|
||||
const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);
|
||||
const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);
|
||||
const DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);
|
||||
|
||||
// If the swap chain already exists, resize it, otherwise create one.
|
||||
if (m_swapChain)
|
||||
|
@ -324,7 +338,8 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
// If the device was removed for any reason, a new device and swap chain will need to be created.
|
||||
|
@ -469,7 +484,7 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// This method is called when the CoreWindow is created (or re-created).
|
||||
void DeviceResources::SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation)
|
||||
void DeviceResources::SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation) noexcept
|
||||
{
|
||||
m_window = window;
|
||||
|
||||
|
@ -590,16 +605,17 @@ void DeviceResources::HandleDeviceLost()
|
|||
}
|
||||
|
||||
// Prepare the command list and render target for rendering.
|
||||
void DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState)
|
||||
void DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState, D3D12_RESOURCE_STATES afterState)
|
||||
{
|
||||
// Reset command list and allocator.
|
||||
ThrowIfFailed(m_commandAllocators[m_backBufferIndex]->Reset());
|
||||
ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_backBufferIndex].Get(), nullptr));
|
||||
|
||||
if (beforeState != D3D12_RESOURCE_STATE_RENDER_TARGET)
|
||||
if (beforeState != afterState)
|
||||
{
|
||||
// Transition the render target into the correct state to allow for drawing into it.
|
||||
D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(), beforeState, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(),
|
||||
beforeState, afterState);
|
||||
m_commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
}
|
||||
|
@ -637,7 +653,8 @@ void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
HandleDeviceLost();
|
||||
|
@ -650,8 +667,7 @@ void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)
|
|||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
|
||||
UpdateColorSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -740,6 +756,7 @@ void DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!adapter)
|
||||
{
|
||||
for (UINT adapterIndex = 0;
|
||||
|
@ -794,6 +811,15 @@ void DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter)
|
|||
// Sets the color space for the swap chain in order to handle HDR output.
|
||||
void DeviceResources::UpdateColorSpace()
|
||||
{
|
||||
if (!m_dxgiFactory)
|
||||
return;
|
||||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
|
||||
}
|
||||
|
||||
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
bool isDisplayHDR10 = false;
|
||||
|
@ -801,11 +827,51 @@ void DeviceResources::UpdateColorSpace()
|
|||
#if defined(NTDDI_WIN10_RS2)
|
||||
if (m_swapChain)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
if (SUCCEEDED(m_swapChain->GetContainingOutput(output.GetAddressOf())))
|
||||
// To detect HDR support, we will need to check the color space in the primary
|
||||
// DXGI output associated with the app at this point in time
|
||||
// (using window/display intersection).
|
||||
|
||||
// Get the retangle bounds of the app window.
|
||||
RECT windowBounds;
|
||||
GetWindowBounds(m_window, &windowBounds);
|
||||
|
||||
const long ax1 = windowBounds.left;
|
||||
const long ay1 = windowBounds.top;
|
||||
const long ax2 = windowBounds.right;
|
||||
const long ay2 = windowBounds.bottom;
|
||||
|
||||
ComPtr<IDXGIOutput> bestOutput;
|
||||
long bestIntersectArea = -1;
|
||||
|
||||
ComPtr<IDXGIAdapter> adapter;
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(m_dxgiFactory->EnumAdapters(adapterIndex, adapter.ReleaseAndGetAddressOf()));
|
||||
++adapterIndex)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
for (UINT outputIndex = 0;
|
||||
SUCCEEDED(adapter->EnumOutputs(outputIndex, output.ReleaseAndGetAddressOf()));
|
||||
++outputIndex)
|
||||
{
|
||||
// Get the rectangle bounds of current output.
|
||||
DXGI_OUTPUT_DESC desc;
|
||||
ThrowIfFailed(output->GetDesc(&desc));
|
||||
const auto& r = desc.DesktopCoordinates;
|
||||
|
||||
// Compute the intersection
|
||||
const long intersectArea = ComputeIntersectionArea(ax1, ay1, ax2, ay2, r.left, r.top, r.right, r.bottom);
|
||||
if (intersectArea > bestIntersectArea)
|
||||
{
|
||||
bestOutput.Swap(output);
|
||||
bestIntersectArea = intersectArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestOutput)
|
||||
{
|
||||
ComPtr<IDXGIOutput6> output6;
|
||||
if (SUCCEEDED(output.As(&output6)))
|
||||
if (SUCCEEDED(bestOutput.As(&output6)))
|
||||
{
|
||||
DXGI_OUTPUT_DESC1 desc;
|
||||
ThrowIfFailed(output6->GetDesc1(&desc));
|
||||
|
@ -842,7 +908,8 @@ void DeviceResources::UpdateColorSpace()
|
|||
m_colorSpace = colorSpace;
|
||||
|
||||
UINT colorSpaceSupport = 0;
|
||||
if (SUCCEEDED(m_swapChain->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
if (m_swapChain
|
||||
&& SUCCEEDED(m_swapChain->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
&& (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
|
||||
{
|
||||
ThrowIfFailed(m_swapChain->SetColorSpace1(colorSpace));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// DeviceResources.h - A wrapper for the Direct3D 12 device and swapchain
|
||||
//
|
||||
|
||||
|
@ -20,8 +20,8 @@ namespace DX
|
|||
class DeviceResources
|
||||
{
|
||||
public:
|
||||
static const unsigned int c_AllowTearing = 0x1;
|
||||
static const unsigned int c_EnableHDR = 0x2;
|
||||
static constexpr unsigned int c_AllowTearing = 0x1;
|
||||
static constexpr unsigned int c_EnableHDR = 0x2;
|
||||
|
||||
DeviceResources(DXGI_FORMAT backBufferFormat = DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
DXGI_FORMAT depthBufferFormat = DXGI_FORMAT_D32_FLOAT,
|
||||
|
@ -30,48 +30,56 @@ namespace DX
|
|||
unsigned int flags = 0) noexcept(false);
|
||||
~DeviceResources();
|
||||
|
||||
DeviceResources(DeviceResources&&) = default;
|
||||
DeviceResources& operator= (DeviceResources&&) = default;
|
||||
|
||||
DeviceResources(DeviceResources const&) = delete;
|
||||
DeviceResources& operator= (DeviceResources const&) = delete;
|
||||
|
||||
void CreateDeviceResources();
|
||||
void CreateWindowSizeDependentResources();
|
||||
void SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation) noexcept;
|
||||
bool WindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void ValidateDevice();
|
||||
void HandleDeviceLost();
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) { m_deviceNotify = deviceNotify; }
|
||||
void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT);
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) noexcept { m_deviceNotify = deviceNotify; }
|
||||
void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT,
|
||||
D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
void Present(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
void WaitForGpu() noexcept;
|
||||
void UpdateColorSpace();
|
||||
|
||||
// Device Accessors.
|
||||
RECT GetOutputSize() const { return m_outputSize; }
|
||||
DXGI_MODE_ROTATION GetRotation() const { return m_rotation; }
|
||||
RECT GetOutputSize() const noexcept { return m_outputSize; }
|
||||
DXGI_MODE_ROTATION GetRotation() const noexcept { return m_rotation; }
|
||||
|
||||
// Direct3D Accessors.
|
||||
ID3D12Device* GetD3DDevice() const { return m_d3dDevice.Get(); }
|
||||
IDXGISwapChain3* GetSwapChain() const { return m_swapChain.Get(); }
|
||||
IDXGIFactory4* GetDXGIFactory() const { return m_dxgiFactory.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; }
|
||||
ID3D12Resource* GetRenderTarget() const { return m_renderTargets[m_backBufferIndex].Get(); }
|
||||
ID3D12Resource* GetDepthStencil() const { return m_depthStencil.Get(); }
|
||||
ID3D12CommandQueue* GetCommandQueue() const { return m_commandQueue.Get(); }
|
||||
ID3D12CommandAllocator* GetCommandAllocator() const { return m_commandAllocators[m_backBufferIndex].Get(); }
|
||||
ID3D12GraphicsCommandList* GetCommandList() const { return m_commandList.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const { return m_depthBufferFormat; }
|
||||
D3D12_VIEWPORT GetScreenViewport() const { return m_screenViewport; }
|
||||
D3D12_RECT GetScissorRect() const { return m_scissorRect; }
|
||||
UINT GetCurrentFrameIndex() const { return m_backBufferIndex; }
|
||||
UINT GetBackBufferCount() const { return m_backBufferCount; }
|
||||
DirectX::XMFLOAT4X4 GetOrientationTransform3D() const { return m_orientationTransform3D; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const { return m_options; }
|
||||
auto GetD3DDevice() const noexcept { return m_d3dDevice.Get(); }
|
||||
auto GetSwapChain() const noexcept { return m_swapChain.Get(); }
|
||||
auto GetDXGIFactory() const noexcept { return m_dxgiFactory.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const noexcept { return m_d3dFeatureLevel; }
|
||||
ID3D12Resource* GetRenderTarget() const noexcept { return m_renderTargets[m_backBufferIndex].Get(); }
|
||||
ID3D12Resource* GetDepthStencil() const noexcept { return m_depthStencil.Get(); }
|
||||
ID3D12CommandQueue* GetCommandQueue() const noexcept { return m_commandQueue.Get(); }
|
||||
ID3D12CommandAllocator* GetCommandAllocator() const noexcept { return m_commandAllocators[m_backBufferIndex].Get(); }
|
||||
auto GetCommandList() const noexcept { return m_commandList.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const noexcept { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const noexcept { return m_depthBufferFormat; }
|
||||
D3D12_VIEWPORT GetScreenViewport() const noexcept { return m_screenViewport; }
|
||||
D3D12_RECT GetScissorRect() const noexcept { return m_scissorRect; }
|
||||
UINT GetCurrentFrameIndex() const noexcept { return m_backBufferIndex; }
|
||||
UINT GetBackBufferCount() const noexcept { return m_backBufferCount; }
|
||||
DirectX::XMFLOAT4X4 GetOrientationTransform3D() const noexcept { return m_orientationTransform3D; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const noexcept { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const noexcept { return m_options; }
|
||||
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const noexcept
|
||||
{
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(
|
||||
m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||
static_cast<INT>(m_backBufferIndex), m_rtvDescriptorSize);
|
||||
}
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const noexcept
|
||||
{
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
|
@ -79,16 +87,15 @@ namespace DX
|
|||
private:
|
||||
void MoveToNextFrame();
|
||||
void GetAdapter(IDXGIAdapter1** ppAdapter);
|
||||
void UpdateColorSpace();
|
||||
|
||||
static const size_t MAX_BACK_BUFFER_COUNT = 3;
|
||||
static constexpr size_t MAX_BACK_BUFFER_COUNT = 3;
|
||||
|
||||
UINT m_backBufferIndex;
|
||||
|
||||
// Direct3D objects.
|
||||
Microsoft::WRL::ComPtr<ID3D12Device> m_d3dDevice;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> m_commandList;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_commandAllocators[MAX_BACK_BUFFER_COUNT];
|
||||
|
||||
// Swap chain objects.
|
||||
|
@ -122,15 +129,15 @@ namespace DX
|
|||
DWORD m_dxgiFactoryFlags;
|
||||
RECT m_outputSize;
|
||||
|
||||
// Transforms used for display orientation.
|
||||
DirectX::XMFLOAT4X4 m_orientationTransform3D;
|
||||
|
||||
// HDR Support
|
||||
DXGI_COLOR_SPACE_TYPE m_colorSpace;
|
||||
|
||||
// DeviceResources options (see flags above)
|
||||
unsigned int m_options;
|
||||
|
||||
// Transforms used for display orientation.
|
||||
DirectX::XMFLOAT4X4 m_orientationTransform3D;
|
||||
|
||||
// The IDeviceNotify can be held directly as it owns the DeviceResources.
|
||||
IDeviceNotify* m_deviceNotify;
|
||||
};
|
||||
|
|
|
@ -26,6 +26,24 @@ using namespace Windows::Foundation;
|
|||
using namespace Windows::Graphics::Display;
|
||||
using namespace DirectX;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
void ExitGame() noexcept;
|
||||
void GetWindowBounds(_In_ IUnknown* window, _Out_ RECT* rect);
|
||||
|
||||
namespace
|
||||
{
|
||||
inline int ConvertDipsToPixels(float dips, float dpi) noexcept
|
||||
{
|
||||
return int(dips * dpi / 96.f + 0.5f);
|
||||
}
|
||||
|
||||
inline float ConvertPixelsToDips(int pixels, float dpi) noexcept
|
||||
{
|
||||
return (float(pixels) * 96.f / dpi);
|
||||
}
|
||||
}
|
||||
|
||||
ref class ViewProvider sealed : public IFrameworkView
|
||||
{
|
||||
public:
|
||||
|
@ -135,8 +153,8 @@ public:
|
|||
m_nativeOrientation = currentDisplayInformation->NativeOrientation;
|
||||
m_currentOrientation = currentDisplayInformation->CurrentOrientation;
|
||||
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight);
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth, m_DPI);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight, m_DPI);
|
||||
|
||||
DXGI_MODE_ROTATION rotation = ComputeDisplayRotation();
|
||||
|
||||
|
@ -196,13 +214,13 @@ protected:
|
|||
ApplicationView::PreferredLaunchWindowingMode = ApplicationViewWindowingMode::PreferredLaunchViewSize;
|
||||
// Change to ApplicationViewWindowingMode::FullScreen to default to full screen
|
||||
|
||||
auto desiredSize = Size(ConvertPixelsToDips(w), ConvertPixelsToDips(h));
|
||||
auto desiredSize = Size(ConvertPixelsToDips(w, m_DPI), ConvertPixelsToDips(h, m_DPI));
|
||||
|
||||
ApplicationView::PreferredLaunchViewSize = desiredSize;
|
||||
|
||||
auto view = ApplicationView::GetForCurrentView();
|
||||
|
||||
auto minSize = Size(ConvertPixelsToDips(320), ConvertPixelsToDips(200));
|
||||
auto minSize = Size(ConvertPixelsToDips(320, m_DPI), ConvertPixelsToDips(200, m_DPI));
|
||||
|
||||
view->SetPreferredMinSize(minSize);
|
||||
|
||||
|
@ -319,6 +337,7 @@ protected:
|
|||
void OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args)
|
||||
{
|
||||
m_sample->ValidateDevice();
|
||||
m_sample->OnDisplayChange();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -333,17 +352,7 @@ private:
|
|||
Windows::Graphics::Display::DisplayOrientations m_nativeOrientation;
|
||||
Windows::Graphics::Display::DisplayOrientations m_currentOrientation;
|
||||
|
||||
inline int ConvertDipsToPixels(float dips) const
|
||||
{
|
||||
return int(dips * m_DPI / 96.f + 0.5f);
|
||||
}
|
||||
|
||||
inline float ConvertPixelsToDips(int pixels) const
|
||||
{
|
||||
return (float(pixels) * 96.f / m_DPI);
|
||||
}
|
||||
|
||||
DXGI_MODE_ROTATION ComputeDisplayRotation() const
|
||||
DXGI_MODE_ROTATION ComputeDisplayRotation() const noexcept
|
||||
{
|
||||
DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
|
||||
|
||||
|
@ -367,6 +376,9 @@ private:
|
|||
case DisplayOrientations::PortraitFlipped:
|
||||
rotation = DXGI_MODE_ROTATION_ROTATE90;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -388,8 +400,14 @@ private:
|
|||
case DisplayOrientations::PortraitFlipped:
|
||||
rotation = DXGI_MODE_ROTATION_ROTATE180;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rotation;
|
||||
|
@ -397,8 +415,8 @@ private:
|
|||
|
||||
void HandleWindowSizeChanged()
|
||||
{
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight);
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth, m_DPI);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight, m_DPI);
|
||||
|
||||
DXGI_MODE_ROTATION rotation = ComputeDisplayRotation();
|
||||
|
||||
|
@ -441,3 +459,32 @@ void ExitSample() noexcept
|
|||
{
|
||||
Windows::ApplicationModel::Core::CoreApplication::Exit();
|
||||
}
|
||||
|
||||
|
||||
// Window size helper
|
||||
_Use_decl_annotations_
|
||||
void GetWindowBounds(IUnknown* window, RECT* rect)
|
||||
{
|
||||
if (!rect)
|
||||
return;
|
||||
|
||||
*rect = {};
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
auto b = reinterpret_cast<CoreWindow^>(window)->Bounds;
|
||||
|
||||
auto currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||
float dpi = currentDisplayInformation->LogicalDpi;
|
||||
|
||||
const int x = ConvertDipsToPixels(b.X, dpi);
|
||||
const int y = ConvertDipsToPixels(b.Y, dpi);
|
||||
const int w = ConvertDipsToPixels(b.Width, dpi);
|
||||
const int h = ConvertDipsToPixels(b.Height, dpi);
|
||||
|
||||
rect->left = static_cast<long>(x);
|
||||
rect->top = static_cast<long>(y);
|
||||
rect->right = static_cast<long>(x + w);
|
||||
rect->bottom = static_cast<long>(y + h);
|
||||
}
|
||||
|
|
|
@ -769,6 +769,11 @@ void Sample::OnResuming()
|
|||
m_keyboardButtons.Reset();
|
||||
}
|
||||
|
||||
void Sample::OnDisplayChange()
|
||||
{
|
||||
m_deviceResources->UpdateColorSpace();
|
||||
}
|
||||
|
||||
void Sample::OnWindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation)
|
||||
{
|
||||
if (!m_deviceResources->WindowSizeChanged(width, height, rotation))
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
void OnDeactivated();
|
||||
void OnSuspending();
|
||||
void OnResuming();
|
||||
void OnDisplayChange();
|
||||
void OnWindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void ValidateDevice();
|
||||
|
||||
|
@ -58,7 +59,7 @@ private:
|
|||
|
||||
void CreateDeviceDependentResources();
|
||||
void CreateWindowSizeDependentResources();
|
||||
|
||||
|
||||
// Device resources.
|
||||
std::unique_ptr<DX::DeviceResources> m_deviceResources;
|
||||
|
||||
|
|
|
@ -31,14 +31,19 @@
|
|||
#include "d3dx12.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// To use graphics and CPU markup events with the latest version of PIX, change this to include <pix3.h>
|
||||
// then add the NuGet package WinPixEventRuntime to the project.
|
||||
// To use graphics and CPU markup events with the latest version of PIX, change this to include <pix3.h>
|
||||
// then add the NuGet package WinPixEventRuntime to the project.
|
||||
#include <pix.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
|
|
@ -10,6 +10,10 @@ using namespace DX;
|
|||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
extern void GetWindowBounds(_In_ IUnknown* window, _Out_ RECT* rect);
|
||||
|
||||
// Constants used to calculate screen rotations
|
||||
namespace ScreenRotation
|
||||
{
|
||||
|
@ -44,11 +48,11 @@ namespace ScreenRotation
|
|||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt)
|
||||
inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt) noexcept
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
|
@ -58,7 +62,14 @@ namespace
|
|||
default: return fmt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline long ComputeIntersectionArea(
|
||||
long ax1, long ay1, long ax2, long ay2,
|
||||
long bx1, long by1, long bx2, long by2) noexcept
|
||||
{
|
||||
return std::max(0l, std::min(ax2, bx2) - std::max(ax1, bx1)) * std::max(0l, std::min(ay2, by2) - std::max(ay1, by1));
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for DeviceResources.
|
||||
DeviceResources::DeviceResources(
|
||||
|
@ -204,6 +215,9 @@ void DeviceResources::CreateDeviceResources()
|
|||
// Determine maximum supported feature level for this device
|
||||
static const D3D_FEATURE_LEVEL s_featureLevels[] =
|
||||
{
|
||||
#if defined(NTDDI_WIN10_FE) && (NTDDI_VERSION >= NTDDI_WIN10_FE)
|
||||
D3D_FEATURE_LEVEL_12_2,
|
||||
#endif
|
||||
D3D_FEATURE_LEVEL_12_1,
|
||||
D3D_FEATURE_LEVEL_12_0,
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
|
@ -304,9 +318,9 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// Determine the render target size in pixels.
|
||||
UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);
|
||||
UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);
|
||||
DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);
|
||||
const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);
|
||||
const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);
|
||||
const DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);
|
||||
|
||||
// If the swap chain already exists, resize it, otherwise create one.
|
||||
if (m_swapChain)
|
||||
|
@ -324,7 +338,8 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
// If the device was removed for any reason, a new device and swap chain will need to be created.
|
||||
|
@ -469,7 +484,7 @@ void DeviceResources::CreateWindowSizeDependentResources()
|
|||
}
|
||||
|
||||
// This method is called when the CoreWindow is created (or re-created).
|
||||
void DeviceResources::SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation)
|
||||
void DeviceResources::SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation) noexcept
|
||||
{
|
||||
m_window = window;
|
||||
|
||||
|
@ -590,16 +605,17 @@ void DeviceResources::HandleDeviceLost()
|
|||
}
|
||||
|
||||
// Prepare the command list and render target for rendering.
|
||||
void DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState)
|
||||
void DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState, D3D12_RESOURCE_STATES afterState)
|
||||
{
|
||||
// Reset command list and allocator.
|
||||
ThrowIfFailed(m_commandAllocators[m_backBufferIndex]->Reset());
|
||||
ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_backBufferIndex].Get(), nullptr));
|
||||
|
||||
if (beforeState != D3D12_RESOURCE_STATE_RENDER_TARGET)
|
||||
if (beforeState != afterState)
|
||||
{
|
||||
// Transition the render target into the correct state to allow for drawing into it.
|
||||
D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(), beforeState, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(),
|
||||
beforeState, afterState);
|
||||
m_commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
}
|
||||
|
@ -637,7 +653,8 @@ void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)
|
|||
{
|
||||
#ifdef _DEBUG
|
||||
char buff[64] = {};
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);
|
||||
sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n",
|
||||
static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));
|
||||
OutputDebugStringA(buff);
|
||||
#endif
|
||||
HandleDeviceLost();
|
||||
|
@ -650,8 +667,7 @@ void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)
|
|||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
|
||||
UpdateColorSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -740,6 +756,7 @@ void DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!adapter)
|
||||
{
|
||||
for (UINT adapterIndex = 0;
|
||||
|
@ -794,6 +811,15 @@ void DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter)
|
|||
// Sets the color space for the swap chain in order to handle HDR output.
|
||||
void DeviceResources::UpdateColorSpace()
|
||||
{
|
||||
if (!m_dxgiFactory)
|
||||
return;
|
||||
|
||||
if (!m_dxgiFactory->IsCurrent())
|
||||
{
|
||||
// Output information is cached on the DXGI Factory. If it is stale we need to create a new factory.
|
||||
ThrowIfFailed(CreateDXGIFactory2(m_dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
|
||||
}
|
||||
|
||||
DXGI_COLOR_SPACE_TYPE colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
bool isDisplayHDR10 = false;
|
||||
|
@ -801,11 +827,51 @@ void DeviceResources::UpdateColorSpace()
|
|||
#if defined(NTDDI_WIN10_RS2)
|
||||
if (m_swapChain)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
if (SUCCEEDED(m_swapChain->GetContainingOutput(output.GetAddressOf())))
|
||||
// To detect HDR support, we will need to check the color space in the primary
|
||||
// DXGI output associated with the app at this point in time
|
||||
// (using window/display intersection).
|
||||
|
||||
// Get the retangle bounds of the app window.
|
||||
RECT windowBounds;
|
||||
GetWindowBounds(m_window, &windowBounds);
|
||||
|
||||
const long ax1 = windowBounds.left;
|
||||
const long ay1 = windowBounds.top;
|
||||
const long ax2 = windowBounds.right;
|
||||
const long ay2 = windowBounds.bottom;
|
||||
|
||||
ComPtr<IDXGIOutput> bestOutput;
|
||||
long bestIntersectArea = -1;
|
||||
|
||||
ComPtr<IDXGIAdapter> adapter;
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(m_dxgiFactory->EnumAdapters(adapterIndex, adapter.ReleaseAndGetAddressOf()));
|
||||
++adapterIndex)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
for (UINT outputIndex = 0;
|
||||
SUCCEEDED(adapter->EnumOutputs(outputIndex, output.ReleaseAndGetAddressOf()));
|
||||
++outputIndex)
|
||||
{
|
||||
// Get the rectangle bounds of current output.
|
||||
DXGI_OUTPUT_DESC desc;
|
||||
ThrowIfFailed(output->GetDesc(&desc));
|
||||
const auto& r = desc.DesktopCoordinates;
|
||||
|
||||
// Compute the intersection
|
||||
const long intersectArea = ComputeIntersectionArea(ax1, ay1, ax2, ay2, r.left, r.top, r.right, r.bottom);
|
||||
if (intersectArea > bestIntersectArea)
|
||||
{
|
||||
bestOutput.Swap(output);
|
||||
bestIntersectArea = intersectArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestOutput)
|
||||
{
|
||||
ComPtr<IDXGIOutput6> output6;
|
||||
if (SUCCEEDED(output.As(&output6)))
|
||||
if (SUCCEEDED(bestOutput.As(&output6)))
|
||||
{
|
||||
DXGI_OUTPUT_DESC1 desc;
|
||||
ThrowIfFailed(output6->GetDesc1(&desc));
|
||||
|
@ -842,7 +908,8 @@ void DeviceResources::UpdateColorSpace()
|
|||
m_colorSpace = colorSpace;
|
||||
|
||||
UINT colorSpaceSupport = 0;
|
||||
if (SUCCEEDED(m_swapChain->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
if (m_swapChain
|
||||
&& SUCCEEDED(m_swapChain->CheckColorSpaceSupport(colorSpace, &colorSpaceSupport))
|
||||
&& (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
|
||||
{
|
||||
ThrowIfFailed(m_swapChain->SetColorSpace1(colorSpace));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// DeviceResources.h - A wrapper for the Direct3D 12 device and swapchain
|
||||
//
|
||||
|
||||
|
@ -20,8 +20,8 @@ namespace DX
|
|||
class DeviceResources
|
||||
{
|
||||
public:
|
||||
static const unsigned int c_AllowTearing = 0x1;
|
||||
static const unsigned int c_EnableHDR = 0x2;
|
||||
static constexpr unsigned int c_AllowTearing = 0x1;
|
||||
static constexpr unsigned int c_EnableHDR = 0x2;
|
||||
|
||||
DeviceResources(DXGI_FORMAT backBufferFormat = DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
DXGI_FORMAT depthBufferFormat = DXGI_FORMAT_D32_FLOAT,
|
||||
|
@ -30,48 +30,56 @@ namespace DX
|
|||
unsigned int flags = 0) noexcept(false);
|
||||
~DeviceResources();
|
||||
|
||||
DeviceResources(DeviceResources&&) = default;
|
||||
DeviceResources& operator= (DeviceResources&&) = default;
|
||||
|
||||
DeviceResources(DeviceResources const&) = delete;
|
||||
DeviceResources& operator= (DeviceResources const&) = delete;
|
||||
|
||||
void CreateDeviceResources();
|
||||
void CreateWindowSizeDependentResources();
|
||||
void SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void SetWindow(IUnknown* window, int width, int height, DXGI_MODE_ROTATION rotation) noexcept;
|
||||
bool WindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void ValidateDevice();
|
||||
void HandleDeviceLost();
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) { m_deviceNotify = deviceNotify; }
|
||||
void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT);
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify) noexcept { m_deviceNotify = deviceNotify; }
|
||||
void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT,
|
||||
D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
void Present(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
void WaitForGpu() noexcept;
|
||||
void UpdateColorSpace();
|
||||
|
||||
// Device Accessors.
|
||||
RECT GetOutputSize() const { return m_outputSize; }
|
||||
DXGI_MODE_ROTATION GetRotation() const { return m_rotation; }
|
||||
RECT GetOutputSize() const noexcept { return m_outputSize; }
|
||||
DXGI_MODE_ROTATION GetRotation() const noexcept { return m_rotation; }
|
||||
|
||||
// Direct3D Accessors.
|
||||
ID3D12Device* GetD3DDevice() const { return m_d3dDevice.Get(); }
|
||||
IDXGISwapChain3* GetSwapChain() const { return m_swapChain.Get(); }
|
||||
IDXGIFactory4* GetDXGIFactory() const { return m_dxgiFactory.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; }
|
||||
ID3D12Resource* GetRenderTarget() const { return m_renderTargets[m_backBufferIndex].Get(); }
|
||||
ID3D12Resource* GetDepthStencil() const { return m_depthStencil.Get(); }
|
||||
ID3D12CommandQueue* GetCommandQueue() const { return m_commandQueue.Get(); }
|
||||
ID3D12CommandAllocator* GetCommandAllocator() const { return m_commandAllocators[m_backBufferIndex].Get(); }
|
||||
ID3D12GraphicsCommandList* GetCommandList() const { return m_commandList.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const { return m_depthBufferFormat; }
|
||||
D3D12_VIEWPORT GetScreenViewport() const { return m_screenViewport; }
|
||||
D3D12_RECT GetScissorRect() const { return m_scissorRect; }
|
||||
UINT GetCurrentFrameIndex() const { return m_backBufferIndex; }
|
||||
UINT GetBackBufferCount() const { return m_backBufferCount; }
|
||||
DirectX::XMFLOAT4X4 GetOrientationTransform3D() const { return m_orientationTransform3D; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const { return m_options; }
|
||||
auto GetD3DDevice() const noexcept { return m_d3dDevice.Get(); }
|
||||
auto GetSwapChain() const noexcept { return m_swapChain.Get(); }
|
||||
auto GetDXGIFactory() const noexcept { return m_dxgiFactory.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const noexcept { return m_d3dFeatureLevel; }
|
||||
ID3D12Resource* GetRenderTarget() const noexcept { return m_renderTargets[m_backBufferIndex].Get(); }
|
||||
ID3D12Resource* GetDepthStencil() const noexcept { return m_depthStencil.Get(); }
|
||||
ID3D12CommandQueue* GetCommandQueue() const noexcept { return m_commandQueue.Get(); }
|
||||
ID3D12CommandAllocator* GetCommandAllocator() const noexcept { return m_commandAllocators[m_backBufferIndex].Get(); }
|
||||
auto GetCommandList() const noexcept { return m_commandList.Get(); }
|
||||
DXGI_FORMAT GetBackBufferFormat() const noexcept { return m_backBufferFormat; }
|
||||
DXGI_FORMAT GetDepthBufferFormat() const noexcept { return m_depthBufferFormat; }
|
||||
D3D12_VIEWPORT GetScreenViewport() const noexcept { return m_screenViewport; }
|
||||
D3D12_RECT GetScissorRect() const noexcept { return m_scissorRect; }
|
||||
UINT GetCurrentFrameIndex() const noexcept { return m_backBufferIndex; }
|
||||
UINT GetBackBufferCount() const noexcept { return m_backBufferCount; }
|
||||
DirectX::XMFLOAT4X4 GetOrientationTransform3D() const noexcept { return m_orientationTransform3D; }
|
||||
DXGI_COLOR_SPACE_TYPE GetColorSpace() const noexcept { return m_colorSpace; }
|
||||
unsigned int GetDeviceOptions() const noexcept { return m_options; }
|
||||
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const noexcept
|
||||
{
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(
|
||||
m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||
static_cast<INT>(m_backBufferIndex), m_rtvDescriptorSize);
|
||||
}
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const noexcept
|
||||
{
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
|
@ -79,16 +87,15 @@ namespace DX
|
|||
private:
|
||||
void MoveToNextFrame();
|
||||
void GetAdapter(IDXGIAdapter1** ppAdapter);
|
||||
void UpdateColorSpace();
|
||||
|
||||
static const size_t MAX_BACK_BUFFER_COUNT = 3;
|
||||
static constexpr size_t MAX_BACK_BUFFER_COUNT = 3;
|
||||
|
||||
UINT m_backBufferIndex;
|
||||
|
||||
// Direct3D objects.
|
||||
Microsoft::WRL::ComPtr<ID3D12Device> m_d3dDevice;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> m_commandList;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_commandAllocators[MAX_BACK_BUFFER_COUNT];
|
||||
|
||||
// Swap chain objects.
|
||||
|
@ -122,15 +129,15 @@ namespace DX
|
|||
DWORD m_dxgiFactoryFlags;
|
||||
RECT m_outputSize;
|
||||
|
||||
// Transforms used for display orientation.
|
||||
DirectX::XMFLOAT4X4 m_orientationTransform3D;
|
||||
|
||||
// HDR Support
|
||||
DXGI_COLOR_SPACE_TYPE m_colorSpace;
|
||||
|
||||
// DeviceResources options (see flags above)
|
||||
unsigned int m_options;
|
||||
|
||||
// Transforms used for display orientation.
|
||||
DirectX::XMFLOAT4X4 m_orientationTransform3D;
|
||||
|
||||
// The IDeviceNotify can be held directly as it owns the DeviceResources.
|
||||
IDeviceNotify* m_deviceNotify;
|
||||
};
|
||||
|
|
|
@ -26,6 +26,24 @@ using namespace Windows::Foundation;
|
|||
using namespace Windows::Graphics::Display;
|
||||
using namespace DirectX;
|
||||
|
||||
#pragma warning(disable : 4061)
|
||||
|
||||
void ExitGame() noexcept;
|
||||
void GetWindowBounds(_In_ IUnknown* window, _Out_ RECT* rect);
|
||||
|
||||
namespace
|
||||
{
|
||||
inline int ConvertDipsToPixels(float dips, float dpi) noexcept
|
||||
{
|
||||
return int(dips * dpi / 96.f + 0.5f);
|
||||
}
|
||||
|
||||
inline float ConvertPixelsToDips(int pixels, float dpi) noexcept
|
||||
{
|
||||
return (float(pixels) * 96.f / dpi);
|
||||
}
|
||||
}
|
||||
|
||||
ref class ViewProvider sealed : public IFrameworkView
|
||||
{
|
||||
public:
|
||||
|
@ -135,8 +153,8 @@ public:
|
|||
m_nativeOrientation = currentDisplayInformation->NativeOrientation;
|
||||
m_currentOrientation = currentDisplayInformation->CurrentOrientation;
|
||||
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight);
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth, m_DPI);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight, m_DPI);
|
||||
|
||||
DXGI_MODE_ROTATION rotation = ComputeDisplayRotation();
|
||||
|
||||
|
@ -194,13 +212,13 @@ protected:
|
|||
ApplicationView::PreferredLaunchWindowingMode = ApplicationViewWindowingMode::PreferredLaunchViewSize;
|
||||
// Change to ApplicationViewWindowingMode::FullScreen to default to full screen
|
||||
|
||||
auto desiredSize = Size(ConvertPixelsToDips(w), ConvertPixelsToDips(h));
|
||||
auto desiredSize = Size(ConvertPixelsToDips(w, m_DPI), ConvertPixelsToDips(h, m_DPI));
|
||||
|
||||
ApplicationView::PreferredLaunchViewSize = desiredSize;
|
||||
|
||||
auto view = ApplicationView::GetForCurrentView();
|
||||
|
||||
auto minSize = Size(ConvertPixelsToDips(320), ConvertPixelsToDips(200));
|
||||
auto minSize = Size(ConvertPixelsToDips(320, m_DPI), ConvertPixelsToDips(200, m_DPI));
|
||||
|
||||
view->SetPreferredMinSize(minSize);
|
||||
|
||||
|
@ -315,6 +333,7 @@ protected:
|
|||
void OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args)
|
||||
{
|
||||
m_sample->ValidateDevice();
|
||||
m_sample->OnDisplayChange();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -329,17 +348,7 @@ private:
|
|||
Windows::Graphics::Display::DisplayOrientations m_nativeOrientation;
|
||||
Windows::Graphics::Display::DisplayOrientations m_currentOrientation;
|
||||
|
||||
inline int ConvertDipsToPixels(float dips) const
|
||||
{
|
||||
return int(dips * m_DPI / 96.f + 0.5f);
|
||||
}
|
||||
|
||||
inline float ConvertPixelsToDips(int pixels) const
|
||||
{
|
||||
return (float(pixels) * 96.f / m_DPI);
|
||||
}
|
||||
|
||||
DXGI_MODE_ROTATION ComputeDisplayRotation() const
|
||||
DXGI_MODE_ROTATION ComputeDisplayRotation() const noexcept
|
||||
{
|
||||
DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
|
||||
|
||||
|
@ -363,6 +372,9 @@ private:
|
|||
case DisplayOrientations::PortraitFlipped:
|
||||
rotation = DXGI_MODE_ROTATION_ROTATE90;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -384,8 +396,14 @@ private:
|
|||
case DisplayOrientations::PortraitFlipped:
|
||||
rotation = DXGI_MODE_ROTATION_ROTATE180;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rotation;
|
||||
|
@ -393,8 +411,8 @@ private:
|
|||
|
||||
void HandleWindowSizeChanged()
|
||||
{
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight);
|
||||
int outputWidth = ConvertDipsToPixels(m_logicalWidth, m_DPI);
|
||||
int outputHeight = ConvertDipsToPixels(m_logicalHeight, m_DPI);
|
||||
|
||||
DXGI_MODE_ROTATION rotation = ComputeDisplayRotation();
|
||||
|
||||
|
@ -436,4 +454,33 @@ int __cdecl main(Platform::Array<Platform::String^>^ /*argv*/)
|
|||
void ExitSample() noexcept
|
||||
{
|
||||
Windows::ApplicationModel::Core::CoreApplication::Exit();
|
||||
}
|
||||
|
||||
|
||||
// Window size helper
|
||||
_Use_decl_annotations_
|
||||
void GetWindowBounds(IUnknown* window, RECT* rect)
|
||||
{
|
||||
if (!rect)
|
||||
return;
|
||||
|
||||
*rect = {};
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
auto b = reinterpret_cast<CoreWindow^>(window)->Bounds;
|
||||
|
||||
auto currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||
float dpi = currentDisplayInformation->LogicalDpi;
|
||||
|
||||
const int x = ConvertDipsToPixels(b.X, dpi);
|
||||
const int y = ConvertDipsToPixels(b.Y, dpi);
|
||||
const int w = ConvertDipsToPixels(b.Width, dpi);
|
||||
const int h = ConvertDipsToPixels(b.Height, dpi);
|
||||
|
||||
rect->left = static_cast<long>(x);
|
||||
rect->top = static_cast<long>(y);
|
||||
rect->right = static_cast<long>(x + w);
|
||||
rect->bottom = static_cast<long>(y + h);
|
||||
}
|
|
@ -145,6 +145,11 @@ void Sample::OnResuming()
|
|||
m_timer.ResetElapsedTime();
|
||||
}
|
||||
|
||||
void Sample::OnDisplayChange()
|
||||
{
|
||||
m_deviceResources->UpdateColorSpace();
|
||||
}
|
||||
|
||||
void Sample::OnWindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation)
|
||||
{
|
||||
if (!m_deviceResources->WindowSizeChanged(width, height, rotation))
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
void OnDeactivated();
|
||||
void OnSuspending();
|
||||
void OnResuming();
|
||||
void OnDisplayChange();
|
||||
void OnWindowSizeChanged(int width, int height, DXGI_MODE_ROTATION rotation);
|
||||
void ValidateDevice();
|
||||
|
||||
|
|
|
@ -42,11 +42,16 @@
|
|||
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pix.h>
|
||||
|
||||
#include <ATGColors.h>
|
||||
|
|
|
@ -42,11 +42,16 @@
|
|||
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pix.h>
|
||||
|
||||
#include <ATGColors.h>
|
||||
|
|
Загрузка…
Ссылка в новой задаче