Skip to content

Commit

Permalink
Merge pull request #32 from Microsoft/develop
Browse files Browse the repository at this point in the history
Merge develop into master
  • Loading branch information
bobbrow committed Oct 6, 2015
2 parents 8f64a67 + 3106a7a commit 073e705
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 30 deletions.
4 changes: 4 additions & 0 deletions Templates/DirectX12App/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ void App::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)

void App::OnDpiChanged(DisplayInformation^ sender, Object^ args)
{
// Note: The value for LogicalDpi retrieved here may not match the effective DPI of the app
// if it is being scaled for high resolution devices. Once the DPI is set on DeviceResources,
// you should always retrieve it using the GetDpi method.
// See DeviceResources.cpp for more details.
GetDeviceResources()->SetDpi(sender->LogicalDpi);
m_main->OnWindowSizeChanged();
}
Expand Down
161 changes: 137 additions & 24 deletions Templates/DirectX12App/Common/DeviceResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,23 @@ using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml::Controls;
using namespace Platform;

namespace DisplayMetrics
{
// High resolution displays can require a lot of GPU and battery power to render.
// High resolution phones, for example, may suffer from poor battery life if
// games attempt to render at 60 frames per second at full fidelity.
// The decision to render at full fidelity across all platforms and form factors
// should be deliberate.
static const bool SupportHighResolutions = false;

// The default thresholds that define a "high resolution" display. If the thresholds
// are exceeded and SupportHighResolutions is false, the dimensions will be scaled
// by 50%.
static const float DpiThreshold = 192.0f; // 200% of standard desktop display.
static const float WidthThreshold = 1920.0f; // 1080p width.
static const float HeightThreshold = 1080.0f; // 1080p height.
};

// Constants used to calculate screen rotations.
namespace ScreenRotation
{
Expand Down Expand Up @@ -58,6 +75,7 @@ DX::DeviceResources::DeviceResources() :
m_nativeOrientation(DisplayOrientations::None),
m_currentOrientation(DisplayOrientations::None),
m_dpi(-1.0f),
m_effectiveDpi(-1.0f),
m_deviceRemoved(false)
{
ZeroMemory(m_fenceValues, sizeof(m_fenceValues));
Expand Down Expand Up @@ -86,9 +104,12 @@ void DX::DeviceResources::CreateDeviceResources()

DX::ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&m_dxgiFactory)));

ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(m_dxgiFactory.Get(), &adapter);

// Create the Direct3D 12 API device object
HRESULT hr = D3D12CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
adapter.Get(), // The hardware adapter.
D3D_FEATURE_LEVEL_11_0, // Minimum feature level this app can support.
IID_PPV_ARGS(&m_d3dDevice) // Returns the Direct3D device created.
);
Expand Down Expand Up @@ -145,13 +166,7 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
}
m_rtvHeap = nullptr;

// Calculate the necessary render target size in pixels.
m_outputSize.Width = DX::ConvertDipsToPixels(m_logicalSize.Width, m_dpi);
m_outputSize.Height = DX::ConvertDipsToPixels(m_logicalSize.Height, m_dpi);

// Prevent zero size DirectX content from being created.
m_outputSize.Width = max(m_outputSize.Width, 1);
m_outputSize.Height = max(m_outputSize.Height, 1);
UpdateRenderTargetSize();

// The width and height of the swap chain must be based on the window's
// natively-oriented width and height. If the window is not in the native
Expand Down Expand Up @@ -189,6 +204,7 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
else
{
// Otherwise, create a new one using the same adapter as the existing Direct3D device.
DXGI_SCALING scaling = DisplayMetrics::SupportHighResolutions ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH;
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};

swapChainDesc.Width = lround(m_d3dRenderTargetSize.Width); // Match the size of the window.
Expand All @@ -201,13 +217,13 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
swapChainDesc.BufferCount = c_frameCount; // Use triple-buffering to minimize latency.
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // All Windows Universal apps must use _FLIP_ SwapEffects
swapChainDesc.Flags = 0;
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.Scaling = scaling;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;

ComPtr<IDXGISwapChain1> swapChain;
DX::ThrowIfFailed(
m_dxgiFactory->CreateSwapChainForCoreWindow(
m_commandQueue.Get(),
m_commandQueue.Get(), // Swap chains need a reference to the command queue in DirectX 12.
reinterpret_cast<IUnknown*>(m_window.Get()),
&swapChainDesc,
nullptr,
Expand Down Expand Up @@ -248,22 +264,15 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
m_swapChain->SetRotation(displayRotation)
);

// Create a render target view of the swap chain back buffer.
// Create render target views of the swap chain back buffer.
{
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.NumDescriptors = c_frameCount;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
DX::ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_rtvHeap)));
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
rtvHeapDesc.NumDescriptors = c_frameCount;
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
DX::ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));
m_rtvHeap->SetName(L"Render Target View Descriptor Heap");

// All pending GPU work was already finished. Update the tracked fence values
// to the last value signaled.
for (UINT n = 0; n < c_frameCount; n++)
{
m_fenceValues[n] = m_fenceValues[m_currentFrame];
}

m_currentFrame = 0;
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
m_rtvDescriptorSize = m_d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
Expand All @@ -279,10 +288,85 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
}
}

// Create a depth stencil view.
{
D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
dsvHeapDesc.NumDescriptors = 1;
dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&m_dsvHeap)));

D3D12_HEAP_PROPERTIES depthHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
D3D12_RESOURCE_DESC depthResourceDesc = CD3DX12_RESOURCE_DESC::Tex2D(
DXGI_FORMAT_D32_FLOAT,
static_cast<UINT>(m_d3dRenderTargetSize.Width),
static_cast<UINT>(m_d3dRenderTargetSize.Height),
1,
0,
1,
0,
D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);

D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT;
depthOptimizedClearValue.DepthStencil.Depth = 1.0f;
depthOptimizedClearValue.DepthStencil.Stencil = 0;

ThrowIfFailed(m_d3dDevice->CreateCommittedResource(
&depthHeapProperties,
D3D12_HEAP_FLAG_NONE,
&depthResourceDesc,
D3D12_RESOURCE_STATE_DEPTH_WRITE,
&depthOptimizedClearValue,
IID_PPV_ARGS(&m_depthStencil)
));

D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
dsvDesc.Flags = D3D12_DSV_FLAG_NONE;

m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
}

// All pending GPU work was already finished. Update the tracked fence values
// to the last value signaled.
for (UINT n = 0; n < c_frameCount; n++)
{
m_fenceValues[n] = m_fenceValues[m_currentFrame];
}

// Set the 3D rendering viewport to target the entire window.
m_screenViewport = { 0.0f, 0.0f, m_d3dRenderTargetSize.Width, m_d3dRenderTargetSize.Height, 0.0f, 1.0f };
}

void DX::DeviceResources::UpdateRenderTargetSize()
{
m_effectiveDpi = m_dpi;

// To improve battery life on high resolution devices, render to a smaller render target
// and allow the GPU to scale the output when it is presented.
if (!DisplayMetrics::SupportHighResolutions && m_dpi > DisplayMetrics::DpiThreshold)
{
float width = DX::ConvertDipsToPixels(m_logicalSize.Width, m_dpi);
float height = DX::ConvertDipsToPixels(m_logicalSize.Height, m_dpi);

if (width > DisplayMetrics::WidthThreshold && height > DisplayMetrics::HeightThreshold)
{
// To scale the app we change the effective DPI. Logical size does not change.
m_effectiveDpi /= 2.0f;
}
}

// Calculate the necessary render target size in pixels.
m_outputSize.Width = DX::ConvertDipsToPixels(m_logicalSize.Width, m_effectiveDpi);
m_outputSize.Height = DX::ConvertDipsToPixels(m_logicalSize.Height, m_effectiveDpi);

// Prevent zero size DirectX content from being created.
m_outputSize.Width = max(m_outputSize.Width, 1);
m_outputSize.Height = max(m_outputSize.Height, 1);
}

// This method is called when the CoreWindow is created (or re-created).
void DX::DeviceResources::SetWindow(CoreWindow^ window)
{
Expand Down Expand Up @@ -473,4 +557,33 @@ DXGI_MODE_ROTATION DX::DeviceResources::ComputeDisplayRotation()
break;
}
return rotation;
}
}

// This method acquires the first available hardware adapter that supports Direct3D 12.
// If no such adapter can be found, *ppAdapter will be set to nullptr.
void DX::DeviceResources::GetHardwareAdapter(IDXGIFactory4* pFactory, IDXGIAdapter1** ppAdapter)
{
ComPtr<IDXGIAdapter1> adapter;
*ppAdapter = nullptr;

for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1(adapterIndex, &adapter); ++adapterIndex)
{
DXGI_ADAPTER_DESC1 desc;
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(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))
{
break;
}
}

*ppAdapter = adapter.Detach();
}
18 changes: 17 additions & 1 deletion Templates/DirectX12App/Common/DeviceResources.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@ namespace DX
void Present();
void WaitForGpu();

// Device Accessors.
// The size of the render target, in pixels.
Windows::Foundation::Size GetOutputSize() const { return m_outputSize; }

// The size of the render target, in dips.
Windows::Foundation::Size GetLogicalSize() const { return m_logicalSize; }

float GetDpi() const { return m_effectiveDpi; }
bool IsDeviceRemoved() const { return m_deviceRemoved; }

// D3D Accessors.
ID3D12Device* GetD3DDevice() const { return m_d3dDevice.Get(); }
IDXGISwapChain3* GetSwapChain() const { return m_swapChain.Get(); }
ID3D12Resource* GetRenderTarget() const { return m_renderTargets[m_currentFrame].Get(); }
ID3D12Resource* GetDepthStencil() const { return m_depthStencil.Get(); }
ID3D12CommandQueue* GetCommandQueue() const { return m_commandQueue.Get(); }
ID3D12CommandAllocator* GetCommandAllocator() const { return m_commandAllocators[m_currentFrame].Get(); }
D3D12_VIEWPORT GetScreenViewport() const { return m_screenViewport; }
Expand All @@ -36,13 +41,19 @@ namespace DX
{
return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_currentFrame, m_rtvDescriptorSize);
}
CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const
{
return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
}

private:
void CreateDeviceIndependentResources();
void CreateDeviceResources();
void CreateWindowSizeDependentResources();
void UpdateRenderTargetSize();
void MoveToNextFrame();
DXGI_MODE_ROTATION ComputeDisplayRotation();
void GetHardwareAdapter(IDXGIFactory4* pFactory, IDXGIAdapter1** ppAdapter);

UINT m_currentFrame;

Expand All @@ -51,7 +62,9 @@ namespace DX
Microsoft::WRL::ComPtr<IDXGIFactory4> m_dxgiFactory;
Microsoft::WRL::ComPtr<IDXGISwapChain3> m_swapChain;
Microsoft::WRL::ComPtr<ID3D12Resource> m_renderTargets[c_frameCount];
Microsoft::WRL::ComPtr<ID3D12Resource> m_depthStencil;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> m_rtvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> m_dsvHeap;
UINT m_rtvDescriptorSize;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_commandAllocators[c_frameCount];
Expand All @@ -74,6 +87,9 @@ namespace DX
Windows::Graphics::Display::DisplayOrientations m_currentOrientation;
float m_dpi;

// This is the DPI that will be reported back to the app. It takes into account whether the app supports high resolution screens or not.
float m_effectiveDpi;

// Transforms used for display orientation.
DirectX::XMFLOAT4X4 m_orientationTransform3D;
};
Expand Down
13 changes: 8 additions & 5 deletions Templates/DirectX12App/Content/Sample3DSceneRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ void Sample3DSceneRenderer::CreateDeviceDependentResources()
state.PS = { &m_pixelShader[0], m_pixelShader.size() };
state.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
state.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
state.DepthStencilState.DepthEnable = FALSE;
state.DepthStencilState.StencilEnable = FALSE;
state.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
state.SampleMask = UINT_MAX;
state.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
state.NumRenderTargets = 1;
state.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
state.DSVFormat = DXGI_FORMAT_D32_FLOAT;
state.SampleDesc.Count = 1;

DX::ThrowIfFailed(m_deviceResources->GetD3DDevice()->CreateGraphicsPipelineState(&state, IID_PPV_ARGS(&m_pipelineState)));
Expand Down Expand Up @@ -229,7 +229,7 @@ void Sample3DSceneRenderer::CreateDeviceDependentResources()
UpdateSubresources(m_commandList.Get(), m_indexBuffer.Get(), indexBufferUpload.Get(), 0, 0, 1, &indexData);

CD3DX12_RESOURCE_BARRIER indexBufferResourceBarrier =
CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);
m_commandList->ResourceBarrier(1, &indexBufferResourceBarrier);
}

Expand Down Expand Up @@ -463,9 +463,12 @@ bool Sample3DSceneRenderer::Render()
m_commandList->ResourceBarrier(1, &renderTargetResourceBarrier);

// Record drawing commands.
m_commandList->ClearRenderTargetView(m_deviceResources->GetRenderTargetView(), DirectX::Colors::CornflowerBlue, 0, nullptr);
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView = m_deviceResources->GetRenderTargetView();
m_commandList->OMSetRenderTargets(1, &renderTargetView, false, nullptr);
D3D12_CPU_DESCRIPTOR_HANDLE depthStencilView = m_deviceResources->GetDepthStencilView();
m_commandList->ClearRenderTargetView(renderTargetView, DirectX::Colors::CornflowerBlue, 0, nullptr);
m_commandList->ClearDepthStencilView(depthStencilView, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);

m_commandList->OMSetRenderTargets(1, &renderTargetView, false, &depthStencilView);

m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
Expand Down

0 comments on commit 073e705

Please sign in to comment.