Update HDR support for PC to avoid GetContainingOutput (#36)

This commit is contained in:
Chuck Walbourn 2022-02-04 17:34:49 -08:00
Родитель 26d73c1ce2
Коммит 187562b015
31 изменённых файлов: 1113 добавлений и 421 удалений

Просмотреть файл

@ -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>