aboutsummaryrefslogtreecommitdiff
path: root/samples/D3D12/src/Viewer.cpp
diff options
context:
space:
mode:
authorlbavoil <[email protected]>2016-03-25 13:01:54 +0100
committerlbavoil <[email protected]>2016-03-25 13:01:54 +0100
commit99174e4e5fb4b7079da80b35a6dfd68f3fd56a1c (patch)
treefbcd4260d6c953d569a887505336a1c3f202e10f /samples/D3D12/src/Viewer.cpp
downloadhbaoplus-99174e4e5fb4b7079da80b35a6dfd68f3fd56a1c.tar.xz
hbaoplus-99174e4e5fb4b7079da80b35a6dfd68f3fd56a1c.zip
GFSDK_HBAO+_distro_r3.0_cl20573789
Diffstat (limited to 'samples/D3D12/src/Viewer.cpp')
-rw-r--r--samples/D3D12/src/Viewer.cpp1216
1 files changed, 1216 insertions, 0 deletions
diff --git a/samples/D3D12/src/Viewer.cpp b/samples/D3D12/src/Viewer.cpp
new file mode 100644
index 0000000..e445ffd
--- /dev/null
+++ b/samples/D3D12/src/Viewer.cpp
@@ -0,0 +1,1216 @@
+/*
+* Copyright (c) 2008-2016, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include <Windows.h>
+#include <tchar.h>
+#include <wrl/client.h>
+#include <stdexcept>
+#include <dxgi1_4.h>
+#include <d3d12.h>
+#include <d3dcompiler.h>
+#include <d3dx12.h>
+#include <d3dx12p.h>
+
+#include <DirectXMath.h>
+
+// For UI rendering
+#include <imgui.h>
+#include "imgui_impl_dx12.h"
+
+#include <string>
+#include <vector>
+
+// Header for HBAO+
+#include "GFSDK_SSAO.h"
+
+// Library link for HBAO+
+#ifdef _WIN64
+#pragma comment(lib, "GFSDK_SSAO_D3D12.win64.lib")
+#else
+#pragma comment(lib, "GFSDK_SSAO_D3D12.win32.lib")
+#endif
+
+// Use binary mesh reader or obj reader
+#define USE_BIN_MESH_READER 1
+
+// MSAA sample count for Viewer application
+#define MSAA_SAMPLE_COUNT 1
+
+#define SRC_PATH L"..\\src\\"
+#define HLSL_FILE_PATH SRC_PATH L"Viewer.hlsl"
+#define VERTEX_BIN_FILE_PATH SRC_PATH L"SibenikVertices.bin"
+#define INDEX_BIN_FILE_PATH SRC_PATH L"SibenikIndices.bin"
+
+using namespace std;
+using namespace DirectX;
+using Microsoft::WRL::ComPtr;
+
+struct Vertex
+{
+ DirectX::XMFLOAT3 position;
+ DirectX::XMFLOAT3 normal;
+ DirectX::XMFLOAT2 textureCoordinate;
+};
+
+struct Mesh
+{
+ std::vector<Vertex> vertices;
+ std::vector<uint32_t> indices;
+};
+
+// For mesh loading
+#if USE_BIN_MESH_READER
+#include "BinMeshReader.h"
+#else
+#include "WaveFrontReader.h"
+#endif
+
+#pragma comment(lib, "dxgi.lib")
+#pragma comment(lib, "d3d12.lib")
+#pragma comment(lib, "d3dcompiler.lib")
+
+namespace
+{
+ int gWindowWidth = 1280;
+ int gWindowHeight = 720;
+ bool gIsWindowed = true;
+ int gAdapterIndex = -1;
+ HWND gMainWindowHandle = 0;
+ float gCameraDistance = 1.0f;
+ float gModelRotation = 90.0f;
+ bool gUseSSAO = true;
+ bool gDrawUI = true;
+ std::string gSelectedGraphicsAdapter;
+ DXGI_FORMAT gColorTextureFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
+ DXGI_FORMAT gNormalTextureFormat = DXGI_FORMAT_R32G32B32A32_FLOAT;
+ DXGI_FORMAT gDepthTextureFormat = DXGI_FORMAT_D32_FLOAT;
+};
+
+void CHK(HRESULT hr)
+{
+ if (FAILED(hr))
+ throw runtime_error("HRESULT is failed value.");
+}
+
+class D3D
+{
+public:
+ // Number of swap chains
+ static const UINT FrameCount = 4;
+
+ ComPtr<IDXGIFactory4> mDxgiFactory;
+ ComPtr<IDXGISwapChain3> mSwapChain;
+
+ int mBufferWidth, mBufferHeight;
+ UINT mFrameIndex = 0;
+
+ ID3D12Device* mDev;
+ ComPtr<ID3D12CommandAllocator> mCmdAllocs[FrameCount];
+ ComPtr<ID3D12CommandQueue> mCmdQueue;
+
+ ComPtr<ID3D12GraphicsCommandList> mCmdList;
+
+ ComPtr<ID3D12Fence> mFence;
+ UINT64 mFenceValues[FrameCount];
+ HANDLE mFenceEvent = 0;
+
+ ComPtr<ID3D12DescriptorHeap> mDescHeapRtv;
+ ComPtr<ID3D12DescriptorHeap> mDescHeapDsv;
+ ComPtr<ID3D12DescriptorHeap> mDescHeapCbvSrvUav;
+ ComPtr<ID3D12DescriptorHeap> mDescHeapSampler;
+ ComPtr<ID3D12DescriptorHeap> mSsaoDescHeapCbvSrvUav;
+
+ ComPtr<ID3D12RootSignature> mRootSignature;
+ ComPtr<ID3D12PipelineState> mPso;
+
+ ComPtr<ID3D12Resource> mVB;
+ D3D12_VERTEX_BUFFER_VIEW mVBView = {};
+ D3D12_INDEX_BUFFER_VIEW mIBView = {};
+ UINT mIndexCount = 0;
+ UINT mVBIndexOffset = 0;
+
+ ComPtr<ID3D12Resource> mDepthBuffer;
+ ComPtr<ID3D12Resource> mConstantBuffer;
+ void* mCBUploadPtr = nullptr;
+
+ // Normal buffer and render target
+ ComPtr<ID3D12Resource> mNormalBuffer[FrameCount];
+ GFSDK_SSAO_RenderTargetView_D3D12 mNormalRTV[FrameCount];
+ GFSDK_SSAO_ShaderResourceView_D3D12 mNormalSRV[FrameCount];
+
+ // Color buffer and render target
+ ComPtr<ID3D12Resource> mColorBuffer[FrameCount];
+ GFSDK_SSAO_RenderTargetView_D3D12 mColorRTV[FrameCount];
+
+ // HBAO+ context and parameter
+ GFSDK_SSAO_Context_D3D12* mSSAO;
+ GFSDK_SSAO_Parameters mAOParams;
+
+public:
+ //--------------------------------------------------------------------------------
+ D3D(int Width, int Height, HWND hWnd, BOOL IsWindowed, INT AdapterIndex)
+ : mBufferWidth(Width), mBufferHeight(Height), mDev(nullptr), mFrameIndex(0), mSSAO(nullptr)
+ {
+ CHK(CreateDXGIFactory1(IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf())));
+
+#if _DEBUG
+ ID3D12Debug* debug = nullptr;
+ D3D12GetDebugInterface(IID_PPV_ARGS(&debug));
+ if (debug)
+ {
+ debug->EnableDebugLayer();
+ debug->Release();
+ debug = nullptr;
+ }
+#endif /* _DEBUG */
+
+ ZeroMemory(mFenceValues, sizeof(mFenceValues));
+
+ ID3D12Device* dev = nullptr;
+ bool UseWarpDevice = false;
+
+ if (UseWarpDevice)
+ {
+ ComPtr<IDXGIAdapter> warpAdapter;
+ CHK(mDxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter)));
+
+ CHK(D3D12CreateDevice(
+ warpAdapter.Get(),
+ D3D_FEATURE_LEVEL_11_0,
+ IID_PPV_ARGS(&dev)
+ ));
+ }
+ else
+ {
+ ComPtr<IDXGIAdapter> Adapter;
+ UINT NumAdapters = 0;
+ std::vector< ComPtr<IDXGIAdapter> > Adapters;
+ for (UINT idx = 0; mDxgiFactory->EnumAdapters(idx, Adapter.GetAddressOf()) != DXGI_ERROR_NOT_FOUND; ++idx)
+ {
+ DXGI_ADAPTER_DESC AdapterDesc;
+ Adapter->GetDesc(&AdapterDesc);
+ // GPU name : adapter_desc.Description
+ wchar_t buff[1024];
+ swprintf(buff, L"Graphics Adapter(%d) : %s\n", idx, &AdapterDesc.Description);
+ OutputDebugStringW(buff);
+ Adapters.push_back(Adapter);
+ NumAdapters++;
+ }
+
+ if ((AdapterIndex >= 0) && (AdapterIndex < (INT)NumAdapters))
+ {
+ Adapter = Adapters[AdapterIndex];
+ }
+ else
+ {
+ Adapter = Adapters[0];
+ }
+
+ DXGI_ADAPTER_DESC AdapterDesc;
+ Adapter->GetDesc(&AdapterDesc);
+ std::wstring DescW = AdapterDesc.Description;
+ std::string DescA = std::string(DescW.begin(), DescW.end());
+ gSelectedGraphicsAdapter = DescA;
+ Adapters.push_back(Adapter);
+
+ CHK(D3D12CreateDevice(Adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev)));
+ }
+
+ mDev = dev;
+
+ const UINT NodeMask = 1;
+
+ for (UINT n = 0; n < FrameCount; n++)
+ {
+ CHK(mDev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCmdAllocs[n])));
+ }
+
+ D3D12_COMMAND_QUEUE_DESC queueDesc = {};
+ queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+ queueDesc.NodeMask = NodeMask;
+ CHK(mDev->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(mCmdQueue.ReleaseAndGetAddressOf())));
+
+ CHK(mDev->CreateCommandList(NodeMask, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAllocs[mFrameIndex].Get(), nullptr, IID_PPV_ARGS(&mCmdList)));
+
+#define SSAO_NUM_DEPTH_SRV 1
+#define SSAO_NUM_NORMAL_SRV FrameCount
+#define SSAO_NUM_SRV (SSAO_NUM_DEPTH_SRV + SSAO_NUM_NORMAL_SRV + GFSDK_SSAO_NUM_DESCRIPTORS_CBV_SRV_UAV_HEAP_D3D12)
+
+#define IMGUI_NUM_CBV 1
+#define IMGUI_NUM_SRV 1
+
+#define VIEWER_NUM_CBV 1
+#define VIEWER_NUM_COLOR_RTV FrameCount
+#define VIEWER_NUM_NORMAL_RTV FrameCount
+
+#define VIEWER_NUM_RTV (VIEWER_NUM_COLOR_RTV + VIEWER_NUM_NORMAL_RTV)
+#define VIEWER_NUM_DSV 1
+#define VIEWER_NUM_SAMPLER 0
+
+ {
+ D3D12_DESCRIPTOR_HEAP_DESC desc = {};
+
+ desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
+ desc.NumDescriptors = VIEWER_NUM_RTV + GFSDK_SSAO_NUM_DESCRIPTORS_RTV_HEAP_D3D12;
+ desc.NodeMask = NodeMask;
+ CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapRtv.ReleaseAndGetAddressOf())));
+ mDescHeapRtv->SetName(L"ViewerDescHeapRtv");
+
+ desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
+ desc.NumDescriptors = VIEWER_NUM_DSV;
+ desc.NodeMask = NodeMask;
+ CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapDsv.ReleaseAndGetAddressOf())));
+ mDescHeapDsv->SetName(L"ViewerDescHeapDsv");
+
+ desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ desc.NumDescriptors = VIEWER_NUM_CBV + IMGUI_NUM_CBV + IMGUI_NUM_SRV;
+ desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+ desc.NodeMask = NodeMask;
+ CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapCbvSrvUav.ReleaseAndGetAddressOf())));
+ mDescHeapCbvSrvUav->SetName(L"ViewerDescHeapCbvSrvUav");
+
+ desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
+ desc.NumDescriptors = VIEWER_NUM_SAMPLER;
+ desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+ desc.NodeMask = NodeMask;
+ if (desc.NumDescriptors > 0)
+ {
+ CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapSampler.ReleaseAndGetAddressOf())));
+ mDescHeapSampler->SetName(L"ViewerDescHeapSampler");
+ }
+ }
+
+ // Create a desc heap for SSAO
+ {
+ D3D12_DESCRIPTOR_HEAP_DESC desc = {};
+
+ desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ desc.NumDescriptors = SSAO_NUM_SRV;
+ desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+ desc.NodeMask = NodeMask;
+ CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mSsaoDescHeapCbvSrvUav.ReleaseAndGetAddressOf())));
+ mSsaoDescHeapCbvSrvUav->SetName(L"ViewerSsaoDescHeapCbvSrvUav");
+ }
+
+ CHK(mDev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence.ReleaseAndGetAddressOf())));
+ mFence->SetName(L"ViewerFence");
+
+ mFenceValues[mFrameIndex]++;
+
+ mFenceEvent = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
+
+ ResizeD3D(hWnd, Width, Height, IsWindowed);
+
+ {
+ CD3DX12_DESCRIPTOR_RANGE descRange1[1];
+ descRange1[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
+
+ CD3DX12_ROOT_PARAMETER rootParam[1];
+ rootParam[0].InitAsDescriptorTable(ARRAYSIZE(descRange1), descRange1);
+
+ ID3D10Blob *sig, *info;
+ auto rootSigDesc = D3D12_ROOT_SIGNATURE_DESC();
+ rootSigDesc.NumParameters = 1;
+ rootSigDesc.NumStaticSamplers = 0;
+ rootSigDesc.pParameters = rootParam;
+ rootSigDesc.pStaticSamplers = nullptr;
+ rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+ CHK(D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &sig, &info));
+ mDev->CreateRootSignature(
+ 0,
+ sig->GetBufferPointer(),
+ sig->GetBufferSize(),
+ IID_PPV_ARGS(mRootSignature.ReleaseAndGetAddressOf()));
+ mRootSignature->SetName(L"ViewerRS");
+ sig->Release();
+ }
+
+ ID3D10Blob *vs, *ps;
+ {
+ ID3D10Blob *info;
+ UINT flag = 0;
+#if _DEBUG
+ flag |= D3DCOMPILE_DEBUG;
+#endif /* _DEBUG */
+ CHK(D3DCompileFromFile(HLSL_FILE_PATH, nullptr, nullptr, "VSMain", "vs_5_0", flag, 0, &vs, &info));
+ CHK(D3DCompileFromFile(HLSL_FILE_PATH, nullptr, nullptr, "PSMain", "ps_5_0", flag, 0, &ps, &info));
+ }
+ D3D12_INPUT_ELEMENT_DESC inputLayout[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ };
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.InputLayout.NumElements = 3;
+ psoDesc.InputLayout.pInputElementDescs = inputLayout;
+ psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
+ psoDesc.pRootSignature = mRootSignature.Get();
+ psoDesc.VS.pShaderBytecode = vs->GetBufferPointer();
+ psoDesc.VS.BytecodeLength = vs->GetBufferSize();
+ psoDesc.PS.pShaderBytecode = ps->GetBufferPointer();
+ psoDesc.PS.BytecodeLength = ps->GetBufferSize();
+ psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
+ psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
+ psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
+ psoDesc.DepthStencilState.DepthEnable = true;
+ psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
+ psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ psoDesc.DepthStencilState.StencilEnable = false;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = gNormalTextureFormat;
+ psoDesc.DSVFormat = gDepthTextureFormat;
+ psoDesc.SampleDesc.Count = MSAA_SAMPLE_COUNT;
+ CHK(mDev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(mPso.ReleaseAndGetAddressOf())));
+ mPso->SetName(L"ViewerPSO");
+ vs->Release();
+ ps->Release();
+
+#if (USE_BIN_MESH_READER)
+ Mesh mesh;
+ LoadVertices(VERTEX_BIN_FILE_PATH, mesh.vertices);
+ LoadIndices(INDEX_BIN_FILE_PATH, mesh.indices);
+#else
+ WaveFrontReader<uint32_t> mesh;
+ CHK(mesh.Load(L"sibenik.obj"));
+#endif
+
+ mIndexCount = static_cast<UINT>(mesh.indices.size());
+ mVBIndexOffset = static_cast<UINT>(sizeof(mesh.vertices[0]) * mesh.vertices.size());
+ UINT IBSize = static_cast<UINT>(sizeof(mesh.indices[0]) * mIndexCount);
+
+ void* vbData = mesh.vertices.data();
+ void* ibData = mesh.indices.data();
+ CHK(mDev->CreateCommittedResource(
+ &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
+ D3D12_HEAP_FLAG_NONE,
+ &CD3DX12_RESOURCE_DESC::Buffer(mVBIndexOffset + IBSize),
+ D3D12_RESOURCE_STATE_GENERIC_READ,
+ nullptr,
+ IID_PPV_ARGS(mVB.ReleaseAndGetAddressOf())));
+ mVB->SetName(L"VertexBuffer");
+
+ char* vbUploadPtr = nullptr;
+ CHK(mVB->Map(0, nullptr, reinterpret_cast<void**>(&vbUploadPtr)));
+ memcpy_s(vbUploadPtr, mVBIndexOffset, vbData, mVBIndexOffset);
+ memcpy_s(vbUploadPtr + mVBIndexOffset, IBSize, ibData, IBSize);
+ mVB->Unmap(0, nullptr);
+
+ mVBView.BufferLocation = mVB->GetGPUVirtualAddress();
+ mVBView.StrideInBytes = sizeof(mesh.vertices[0]);
+ mVBView.SizeInBytes = mVBIndexOffset;
+ mIBView.BufferLocation = mVB->GetGPUVirtualAddress() + mVBIndexOffset;
+ mIBView.Format = (sizeof(mesh.indices[0]) == 2) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
+ mIBView.SizeInBytes = IBSize;
+
+ // Constant buffer
+ CHK(mDev->CreateCommittedResource(
+ &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
+ D3D12_HEAP_FLAG_NONE,
+ &CD3DX12_RESOURCE_DESC::Buffer(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT),
+ D3D12_RESOURCE_STATE_GENERIC_READ,
+ nullptr,
+ IID_PPV_ARGS(mConstantBuffer.ReleaseAndGetAddressOf())));
+ mConstantBuffer->SetName(L"ViewerConstantBuffer");
+
+ D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
+ cbvDesc.BufferLocation = mConstantBuffer->GetGPUVirtualAddress();
+ cbvDesc.SizeInBytes = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT; // must be a multiple of 256
+ mDev->CreateConstantBufferView(&cbvDesc, mDescHeapCbvSrvUav->GetCPUDescriptorHandleForHeapStart());
+ CHK(mConstantBuffer->Map(0, nullptr, reinterpret_cast<void**>(&mCBUploadPtr)));
+
+ InitSSAO();
+
+ mAOParams = {};
+ mAOParams.Radius = 2.f;
+ mAOParams.Bias = 0.2f;
+ mAOParams.PowerExponent = 2.f;
+ mAOParams.Blur.Enable = true;
+ mAOParams.Blur.Sharpness = 32.f;
+ mAOParams.Blur.Radius = GFSDK_SSAO_BLUR_RADIUS_4;
+
+ ImGui_ImplDX12_Init(hWnd, dev, mCmdQueue.Get(), mCmdList.Get(), mDescHeapCbvSrvUav.Get(), VIEWER_NUM_CBV);
+ }
+
+ //--------------------------------------------------------------------------------
+ void Release()
+ {
+ ReleaseSSAO();
+ ImGui_ImplDX12_Shutdown();
+
+ mConstantBuffer->Unmap(0, nullptr);
+ CloseHandle(mFenceEvent);
+ for (UINT Idx = 0; Idx < FrameCount; ++Idx)
+ {
+ mCmdAllocs[Idx].Reset();
+ mColorBuffer[Idx].Reset();
+ mNormalBuffer[Idx].Reset();
+ }
+ mCmdList.Reset();
+ mFence.Reset();
+ mCmdQueue.Reset();
+ mSsaoDescHeapCbvSrvUav.Reset();
+ mDescHeapCbvSrvUav.Reset();
+ mDescHeapDsv.Reset();
+ mDescHeapRtv.Reset();
+ mDescHeapSampler.Reset();
+ if (mSwapChain)
+ {
+ mSwapChain->SetFullscreenState(FALSE, NULL);
+ mSwapChain.Reset();
+ }
+ mConstantBuffer.Reset();
+ mDepthBuffer.Reset();
+ mDxgiFactory.Reset();
+ mPso.Reset();
+ mRootSignature.Reset();
+ mVB.Reset();
+ }
+
+ //--------------------------------------------------------------------------------
+ ~D3D()
+ {
+ Release();
+ }
+
+ //--------------------------------------------------------------------------------
+ void ResizeD3D(HWND hWnd, int Width, int Height, BOOL IsWindowed)
+ {
+ if (!mDev)
+ {
+ return;
+ }
+
+ DXGI_SWAP_CHAIN_DESC scDesc = {};
+ scDesc.BufferCount = FrameCount;
+ scDesc.BufferDesc.Width = Width;
+ scDesc.BufferDesc.Height = Height;
+ scDesc.BufferDesc.Format = gColorTextureFormat;
+ scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ //scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; // For better framerate in windowed mode, but it won't allow fullscreen switching
+ scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+ scDesc.OutputWindow = hWnd;
+ scDesc.SampleDesc.Count = 1;
+ scDesc.SampleDesc.Quality = 0;
+ scDesc.Windowed = IsWindowed;
+
+ WaitForGpuIdle();
+
+ // Release color/normal render targets before calling ResizeBuffers().
+ // Also reset the frame fence values.
+ for (UINT Idx = 0; Idx < FrameCount; ++Idx)
+ {
+ mColorBuffer[Idx].Reset();
+ mNormalBuffer[Idx].Reset();
+ mFenceValues[Idx] = mFenceValues[mFrameIndex];
+ }
+
+ ComPtr<IDXGISwapChain> swapChain;
+ if (!mSwapChain)
+ {
+ CHK(mDxgiFactory->CreateSwapChain(mCmdQueue.Get(), &scDesc, &swapChain));
+ swapChain.As(&mSwapChain);
+ }
+
+ DXGI_SWAP_CHAIN_DESC desc = {};
+ mSwapChain->GetDesc(&desc);
+ CHK(mSwapChain->ResizeBuffers(FrameCount, Width, Height, gColorTextureFormat, desc.Flags));
+
+ mBufferWidth = Width;
+ mBufferHeight = Height;
+
+ mFrameIndex = mSwapChain->GetCurrentBackBufferIndex();
+
+ for (UINT i = 0; i < FrameCount; i++)
+ {
+ CHK(mSwapChain->GetBuffer(i, IID_PPV_ARGS(mColorBuffer[i].ReleaseAndGetAddressOf())));
+ mColorBuffer[i]->SetName(L"SwapChain_Buffer");
+ }
+
+ for (UINT FrameIndex = 0; FrameIndex < FrameCount; ++FrameIndex)
+ {
+ // Create color buffer RTV
+ {
+ D3D12_RENDER_TARGET_VIEW_DESC colorRTVDesc = {};
+ colorRTVDesc.Format = gColorTextureFormat;
+ colorRTVDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
+
+ CD3DX12_CPU_DESCRIPTOR_HANDLE ColorRTV(
+ mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(),
+ FrameIndex * mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
+ mDev->CreateRenderTargetView(mColorBuffer[FrameIndex].Get(), &colorRTVDesc, ColorRTV);
+
+ mColorRTV[FrameIndex] = {};
+ mColorRTV[FrameIndex].CpuHandle = ColorRTV.ptr;
+ mColorRTV[FrameIndex].pResource = mColorBuffer[FrameIndex].Get();
+ }
+ }
+
+ // Create depth buffer and SRV
+ {
+ // Create depth resource
+ {
+ D3D12_RESOURCE_DESC resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D(
+ DXGI_FORMAT_R32_TYPELESS, mBufferWidth, mBufferHeight, 1, 1, MSAA_SAMPLE_COUNT, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL,
+ D3D12_TEXTURE_LAYOUT_UNKNOWN, 0);
+
+ D3D12_CLEAR_VALUE dsvClearValue;
+ dsvClearValue.Format = gDepthTextureFormat;
+ dsvClearValue.DepthStencil.Depth = 1.0f;
+ dsvClearValue.DepthStencil.Stencil = 0;
+
+ CHK(mDev->CreateCommittedResource(
+ &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // No need to read/write by CPU
+ D3D12_HEAP_FLAG_NONE,
+ &resourceDesc,
+ D3D12_RESOURCE_STATE_COMMON,
+ &dsvClearValue,
+ IID_PPV_ARGS(mDepthBuffer.ReleaseAndGetAddressOf())));
+ mDepthBuffer->SetName(L"DepthTexture");
+ }
+
+ // Depth DSV
+ {
+ D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
+#if MSAA_SAMPLE_COUNT > 1
+ dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;
+#else
+ dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
+#endif
+ dsvDesc.Format = gDepthTextureFormat;
+ dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
+
+ CD3DX12_CPU_DESCRIPTOR_HANDLE DepthDSV(mDescHeapDsv->GetCPUDescriptorHandleForHeapStart());
+ mDev->CreateDepthStencilView(mDepthBuffer.Get(), &dsvDesc, DepthDSV);
+ }
+
+ // Depth SRV
+ {
+ D3D12_SHADER_RESOURCE_VIEW_DESC depthSRVDesc = {};
+
+ depthSRVDesc.Format = DXGI_FORMAT_R32_FLOAT;
+ depthSRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+#if MSAA_SAMPLE_COUNT > 1
+ depthSRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
+#else
+ depthSRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+ depthSRVDesc.Texture2D.MipLevels = 1;
+ depthSRVDesc.Texture2D.MostDetailedMip = 0; // No MIP
+ depthSRVDesc.Texture2D.PlaneSlice = 0;
+ depthSRVDesc.Texture2D.ResourceMinLODClamp = 0.0f;
+#endif
+
+ CD3DX12_CPU_DESCRIPTOR_HANDLE DepthSRV(
+ mSsaoDescHeapCbvSrvUav->GetCPUDescriptorHandleForHeapStart());
+ mDev->CreateShaderResourceView(mDepthBuffer.Get(), &depthSRVDesc, DepthSRV);
+ }
+ }
+
+ // Normal render targets
+ for (UINT FrameIndex = 0; FrameIndex < FrameCount; ++FrameIndex)
+ {
+ D3D12_RESOURCE_DESC NormalRTVDesc = CD3DX12_RESOURCE_DESC::Tex2D(
+ gNormalTextureFormat, mBufferWidth, mBufferHeight, 1, 1, MSAA_SAMPLE_COUNT, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
+ D3D12_TEXTURE_LAYOUT_UNKNOWN, 0);
+
+ FLOAT ClearColor[] = { 0, 0, 0, 1.0f };
+ CD3DX12_CLEAR_VALUE NormalClearValue(NormalRTVDesc.Format, ClearColor);
+ mDev->CreateCommittedResource(
+ &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE,
+ &NormalRTVDesc, D3D12_RESOURCE_STATE_COMMON, &NormalClearValue, IID_PPV_ARGS(mNormalBuffer[FrameIndex].ReleaseAndGetAddressOf()));
+ mNormalBuffer[FrameIndex]->SetName(L"NormalBuffer");
+
+ // SRV
+ D3D12_SHADER_RESOURCE_VIEW_DESC NormalSRVDesc = {};
+ NormalSRVDesc.Format = NormalRTVDesc.Format;
+ NormalSRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+#if MSAA_SAMPLE_COUNT > 1
+ NormalSRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
+#else
+ NormalSRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+ NormalSRVDesc.Texture2D.MipLevels = 1;
+ NormalSRVDesc.Texture2D.MostDetailedMip = 0; // No MIP
+ NormalSRVDesc.Texture2D.PlaneSlice = 0;
+ NormalSRVDesc.Texture2D.ResourceMinLODClamp = 0.0f;
+#endif
+
+ mNormalSRV[FrameIndex] = {};
+ mNormalSRV[FrameIndex].pResource = mNormalBuffer[FrameIndex].Get();
+ CD3DX12_CPU_DESCRIPTOR_HANDLE NormalSRVHandle(
+ mSsaoDescHeapCbvSrvUav->GetCPUDescriptorHandleForHeapStart(),
+ SSAO_NUM_DEPTH_SRV + FrameIndex,
+ mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));
+ mDev->CreateShaderResourceView(mNormalBuffer[FrameIndex].Get(), &NormalSRVDesc, NormalSRVHandle);
+
+ // RTV
+ D3D12_RENDER_TARGET_VIEW_DESC normalRTVDesc = {};
+ normalRTVDesc.Format = NormalRTVDesc.Format;
+#if MSAA_SAMPLE_COUNT > 1
+ normalRTVDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
+#else
+ normalRTVDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
+ normalRTVDesc.Texture2D.MipSlice = 0;
+#endif
+ mNormalRTV[FrameIndex] = {};
+ mNormalRTV[FrameIndex].pResource = mNormalBuffer[FrameIndex].Get();
+ mNormalRTV[FrameIndex].CpuHandle = CD3DX12_CPU_DESCRIPTOR_HANDLE(
+ mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(),
+ VIEWER_NUM_COLOR_RTV + FrameIndex,
+ mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV)).ptr;
+ mDev->CreateRenderTargetView(mNormalBuffer[FrameIndex].Get(), &normalRTVDesc, { mNormalRTV[FrameIndex].CpuHandle });
+ }
+ }
+
+ void InitSSAO()
+ {
+ const UINT NodeMask = 1;
+
+ GFSDK_SSAO_CustomHeap CustomHeap;
+ CustomHeap.new_ = ::operator new;
+ CustomHeap.delete_ = ::operator delete;
+
+ GFSDK_SSAO_DescriptorHeaps_D3D12 DescriptorHeaps;
+
+ DescriptorHeaps.CBV_SRV_UAV.pDescHeap = mSsaoDescHeapCbvSrvUav.Get();
+ DescriptorHeaps.CBV_SRV_UAV.BaseIndex = SSAO_NUM_DEPTH_SRV + SSAO_NUM_NORMAL_SRV;
+ DescriptorHeaps.CBV_SRV_UAV.NumDescriptors = GFSDK_SSAO_NUM_DESCRIPTORS_CBV_SRV_UAV_HEAP_D3D12;
+
+ DescriptorHeaps.RTV.pDescHeap = mDescHeapRtv.Get();
+ DescriptorHeaps.RTV.BaseIndex = VIEWER_NUM_RTV;
+ DescriptorHeaps.RTV.NumDescriptors = GFSDK_SSAO_NUM_DESCRIPTORS_RTV_HEAP_D3D12;
+
+ GFSDK_SSAO_Status status = GFSDK_SSAO_CreateContext_D3D12(mDev, NodeMask, DescriptorHeaps, &mSSAO, &CustomHeap);
+ assert(status == GFSDK_SSAO_OK);
+ }
+
+ void ReleaseSSAO()
+ {
+ if (mSSAO)
+ {
+ mSSAO->Release();
+ mSSAO = nullptr;
+ }
+ }
+
+ //--------------------------------------------------------------------------------
+ ID3D12Device* GetDevice() const
+ {
+ return mDev;
+ }
+
+ void WaitForGpuIdle()
+ {
+ // Schedule a Signal command in the queue.
+ const UINT64 currentFenceValue = mFenceValues[mFrameIndex];
+ CHK(mCmdQueue->Signal(mFence.Get(), currentFenceValue));
+
+ CHK(mFence->SetEventOnCompletion(mFenceValues[mFrameIndex], mFenceEvent));
+ WaitForSingleObjectEx(mFenceEvent, INFINITE, FALSE);
+ }
+
+ //--------------------------------------------------------------------------------
+ void Draw()
+ {
+ // Upload constant buffer
+ XMMATRIX ViewMat, ProjMat, WorldMat, ViewProjMat;
+ {
+#if USE_BIN_MESH_READER
+ ViewMat = XMMatrixIdentity();
+ WorldMat = XMMatrixIdentity();
+#else
+ WorldMat = XMMatrixRotationY(XMConvertToRadians(gModelRotation));
+ ViewMat = XMMatrixLookAtLH({ 0, 1, gCameraDistance }, { 0, 0, 0 }, { 0, 1, 0 });
+#endif
+
+ float nearPlane = .01f;
+ float farPlane = 500.0f;
+ ProjMat = XMMatrixPerspectiveFovLH(40 * 3.141592f / 180.f, (float)mBufferWidth / mBufferHeight, nearPlane, farPlane);
+ XMMATRIX MVPTransMat = XMMatrixTranspose(WorldMat * ViewMat * ProjMat);
+ XMMATRIX WorldTransMat = XMMatrixTranspose(WorldMat);
+
+ ViewProjMat = XMMatrixMultiply(ViewMat, ProjMat);
+
+ // mCBUploadPtr is Write-Combine memory
+ memcpy_s(mCBUploadPtr, 64, &MVPTransMat, 64);
+ memcpy_s(reinterpret_cast<char*>(mCBUploadPtr) + 64, 64, &WorldTransMat, 64);
+ }
+
+ // Get current RTV descriptor
+ CD3DX12_CPU_DESCRIPTOR_HANDLE descHandleRtv(
+ mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(),
+ mFrameIndex,
+ mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
+
+ // Get current swap chain
+ ID3D12Resource* ColorBuffer = mColorBuffer[mFrameIndex].Get();
+ ID3D12Resource* DepthBuffer = mDepthBuffer.Get();
+
+ // Get DSV
+ CD3DX12_CPU_DESCRIPTOR_HANDLE DepthDSV(mDescHeapDsv->GetCPUDescriptorHandleForHeapStart());
+
+ SetResourceBarrier(mCmdList.Get(), ColorBuffer, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+ SetResourceBarrier(mCmdList.Get(), DepthBuffer, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE);
+
+ // Viewport & Scissor
+ D3D12_VIEWPORT viewport = {};
+ viewport.Width = (float)mBufferWidth;
+ viewport.Height = (float)mBufferHeight;
+ viewport.MinDepth = 0.0f;
+ viewport.MaxDepth = 1.0f;
+ mCmdList->RSSetViewports(1, &viewport);
+ D3D12_RECT scissor = {};
+ scissor.right = (LONG)mBufferWidth;
+ scissor.bottom = (LONG)mBufferHeight;
+ mCmdList->RSSetScissorRects(1, &scissor);
+
+ // Clear DepthTexturesh
+ mCmdList->ClearDepthStencilView(DepthDSV, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
+
+ // Draw the geometry
+ D3D12_CPU_DESCRIPTOR_HANDLE RTVs[] = { { mNormalRTV[mFrameIndex].CpuHandle } };
+ mCmdList->OMSetRenderTargets(ARRAYSIZE(RTVs), RTVs, false, &DepthDSV);
+
+ mCmdList->SetGraphicsRootSignature(mRootSignature.Get());
+ ID3D12DescriptorHeap* descHeaps[] = { mDescHeapCbvSrvUav.Get() };
+ mCmdList->SetDescriptorHeaps(ARRAYSIZE(descHeaps), descHeaps);
+
+ mCmdList->SetGraphicsRootDescriptorTable(0, mDescHeapCbvSrvUav->GetGPUDescriptorHandleForHeapStart());
+ mCmdList->SetPipelineState(mPso.Get());
+ mCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ mCmdList->IASetVertexBuffers(0, 1, &mVBView);
+ mCmdList->IASetIndexBuffer(&mIBView);
+ mCmdList->DrawIndexedInstanced(mIndexCount, 1, 0, 0, 0);
+
+ SetResourceBarrier(mCmdList.Get(), DepthBuffer, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+
+ if (gUseSSAO)
+ {
+ // Set input data
+ GFSDK_SSAO_InputData_D3D12 InputData = {};
+ InputData.DepthData.DepthTextureType = GFSDK_SSAO_HARDWARE_DEPTHS;
+
+ // FullResDepthTextureSRV
+ {
+ CD3DX12_GPU_DESCRIPTOR_HANDLE DepthSrvGpuHandle(
+ mSsaoDescHeapCbvSrvUav->GetGPUDescriptorHandleForHeapStart());
+ InputData.DepthData.FullResDepthTextureSRV.pResource = DepthBuffer;
+ InputData.DepthData.FullResDepthTextureSRV.GpuHandle = DepthSrvGpuHandle.ptr;
+ }
+
+ // DepthData
+ InputData.DepthData.ProjectionMatrix.Data = GFSDK_SSAO_Float4x4((const GFSDK_SSAO_FLOAT*)&ProjMat);
+ InputData.DepthData.ProjectionMatrix.Layout = GFSDK_SSAO_ROW_MAJOR_ORDER;
+
+#if USE_BIN_MESH_READER
+ InputData.DepthData.MetersToViewSpaceUnits = 0.005f;
+#else
+ InputData.DepthData.MetersToViewSpaceUnits = 1.f;
+#endif
+
+ // NormalData
+ {
+ CD3DX12_GPU_DESCRIPTOR_HANDLE NormalSrvGpuHandle(
+ mSsaoDescHeapCbvSrvUav->GetGPUDescriptorHandleForHeapStart(),
+ SSAO_NUM_DEPTH_SRV + mFrameIndex,
+ mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));
+
+ mNormalSRV[mFrameIndex].GpuHandle = NormalSrvGpuHandle.ptr;
+
+#if USE_BIN_MESH_READER
+ InputData.NormalData.Enable = false;
+#else
+ InputData.NormalData.Enable = true;
+#endif
+
+ if (InputData.NormalData.Enable)
+ {
+ InputData.NormalData.WorldToViewMatrix.Data = GFSDK_SSAO_Float4x4((const GFSDK_SSAO_FLOAT*)&ViewMat);
+ InputData.NormalData.WorldToViewMatrix.Layout = GFSDK_SSAO_ROW_MAJOR_ORDER;
+ InputData.NormalData.FullResNormalTextureSRV = mNormalSRV[mFrameIndex];
+ }
+ }
+
+ //GFSDK_SSAO_RenderMask RenderMask = GFSDK_SSAO_RENDER_DEBUG_NORMAL;
+ GFSDK_SSAO_RenderMask RenderMask = GFSDK_SSAO_RENDER_AO;
+
+ // Set SSAO descriptor heap
+ {
+ ID3D12DescriptorHeap* descHeaps[] = { mSsaoDescHeapCbvSrvUav.Get() };
+ mCmdList->SetDescriptorHeaps(ARRAYSIZE(descHeaps), descHeaps);
+ }
+
+ GFSDK_SSAO_Output_D3D12 Output;
+ Output.pRenderTargetView = &mColorRTV[mFrameIndex];
+
+ GFSDK_SSAO_Status status = mSSAO->RenderAO(mCmdQueue.Get(), mCmdList.Get(), InputData, mAOParams, Output, RenderMask);
+ assert(status == GFSDK_SSAO_OK);
+
+ // Revert to the original descriptor heap
+ {
+ ID3D12DescriptorHeap* descHeaps[] = { mDescHeapCbvSrvUav.Get() };
+ mCmdList->SetDescriptorHeaps(ARRAYSIZE(descHeaps), descHeaps);
+ }
+ }
+
+ if (gDrawUI)
+ {
+ D3D12_CPU_DESCRIPTOR_HANDLE RTVs[] = { mColorRTV[mFrameIndex].CpuHandle };
+
+ mCmdList->OMSetRenderTargets(ARRAYSIZE(RTVs), RTVs, false, nullptr);
+ DrawUI();
+ }
+
+ // Barrier RenderTarget -> Present
+ SetResourceBarrier(mCmdList.Get(), ColorBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+
+ // Exec
+ CHK(mCmdList->Close());
+ ID3D12CommandList* const cmdList = mCmdList.Get();
+ mCmdQueue->ExecuteCommandLists(1, &cmdList);
+
+ // Present
+ CHK(mSwapChain->Present(0, 0));
+
+ // Move to next frame
+ {
+ // Schedule a Signal command in the queue.
+ const UINT64 currentFenceValue = mFenceValues[mFrameIndex];
+ CHK(mCmdQueue->Signal(mFence.Get(), currentFenceValue));
+
+ // Update the frame index.
+ mFrameIndex = mSwapChain->GetCurrentBackBufferIndex();
+
+ // If the next frame is not ready to be rendered yet, wait until it is ready.
+ UINT64 CompletedValue = mFence->GetCompletedValue();
+ if (CompletedValue < mFenceValues[mFrameIndex])
+ {
+ CHK(mFence->SetEventOnCompletion(mFenceValues[mFrameIndex], mFenceEvent));
+ WaitForSingleObjectEx(mFenceEvent, INFINITE, FALSE);
+ }
+
+ // Set the fence value for the next frame.
+ mFenceValues[mFrameIndex] = currentFenceValue + 1;
+ }
+
+ // Command list allocators can only be reset when the associated
+ // command lists have finished execution on the GPU; apps should use
+ // fences to determine GPU execution progress.
+ CHK(mCmdAllocs[mFrameIndex]->Reset());
+
+ // However, when ExecuteCommandList() is called on a particular command
+ // list, that command list can then be reset at any time and must be before
+ // re-recording.
+ CHK(mCmdList->Reset(mCmdAllocs[mFrameIndex].Get(), nullptr));
+ }
+
+ //--------------------------------------------------------------------------------
+ void DrawUI()
+ {
+ // Draw UI
+ ImGui_ImplDX12_NewFrame();
+
+ bool show_ssao_window = true;
+ bool show_test_window = false;
+
+ // Show SSAO property window
+ if (show_ssao_window)
+ {
+ ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiSetCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiSetCond_FirstUseEver);
+ ImGui::Begin("HBAO+", &show_ssao_window);
+
+ GFSDK_SSAO_Version Version;
+ GFSDK_SSAO_Status Status;
+ Status = GFSDK_SSAO_GetVersion(&Version);
+ assert(Status == GFSDK_SSAO_OK);
+
+ ImGui::Text("D3D12 HBAO+ %d.%d.%d.%d", Version.Major, Version.Minor, Version.Branch, Version.Revision);
+
+ ImGui::Text("%s", gSelectedGraphicsAdapter.c_str());
+#if MSAA_SAMPLE_COUNT > 1
+ ImGui::Text("%dx MSAA", MSAA_SAMPLE_COUNT);
+#endif
+ ImGui::Text("%.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
+
+ float radius = mAOParams.Radius;
+ ImGui::DragFloat("Radius", &radius, 0.05f, 0.0f, 100.0f);
+ if (radius != mAOParams.Radius)
+ {
+ mAOParams.Radius = radius;
+ int stop = 0;
+ stop = stop;
+ }
+ ImGui::DragFloat("PowerExponent", &mAOParams.PowerExponent, 0.05f, 1.f, 8.f);
+ ImGui::DragFloat("Bias", &mAOParams.Bias, 0.001f, 0, 0.5f);
+
+ ImGui::DragFloat("NearAO", &mAOParams.NearAO, 0.01f, 1.f, 2.f);
+ ImGui::DragFloat("FarAO", &mAOParams.FarAO, 0.01f, 1.f, 2.f);
+
+ bool BlurEnabled = mAOParams.Blur.Enable ? true : false;
+ ImGui::Checkbox("Blur.Enable", &BlurEnabled);
+ mAOParams.Blur.Enable = BlurEnabled;
+
+ const char* listbox_items[] = { "GFSDK_SSAO_BLUR_RADIUS_2", "GFSDK_SSAO_BLUR_RADIUS_4" };
+ int listbox_item_current = (int)mAOParams.Blur.Radius;
+ ImGui::ListBox("Blur.Radius", &listbox_item_current, listbox_items, ARRAYSIZE(listbox_items), 2);
+ mAOParams.Blur.Radius = (GFSDK_SSAO_BlurRadius)(listbox_item_current);
+
+ ImGui::DragFloat("Blur.Sharpness", &mAOParams.Blur.Sharpness, 0.f, 0.f, 32.0f);
+
+ ImGui::End();
+ }
+
+ // Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
+ if (show_test_window)
+ {
+ ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
+ ImGui::ShowTestWindow(&show_test_window);
+ }
+
+ ImGui::Render();
+ }
+
+private:
+ void SetResourceBarrier(ID3D12GraphicsCommandList* commandList,
+ ID3D12Resource* res,
+ D3D12_RESOURCE_STATES before,
+ D3D12_RESOURCE_STATES after)
+ {
+ D3D12_RESOURCE_BARRIER desc = {};
+ desc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ desc.Transition.pResource = res;
+ desc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+ desc.Transition.StateBefore = before;
+ desc.Transition.StateAfter = after;
+ desc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+ commandList->ResourceBarrier(1, &desc);
+ }
+};
+
+D3D* gD3D = nullptr;
+
+extern LRESULT ImGui_ImplDX12_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+//--------------------------------------------------------------------------------
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static WORD sLastX = 0, sLastY = 0;
+
+ ImGui_ImplDX12_WndProcHandler(hWnd, message, wParam, lParam);
+
+ switch (message)
+ {
+ case WM_SIZE:
+ {
+ if (gD3D)
+ {
+ BOOL IsFullScreen = FALSE;
+ if (gD3D->mSwapChain) {
+ gD3D->mSwapChain->GetFullscreenState(&IsFullScreen, NULL);
+ }
+ gD3D->ResizeD3D(hWnd, LOWORD(lParam), HIWORD(lParam), !IsFullScreen);
+ }
+ }
+ break;
+ case WM_KEYDOWN:
+ if (wParam == VK_ESCAPE)
+ {
+ gDrawUI = !gDrawUI;
+ //PostMessage(hWnd, WM_DESTROY, 0, 0);
+ //return 0;
+ }
+ if (wParam == VK_F5)
+ {
+ gD3D->ReleaseSSAO();
+ gD3D->InitSSAO();
+ OutputDebugStringA("SSAO Reloaded\n");
+ }
+ if (wParam == 'W')
+ {
+ gCameraDistance -= 0.1f;
+ }
+ else if (wParam == 'S')
+ {
+ gCameraDistance += 0.1f;
+ }
+
+ break;
+
+ case WM_MOUSEMOVE:
+ {
+ WORD x = LOWORD(lParam);
+ WORD y = HIWORD(lParam);
+
+ if (wParam & MK_RBUTTON)
+ {
+ gModelRotation -= float(x - sLastX);
+ }
+ sLastX = x;
+ sLastY = y;
+ }
+ break;
+ case WM_PAINT:
+ if (gD3D) gD3D->Draw();
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+//--------------------------------------------------------------------------------
+void FitToDesiredClientSize(HWND hwnd, int Width, int Height, DWORD window_style, bool has_menu)
+{
+ RECT current_win_rect;
+ ::GetWindowRect(hwnd, &current_win_rect);
+ RECT desired_rect = current_win_rect;
+ desired_rect.right = current_win_rect.left + Width;
+ desired_rect.bottom = current_win_rect.top + Height;
+ ::AdjustWindowRect(&desired_rect, window_style, (has_menu) ? TRUE : FALSE);
+ Width = desired_rect.right - desired_rect.left;
+ Height = desired_rect.bottom - desired_rect.top;
+ ::SetWindowLongPtr(hwnd, GWL_STYLE, window_style);
+ ::SetWindowPos(hwnd, HWND_TOP, 0, 0, Width, Height, SWP_SHOWWINDOW);
+}
+
+//--------------------------------------------------------------------------------
+static HWND SetupWindow(int Width, int Height, bool IsWindowed)
+{
+ WNDCLASSEX wcex;
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = (HMODULE)GetModuleHandle(0);
+ wcex.hIcon = nullptr;
+ wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcex.lpszMenuName = nullptr;
+ wcex.lpszClassName = _T("WindowClass");
+ wcex.hIconSm = nullptr;
+ if (!RegisterClassEx(&wcex))
+ {
+ throw runtime_error("RegisterClassEx()");
+ }
+
+ DWORD windowStyle = WS_OVERLAPPEDWINDOW;
+ HWND hWnd = CreateWindowEx(
+ 0, // WS_EX_TOPMOST,
+ _T("WindowClass"), _T("HBAO+ DX12"),
+ windowStyle,
+ 0, 0, Width, Height,
+ nullptr, nullptr, nullptr, nullptr);
+ if (!hWnd)
+ {
+ throw runtime_error("CreateWindow()");
+ }
+
+ if (IsWindowed)
+ {
+ FitToDesiredClientSize(hWnd, Width, Height, windowStyle, false);
+ }
+
+ return hWnd;
+}
+
+//--------------------------------------------------------------------------------
+int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR CmdLine, int)
+{
+ MSG msg;
+ ZeroMemory(&msg, sizeof msg);
+
+ ID3D12Device* dev = nullptr;
+
+ std::vector<std::string> arguments;
+ if (CmdLine)
+ {
+ char buff[1024];
+ strcpy(buff, CmdLine);
+ char * pch = strtok(buff, " ");
+ while (pch != NULL)
+ {
+ arguments.push_back(pch);
+ pch = strtok(NULL, " ");
+ }
+ }
+
+ for (size_t idx = 0; idx < arguments.size(); ++idx)
+ {
+ std::string arg = arguments[idx];
+ if (_stricmp(arg.c_str(), "-width") == 0)
+ {
+ gWindowWidth = atoi(arguments[idx + 1].c_str());
+ idx++;
+ }
+ else if (_stricmp(arg.c_str(), "-height") == 0)
+ {
+ gWindowHeight = atoi(arguments[idx + 1].c_str());
+ idx++;
+ }
+ else if (_stricmp(arg.c_str(), "-window") == 0)
+ {
+ gIsWindowed = (atoi(arguments[idx + 1].c_str()) == 1) ? true : false;
+ idx++;
+ }
+ else if (_stricmp(arg.c_str(), "-ui") == 0)
+ {
+ gDrawUI = (atoi(arguments[idx + 1].c_str()) == 1) ? true : false;
+ idx++;
+ }
+ else if (_stricmp(arg.c_str(), "-adapter") == 0)
+ {
+ gAdapterIndex = (atoi(arguments[idx + 1].c_str()) == 1) ? true : false;
+ idx++;
+ }
+ }
+
+#ifdef NDEBUG
+ try
+#endif
+ {
+ gMainWindowHandle = SetupWindow(gWindowWidth, gWindowHeight, gIsWindowed);
+ ShowWindow(gMainWindowHandle, SW_SHOW);
+ UpdateWindow(gMainWindowHandle);
+
+ gD3D = new D3D(gWindowWidth, gWindowHeight, gMainWindowHandle, gIsWindowed, gAdapterIndex);
+ dev = gD3D->GetDevice();
+
+ while (msg.message != WM_QUIT)
+ {
+ if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+#ifdef NDEBUG
+ catch (std::exception &e)
+ {
+ MessageBoxA(gMainWindowHandle, e.what(), "Exception occured.", MB_ICONSTOP);
+ }
+#endif
+
+ if (gD3D)
+ delete gD3D;
+
+ if (dev)
+ dev->Release();
+
+ return static_cast<int>(msg.wParam);
+}