summaryrefslogtreecommitdiffstats
path: root/tools/render-test/render-d3d12.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/render-test/render-d3d12.cpp')
-rw-r--r--tools/render-test/render-d3d12.cpp337
1 files changed, 337 insertions, 0 deletions
diff --git a/tools/render-test/render-d3d12.cpp b/tools/render-test/render-d3d12.cpp
new file mode 100644
index 000000000..2308c601a
--- /dev/null
+++ b/tools/render-test/render-d3d12.cpp
@@ -0,0 +1,337 @@
+// render-d3d12.cpp
+#include "render-d3d12.h"
+
+#include "options.h"
+#include "render.h"
+
+// In order to use the Slang API, we need to include its header
+
+#include <slang.h>
+
+// We will be rendering with Direct3D 12, so we need to include
+// the Windows and D3D12 headers
+
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <Windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#undef NOMINMAX
+
+#include <dxgi1_4.h>
+#include <d3d12.h>
+#include <d3dcompiler.h>
+
+// We will use the C standard library just for printing error messages.
+#include <stdio.h>
+
+#ifdef _MSC_VER
+#include <stddef.h>
+#if (_MSC_VER < 1900)
+#define snprintf sprintf_s
+#endif
+#endif
+//
+using namespace Slang;
+
+#define ENABLE_DEBUG_LAYER 1
+
+namespace renderer_test {
+
+// The Slang compiler currently generates HLSL source, so we'll need a utility
+// routine (defined later) to translate that into D3D11 shader bytecode.
+ID3DBlob* compileHLSLShader(
+ char const* sourcePath,
+ char const* source,
+ char const* entryPointName,
+ char const* dxProfileName);
+
+static char const* vertexProfileName = "vs_4_0";
+static char const* fragmentProfileName = "ps_4_0";
+
+//
+
+class D3D12Renderer : public Renderer, public ShaderCompiler
+{
+public:
+ IDXGISwapChain* dxSwapChain = NULL;
+
+ ID3D12Device* dxDevice = NULL;
+
+ virtual PROC loadProc(
+ HMODULE module,
+ char const* name)
+ {
+ PROC proc = GetProcAddress(module, name);
+ if( !proc )
+ {
+ fprintf(stderr,
+ "error: failed load symbol '%s'\n", name);
+ exit(1);
+ }
+ return proc;
+ }
+
+ void checkResult(HRESULT result)
+ {
+ assert(SUCCEEDED(result));
+ }
+
+ virtual void initialize(void* inWindowHandle) override
+ {
+ auto windowHandle = (HWND) inWindowHandle;
+ // Rather than statically link against D3D, we load it dynamically.
+
+ HMODULE d3d12 = LoadLibraryA("d3d12.dll");
+ if(!d3d12)
+ {
+ fprintf(stderr, "error: failed load 'd3d12.dll'\n");
+ exit(1);
+ }
+
+#define LOAD_PROC(TYPE, NAME) \
+ TYPE NAME##_ = (TYPE) loadProc(d3d12, #NAME)
+
+
+ UINT dxgiFactoryFlags = 0;
+
+#if ENABLE_DEBUG_LAYER
+ LOAD_PROC(PFN_D3D12_GET_DEBUG_INTERFACE, D3D12GetDebugInterface);
+
+ ID3D12Debug* debugController;
+ if(SUCCEEDED(D3D12GetDebugInterface_(IID_PPV_ARGS(&debugController))))
+ {
+ debugController->EnableDebugLayer();
+ dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
+ }
+#endif
+
+ typedef HRESULT (WINAPI *PFN_DXGI_CREATE_FACTORY_2)(UINT Flags, REFIID riid, _COM_Outptr_ void **ppFactory);
+
+
+ LOAD_PROC(PFN_DXGI_CREATE_FACTORY_2, CreateDXGIFactory2);
+
+ IDXGIFactory4* dxgiFactory;
+ checkResult(CreateDXGIFactory2_(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory)));
+
+ D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
+
+ // Search for an adapter that meets our requirements
+ IDXGIAdapter* adapter = nullptr;
+
+ LOAD_PROC(PFN_D3D12_CREATE_DEVICE, D3D12CreateDevice);
+
+ UINT adapterCounter = 0;
+ for(;;)
+ {
+ UINT adapterIndex = adapterCounter++;
+ IDXGIAdapter1* candidateAdapter = nullptr;
+ if(dxgiFactory->EnumAdapters1(adapterIndex, &candidateAdapter) == DXGI_ERROR_NOT_FOUND)
+ break;
+
+ DXGI_ADAPTER_DESC1 desc;
+ candidateAdapter->GetDesc1(&desc);
+
+ if( desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE )
+ {
+ // TODO: may want to allow software driver as fallback
+ }
+ else if( SUCCEEDED(D3D12CreateDevice_(
+ candidateAdapter, featureLevel, IID_PPV_ARGS(&dxDevice))) )
+ {
+ // We found one!
+ adapter = candidateAdapter;
+ break;
+ }
+
+ candidateAdapter->Release();
+ }
+
+ if(!adapter)
+ {
+ return;
+ }
+
+ // Command Queue
+
+ D3D12_COMMAND_QUEUE_DESC queueDesc = {};
+ queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+
+ ID3D12CommandQueue* commandQueue;
+ checkResult(dxDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)));
+
+ // Swap Chain
+
+
+ UINT frameCount = 2; // TODO: configure
+
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
+ swapChainDesc.BufferCount = frameCount;
+ swapChainDesc.Width = gWindowWidth;
+ swapChainDesc.Height = gWindowHeight;
+ swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+ swapChainDesc.SampleDesc.Count = 1;
+
+ IDXGISwapChain1* swapChain;
+ checkResult(dxgiFactory->CreateSwapChainForHwnd(
+ commandQueue,
+ windowHandle,
+ &swapChainDesc,
+ nullptr,
+ nullptr,
+ &swapChain));
+
+ // Is this needed?
+ dxgiFactory->MakeWindowAssociation(
+ windowHandle, DXGI_MWA_NO_ALT_ENTER);
+
+ IDXGISwapChain3* swapChainEx;
+ swapChain->QueryInterface(IID_PPV_ARGS(&swapChainEx));
+
+ UINT frameIndex = swapChainEx->GetCurrentBackBufferIndex();
+
+ // Descriptor heaps
+
+ D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
+ rtvHeapDesc.NumDescriptors = frameCount;
+ rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
+
+ ID3D12DescriptorHeap* rtvHeap;
+ checkResult(dxDevice->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvHeap)));
+
+ UINT rtvDescriptorSize = dxDevice->GetDescriptorHandleIncrementSize(
+ D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart();
+
+ // Create per-frame RTVs
+ ID3D12Resource* backBufferResources[2];
+ for( UINT ff = 0; ff < frameCount; ++ff )
+ {
+ checkResult(swapChainEx->GetBuffer(ff, IID_PPV_ARGS(&backBufferResources[ff])));
+ dxDevice->CreateRenderTargetView(
+ backBufferResources[ff],
+ nullptr,
+ rtvHandle);
+ rtvHandle.ptr += rtvDescriptorSize;
+ }
+
+ ID3D12CommandAllocator* commandAllocator;
+ checkResult(dxDevice->CreateCommandAllocator(
+ D3D12_COMMAND_LIST_TYPE_DIRECT,
+ IID_PPV_ARGS(&commandAllocator)));
+ }
+
+ float clearColor[4] = { 0, 0, 0, 0 };
+ virtual void setClearColor(float const* color) override
+ {
+ memcpy(clearColor, color, sizeof(clearColor));
+ }
+
+ virtual void clearFrame() override
+ {
+ }
+
+ virtual void presentFrame() override
+ {
+ }
+
+ virtual void captureScreenShot(char const* outputPath) override
+ {
+ }
+
+ virtual ShaderCompiler* getShaderCompiler() override
+ {
+ return this;
+ }
+
+ virtual Buffer* createBuffer(BufferDesc const& desc) override
+ {
+ return nullptr;
+ }
+
+ static DXGI_FORMAT mapFormat(Format format)
+ {
+ switch( format )
+ {
+ case Format::RGB_Float32:
+ return DXGI_FORMAT_R32G32B32_FLOAT;
+ case Format::RG_Float32:
+ return DXGI_FORMAT_R32G32_FLOAT;
+ default:
+ return DXGI_FORMAT_UNKNOWN;
+ }
+ }
+
+ virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override
+ {
+ return nullptr;
+ }
+
+ virtual void* map(Buffer* buffer, MapFlavor flavor) override
+ {
+ return nullptr;
+ }
+
+ virtual void unmap(Buffer* buffer) override
+ {
+ }
+
+ virtual void setInputLayout(InputLayout* inputLayout) override
+ {
+ }
+
+ virtual void setPrimitiveTopology(PrimitiveTopology topology) override
+ {
+ }
+
+ virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override
+ {
+ }
+
+ virtual void setShaderProgram(ShaderProgram* inProgram) override
+ {
+ }
+
+ virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override
+ {
+ }
+
+ virtual void draw(UInt vertexCount, UInt startVertex) override
+ {
+ }
+
+
+ virtual void dispatchCompute(int x, int y, int z) override
+ {
+ }
+
+ virtual BindingState * createBindingState(const ShaderInputLayout & layout)
+ {
+ return nullptr;
+ }
+
+ virtual void setBindingState(BindingState * state)
+ {
+ }
+
+ virtual void serializeOutput(BindingState* state, const char * fileName)
+ {
+ }
+
+ // ShaderCompiler interface
+
+ virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override
+ {
+ return nullptr;
+ }
+
+};
+
+Renderer* createD3D12Renderer()
+{
+ return new D3D12Renderer();
+}
+
+} // renderer_test