diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-02-02 07:49:32 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-02-02 07:49:32 -0800 |
| commit | b034398ab12d3cc3a5fc04174688cb707404791d (patch) | |
| tree | ffa3f01046a7dca55cf004855ca9424c82eaa46f /tools/render-test/render-d3d12.cpp | |
| parent | 652a3c987d2b42d069bf54ba251126208d00d9e7 (diff) | |
Initial work on getting render-test to support vulkan (#391)
* Basic fixes to gets some Vulkan GLSL out of the IR path
We haven't been paying much attention to the Vulkan output from the IR path, but that needs to change ASAP. This commit really just implements quick fixes, without concern for whether they are a good fit in the long term.
- Add some more mappings from D3D `SV_*` semantics to built-in GLSL variables, and stop redeclaring those built-in variables in our output GLSL.
- Add custom output logic for HLSL `*StructuredBuffer<T>` types, so that they emit as `buffer` declarations with an unsized array inside. This has some real limitations:
- What if the user passes the type into a function? The parameter should be typed as an (unsized) array, and not a buffer.
- What happens if we have an array of structured buffers? We need to declare an array of blocks (which GLSL allows), but this changes the GLSL we should emit when indexing.
- Customize the way that we emit entry point attributes (e.g., `[numthread(...)]`) to also support outputting equivalent GLSL `layout` qualifiers.
In many of these cases, a better fix might involve doing more of this work in the IR as part of legalization (e.g., we already have a pass that deals with varying input/output for GLSL, so that should probalby be responsible for swapping the `SV_*` to `gl_*`, especially in cases where the types don't match perfectly across langauges).
* Start adding Vulkan support to render-test
- Add both Vulkan and D3D12 as nominally supported back-ends
- Add a git submodule to pull in the Vulkan SDK dependencies
- I don't want our users to have to install it manually, since the SDK is huge
- Checking in the binaries to our main repository seems like a bad idea, but my hope is that we can prune the bloat using a subodule with the `shallow` cloning option
- Implement enough logic for the Vulkan back-end to get a single test passing on Vulkan
* Fix warning
* Fixup: disable new compute tests for Linux
* Fixup: ignore Vulkan tests on AppVeyor
* Dynamically load Vulkan implementation
Rather than statically link to the Vulkan library, we will dynamically load all of the required functions.
This removes the need to have the stub libs involved at all.
* Remove vulkan submodule
I had set up a `vulkan` submodule to pull in the headers and stub libs, but now that we are going to dynamically load all the symbols anyway, the stub lib binaries aren't needed and we can just commit the headers.
* Add Vulkan headers to external/
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 |
