diff options
Diffstat (limited to 'tools/render-test/render-d3d12.cpp')
| -rw-r--r-- | tools/render-test/render-d3d12.cpp | 337 |
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 |
