diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-03-21 14:28:43 -0400 |
|---|---|---|
| committer | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-03-21 11:28:43 -0700 |
| commit | d421988f91d0d6fda78b9aea4cba763f9c662ffe (patch) | |
| tree | 4207ebec4a744f67df540388133033753cffa359 /tools/render-test | |
| parent | 98b8e0c809ceab84cee25389e54f3f37d220d95e (diff) | |
First pass impls on ComPtr and reorganise Renderer (#450)
* Fixed some small typos in api-users-guide.md
* Fix some small typos in slang-test/main.cpp, render-test/render-d3d11.cpp
* Remove exit() calls from test code. Added Slang::Result, which works in the same way as COM HRESULT.
* FIx bug introduced when moving to Slang::Result - handling E_INVALIDARG on Dx11.
* Fix the testing of feature levels on Dx11 renderer.
* First attempt at README.md for slang-test.
* Tidied up the slang-test README.md file.
* Fix some small typos in tools/slang-test/main.cpp
* Fix spaces -> tabs problems.
Fix some small types.
* Refactor Renderer implementations such that:
* Class definition does not contain long implementation/s
* Removed unused globals
* Ordered implementation after class definition
* Made renderer specific classes child classes, and use Impl postfix to differentiate
* Converted tabs into spaces
* First pass at Slang::ComPtr. Added slang-defines.h which sets up some fairly commonly used defines such as SLANG_FORCE_INLINE, compiler detection, os detection, and some other cross platform features.
Diffstat (limited to 'tools/render-test')
| -rw-r--r-- | tools/render-test/render-d3d11.cpp | 1508 | ||||
| -rw-r--r-- | tools/render-test/render-d3d12.cpp | 421 | ||||
| -rw-r--r-- | tools/render-test/render-gl.cpp | 1109 | ||||
| -rw-r--r-- | tools/render-test/render-vk.cpp | 1398 | ||||
| -rw-r--r-- | tools/render-test/render.h | 42 |
5 files changed, 2248 insertions, 2230 deletions
diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp index ba8d9e46d..dc86e2e44 100644 --- a/tools/render-test/render-d3d11.cpp +++ b/tools/render-test/render-d3d11.cpp @@ -1,4 +1,4 @@ -// render-d3d11.cpp +// render-d3d11.cpp #include "render-d3d11.h" #include "options.h" @@ -40,61 +40,124 @@ using namespace Slang; namespace renderer_test { -struct D3DBinding -{ - ShaderInputType type; - InputBufferType bufferType; // Only valid if `type` is `Buffer` - ID3D11ShaderResourceView * srv = nullptr; - ID3D11UnorderedAccessView * uav = nullptr; - ID3D11Buffer * buffer = nullptr; - ID3D11SamplerState * samplerState = nullptr; - int binding = 0; - bool isOutput = false; - int bufferLength = 0; -}; -struct D3DBindingState +//static char const* vertexEntryPointName = "vertexMain"; +//static char const* fragmentEntryPointName = "fragmentMain"; + +//static char const* vertexProfileName = "vs_4_0"; +//static char const* fragmentProfileName = "ps_4_0"; + +class D3D11Renderer : public Renderer, public ShaderCompiler { - List<D3DBinding> bindings; - int numRenderTargets = 0; -}; +public: + // Renderer implementation + virtual SlangResult initialize(void* inWindowHandle) override; + virtual void setClearColor(float const* color) override; + virtual void clearFrame() override; + virtual void presentFrame() override; + virtual SlangResult captureScreenShot(char const* outputPath) override; + virtual void serializeOutput(BindingState* state, const char * fileName) override; + virtual Buffer* createBuffer(BufferDesc const& desc) override; + virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override; + virtual BindingState * createBindingState(const ShaderInputLayout& layout) override; + virtual ShaderCompiler* getShaderCompiler() override; + virtual void* map(Buffer* buffer, MapFlavor flavor) override; + virtual void unmap(Buffer* buffer) override; + virtual void setInputLayout(InputLayout* inputLayout) override; + virtual void setPrimitiveTopology(PrimitiveTopology topology) override; + virtual void setBindingState(BindingState * state); + 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; + + // ShaderCompiler implementation + virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override; -// + protected: + struct BindingImpl + { + ShaderInputType type; + InputBufferType bufferType; // Only valid if `type` is `Buffer` + ID3D11ShaderResourceView * srv = nullptr; + ID3D11UnorderedAccessView * uav = nullptr; + ID3D11Buffer * buffer = nullptr; + ID3D11SamplerState * samplerState = nullptr; + int binding = 0; + bool isOutput = false; + int bufferLength = 0; + }; + struct BindingStateImpl + { + List<BindingImpl> bindings; + int numRenderTargets = 0; + }; + struct ShaderProgramImpl + { + ID3D11VertexShader* dxVertexShader = nullptr; + ID3D11PixelShader* dxPixelShader = nullptr; + ID3D11ComputeShader* dxComputeShader = nullptr; + }; -// + struct BufferImpl + { + ID3D11Buffer* buffer = nullptr; + }; -// Global variabels for the various D3D11 API objects to be used for rendering -ID3D11Buffer* dxConstantBuffer; -ID3D11InputLayout* dxInputLayout; -ID3D11Buffer* dxVertexBuffer; -ID3D11VertexShader* dxVertexShader; -ID3D11PixelShader* dxPixelShader; + /// Calculate size taking into account alignment. Alignment must be a power of 2 + static UInt calcAligned(UInt size, UInt alignment) { return (size + alignment - 1) & ~(alignment - 1); } + + static DXGI_FORMAT getMapFormat(Format format); -// 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); + /// The Slang compiler currently generates HLSL source, so we'll need a utility + /// routine (defined later) to translate that into D3D11 shader bytecode. + /// Definition of the HLSL-to-bytecode compilation logic. + static ID3DBlob* compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName); + /// Capture a texture to a file + static HRESULT captureTextureToFile(ID3D11Device* dxDevice, ID3D11DeviceContext* dxContext, ID3D11Texture2D* dxTexture, char const* outputPath); -static char const* vertexEntryPointName = "vertexMain"; -static char const* fragmentEntryPointName = "fragmentMain"; + void* map(ID3D11Buffer * buffer, MapFlavor flavor); + void unmap(ID3D11Buffer * buffer); -static char const* vertexProfileName = "vs_4_0"; -static char const* fragmentProfileName = "ps_4_0"; + void createInputBuffer(InputBufferDesc & bufferDesc, List<unsigned int> & bufferData, ID3D11Buffer * &bufferOut, + ID3D11UnorderedAccessView * &viewOut, ID3D11ShaderResourceView * &srvOut); -ID3DBlob* gVertexShaderBlob; -ID3DBlob* gPixelShaderBlob; + void createInputTexture(const InputTextureDesc & inputDesc, ID3D11ShaderResourceView * &viewOut); -// -// Definition of the HLSL-to-bytecode compilation logic. -// -ID3DBlob* compileHLSLShader( - char const* sourcePath, - char const* source, - char const* entryPointName, - char const* dxProfileName ) + void createInputSampler(const InputSamplerDesc & inputDesc, ID3D11SamplerState * & stateOut); + + void applyBindingState(bool isCompute); + + IDXGISwapChain* dxSwapChain = nullptr; + ID3D11Device* dxDevice = nullptr; + ID3D11DeviceContext* dxImmediateContext = nullptr; + ID3D11Texture2D* dxBackBufferTexture = nullptr; + List<ID3D11RenderTargetView*> dxRenderTargetViews; + List<ID3D11Texture2D*> dxRenderTargetTextures; + BindingStateImpl* currentBindings = nullptr; + float clearColor[4] = { 0, 0, 0, 0 }; +}; + +Renderer* createD3D11Renderer() +{ + return new D3D11Renderer(); +} + +/* static */DXGI_FORMAT D3D11Renderer::getMapFormat(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; + } +} + +/* static */ID3DBlob* D3D11Renderer::compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName) { // Rather than statically link against the `d3dcompile` library, we // dynamically load it. @@ -104,21 +167,21 @@ ID3DBlob* compileHLSLShader( // on-the-fly like this // static pD3DCompile D3DCompile_ = nullptr; - if( !D3DCompile_ ) + if (!D3DCompile_) { // TODO(tfoley): maybe want to search for one of a few versions of the DLL HMODULE d3dcompiler = LoadLibraryA("d3dcompiler_47.dll"); - if(!d3dcompiler) + if (!d3dcompiler) { fprintf(stderr, "error: failed load 'd3dcompiler_47.dll'\n"); return nullptr; } D3DCompile_ = (pD3DCompile)GetProcAddress(d3dcompiler, "D3DCompile"); - if( !D3DCompile_ ) + if (!D3DCompile_) { fprintf(stderr, "error: failed load symbol 'D3DCompile'\n"); - return nullptr; + return nullptr; } } @@ -155,7 +218,7 @@ ID3DBlob* compileHLSLShader( // If the HLSL-to-bytecode compilation produced any diagnostic messages // then we will print them out (whether or not the compilation failed). - if( dxErrorBlob ) + if (dxErrorBlob) { fputs( (char const*)dxErrorBlob->GetBufferPointer(), @@ -168,7 +231,7 @@ ID3DBlob* compileHLSLShader( dxErrorBlob->Release(); } - if( FAILED(hr) ) + if (FAILED(hr)) { return nullptr; } @@ -176,34 +239,26 @@ ID3DBlob* compileHLSLShader( return dxShaderBlob; } - - - -// Capture a texture to a file - -static HRESULT captureTextureToFile( - ID3D11Device* dxDevice, - ID3D11DeviceContext* dxContext, - ID3D11Texture2D* dxTexture, - char const* outputPath) +/* static */HRESULT D3D11Renderer::captureTextureToFile(ID3D11Device* dxDevice, ID3D11DeviceContext* dxContext, + ID3D11Texture2D* dxTexture, char const* outputPath) { - if(!dxContext) return E_INVALIDARG; - if(!dxTexture) return E_INVALIDARG; + if (!dxContext) return E_INVALIDARG; + if (!dxTexture) return E_INVALIDARG; D3D11_TEXTURE2D_DESC dxTextureDesc; dxTexture->GetDesc(&dxTextureDesc); // Don't bother supporting MSAA for right now - if( dxTextureDesc.SampleDesc.Count > 1 ) + if (dxTextureDesc.SampleDesc.Count > 1) { - fprintf(stderr, "ERROR: cannot capture multisample texture\n"); + fprintf(stderr, "ERROR: cannot capture multi-sample texture\n"); return E_INVALIDARG; } HRESULT hr = S_OK; ID3D11Texture2D* dxStagingTexture = nullptr; - if( dxTextureDesc.Usage == D3D11_USAGE_STAGING && (dxTextureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) ) + if (dxTextureDesc.Usage == D3D11_USAGE_STAGING && (dxTextureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) { dxStagingTexture = dxTexture; dxStagingTexture->AddRef(); @@ -217,12 +272,12 @@ static HRESULT captureTextureToFile( dxTextureDesc.Usage = D3D11_USAGE_STAGING; hr = dxDevice->CreateTexture2D(&dxTextureDesc, 0, &dxStagingTexture); - if( FAILED(hr) ) + if (FAILED(hr)) { fprintf(stderr, "ERROR: failed to create staging texture\n"); return hr; } - + dxContext->CopyResource(dxStagingTexture, dxTexture); } @@ -230,240 +285,215 @@ static HRESULT captureTextureToFile( D3D11_MAPPED_SUBRESOURCE dxMappedResource; hr = dxContext->Map(dxStagingTexture, 0, D3D11_MAP_READ, 0, &dxMappedResource); - if( FAILED(hr) ) + if (FAILED(hr)) { fprintf(stderr, "ERROR: failed to map texture for read\n"); return hr; } - int stbResult = stbi_write_png( - outputPath, - dxTextureDesc.Width, - dxTextureDesc.Height, - 4, - dxMappedResource.pData, - dxMappedResource.RowPitch); - if( !stbResult ) + int stbResult = stbi_write_png(outputPath, dxTextureDesc.Width, dxTextureDesc.Height, 4, + dxMappedResource.pData, dxMappedResource.RowPitch); + + // Make sure to unmap + dxContext->Unmap(dxStagingTexture, 0); + dxStagingTexture->Release(); + + if (!stbResult) { fprintf(stderr, "ERROR: failed to write texture to file\n"); return E_UNEXPECTED; } - dxContext->Unmap(dxStagingTexture, 0); - - dxStagingTexture->Release(); - return S_OK; } -// +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! -class D3D11Renderer : public Renderer, public ShaderCompiler +SlangResult D3D11Renderer::initialize(void* inWindowHandle) { -public: - IDXGISwapChain* dxSwapChain = nullptr; - ID3D11Device* dxDevice = nullptr; - ID3D11DeviceContext* dxImmediateContext = nullptr; - ID3D11Texture2D* dxBackBufferTexture = nullptr; - List<ID3D11RenderTargetView*> dxRenderTargetViews; - List<ID3D11Texture2D *> dxRenderTargetTextures; - D3DBindingState * currentBindings = nullptr; - virtual SlangResult initialize(void* inWindowHandle) override + auto windowHandle = (HWND)inWindowHandle; + // Rather than statically link against D3D, we load it dynamically. + + HMODULE d3d11 = LoadLibraryA("d3d11.dll"); + if (!d3d11) { - auto windowHandle = (HWND) inWindowHandle; - // Rather than statically link against D3D, we load it dynamically. + fprintf(stderr, "error: failed load 'd3d11.dll'\n"); + return SLANG_FAIL; + } - HMODULE d3d11 = LoadLibraryA("d3d11.dll"); - if(!d3d11) - { - fprintf(stderr, "error: failed load 'd3d11.dll'\n"); - return SLANG_FAIL; - } + PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN D3D11CreateDeviceAndSwapChain_ = + (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(d3d11, "D3D11CreateDeviceAndSwapChain"); + if (!D3D11CreateDeviceAndSwapChain_) + { + fprintf(stderr, + "error: failed load symbol 'D3D11CreateDeviceAndSwapChain'\n"); + return SLANG_FAIL; + } - PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN D3D11CreateDeviceAndSwapChain_ = - (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(d3d11, "D3D11CreateDeviceAndSwapChain"); - if(!D3D11CreateDeviceAndSwapChain_) - { - fprintf(stderr, - "error: failed load symbol 'D3D11CreateDeviceAndSwapChain'\n"); - return SLANG_FAIL; - } + // We create our device in debug mode, just so that we can check that the + // example doesn't trigger warnings. + UINT deviceFlags = 0; + deviceFlags |= D3D11_CREATE_DEVICE_DEBUG; + + + // Our swap chain uses RGBA8 with sRGB, with double buffering. + + DXGI_SWAP_CHAIN_DESC dxSwapChainDesc = { 0 }; + dxSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + + // Note(tfoley): Disabling sRGB for DX back buffer for now, so that we + // can get consistent output with OpenGL, where setting up sRGB will + // probably be more involved. + // dxSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + dxSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + + dxSwapChainDesc.SampleDesc.Count = 1; + dxSwapChainDesc.SampleDesc.Quality = 0; + dxSwapChainDesc.BufferCount = 2; + dxSwapChainDesc.OutputWindow = windowHandle; + dxSwapChainDesc.Windowed = TRUE; + dxSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + dxSwapChainDesc.Flags = 0; + + // We will ask for the highest feature level that can be supported. + D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1, + }; + D3D_FEATURE_LEVEL dxFeatureLevel = D3D_FEATURE_LEVEL_9_1; + const int totalNumFeatureLevels = sizeof(featureLevels) / sizeof(featureLevels[0]); + + // On a machine that does not have an up-to-date version of D3D installed, + // the `D3D11CreateDeviceAndSwapChain` call will fail with `E_INVALIDARG` + // if you ask for featuer level 11_1. The workaround is to call + // `D3D11CreateDeviceAndSwapChain` up to twice: the first time with 11_1 + // at the start of the list of requested feature levels, and the second + // time without it. - // We create our device in debug mode, just so that we can check that the - // example doesn't trigger warnings. - UINT deviceFlags = 0; - deviceFlags |= D3D11_CREATE_DEVICE_DEBUG; - - - // Our swap chain uses RGBA8 with sRGB, with double buffering. - - DXGI_SWAP_CHAIN_DESC dxSwapChainDesc = { 0 }; - dxSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - - // Note(tfoley): Disabling sRGB for DX back buffer for now, so that we - // can get consistent output with OpenGL, where setting up sRGB will - // probably be more involved. -// dxSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - dxSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - - dxSwapChainDesc.SampleDesc.Count = 1; - dxSwapChainDesc.SampleDesc.Quality = 0; - dxSwapChainDesc.BufferCount = 2; - dxSwapChainDesc.OutputWindow = windowHandle; - dxSwapChainDesc.Windowed = TRUE; - dxSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - dxSwapChainDesc.Flags = 0; - - // We will ask for the highest feature level that can be supported. - D3D_FEATURE_LEVEL featureLevels[] = { - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1, - }; - D3D_FEATURE_LEVEL dxFeatureLevel = D3D_FEATURE_LEVEL_9_1; - const int totalNumFeatureLevels = sizeof(featureLevels) / sizeof(featureLevels[0]); - - // On a machine that does not have an up-to-date version of D3D installed, - // the `D3D11CreateDeviceAndSwapChain` call will fail with `E_INVALIDARG` - // if you ask for featuer level 11_1. The workaround is to call - // `D3D11CreateDeviceAndSwapChain` up to twice: the first time with 11_1 - // at the start of the list of requested feature levels, and the second - // time without it. - - for( int ii = 0; ii < 2; ++ii ) + for (int ii = 0; ii < 2; ++ii) + { + const HRESULT hr = D3D11CreateDeviceAndSwapChain_( + NULL, // adapter (use default) + D3D_DRIVER_TYPE_REFERENCE, + //D3D_DRIVER_TYPE_HARDWARE, + NULL, // software + deviceFlags, + &featureLevels[ii], + totalNumFeatureLevels - ii, + D3D11_SDK_VERSION, + &dxSwapChainDesc, + &dxSwapChain, + &dxDevice, + &dxFeatureLevel, + &dxImmediateContext); + + // Failures with `E_INVALIDARG` might be due to feature level 11_1 + // not being supported. + if (hr == E_INVALIDARG) { - const HRESULT hr = D3D11CreateDeviceAndSwapChain_( - NULL, // adapter (use default) - D3D_DRIVER_TYPE_REFERENCE, - //D3D_DRIVER_TYPE_HARDWARE, - NULL, // software - deviceFlags, - &featureLevels[ii], - totalNumFeatureLevels - ii, - D3D11_SDK_VERSION, - &dxSwapChainDesc, - &dxSwapChain, - &dxDevice, - &dxFeatureLevel, - &dxImmediateContext); - - // Failures with `E_INVALIDARG` might be due to feature level 11_1 - // not being supported. - if (hr == E_INVALIDARG) - { - continue; - } - - // Other failures are real, though. - SLANG_RETURN_ON_FAIL(hr); - // We must have a swap chain - break; + continue; } - - // After we've created the swap chain, we can request a pointer to the - // back buffer as a D3D11 texture, and create a render-target view from it. - static const IID kIID_ID3D11Texture2D = { - 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, - 0x95, 0x35, 0xd3, 0x4f, 0x9c }; + // Other failures are real, though. + SLANG_RETURN_ON_FAIL(hr); + // We must have a swap chain + break; + } - SLANG_RETURN_ON_FAIL(dxSwapChain->GetBuffer(0, kIID_ID3D11Texture2D, (void**)&dxBackBufferTexture)); + // After we've created the swap chain, we can request a pointer to the + // back buffer as a D3D11 texture, and create a render-target view from it. - for (int i = 0; i < 8; i++) - { - ID3D11Texture2D* texture; - D3D11_TEXTURE2D_DESC textureDesc; - dxBackBufferTexture->GetDesc(&textureDesc); - SLANG_RETURN_ON_FAIL(dxDevice->CreateTexture2D(&textureDesc, nullptr, &texture)); - - ID3D11RenderTargetView * rtv; - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - rtvDesc.Texture2D.MipSlice = 0; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - SLANG_RETURN_ON_FAIL(dxDevice->CreateRenderTargetView(texture, &rtvDesc, &rtv)); - - dxRenderTargetViews.Add(rtv); - dxRenderTargetTextures.Add(texture); - } + static const IID kIID_ID3D11Texture2D = { + 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, + 0x95, 0x35, 0xd3, 0x4f, 0x9c }; - dxImmediateContext->OMSetRenderTargets((UINT)dxRenderTargetViews.Count(), dxRenderTargetViews.Buffer(), nullptr); - - // Similarly, we are going to set up a viewport once, and then never - // switch, since this is a simple test app. - D3D11_VIEWPORT dxViewport; - dxViewport.TopLeftX = 0; - dxViewport.TopLeftY = 0; - dxViewport.Width = (float) gWindowWidth; - dxViewport.Height = (float) gWindowHeight; - dxViewport.MaxDepth = 1; // TODO(tfoley): use reversed depth - dxViewport.MinDepth = 0; - dxImmediateContext->RSSetViewports(1, &dxViewport); - - return SLANG_OK; - } + SLANG_RETURN_ON_FAIL(dxSwapChain->GetBuffer(0, kIID_ID3D11Texture2D, (void**)&dxBackBufferTexture)); - float clearColor[4] = { 0, 0, 0, 0 }; - virtual void setClearColor(float const* color) override + for (int i = 0; i < 8; i++) { - memcpy(clearColor, color, sizeof(clearColor)); + ID3D11Texture2D* texture; + D3D11_TEXTURE2D_DESC textureDesc; + dxBackBufferTexture->GetDesc(&textureDesc); + SLANG_RETURN_ON_FAIL(dxDevice->CreateTexture2D(&textureDesc, nullptr, &texture)); + + ID3D11RenderTargetView * rtv; + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + rtvDesc.Texture2D.MipSlice = 0; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + SLANG_RETURN_ON_FAIL(dxDevice->CreateRenderTargetView(texture, &rtvDesc, &rtv)); + + dxRenderTargetViews.Add(rtv); + dxRenderTargetTextures.Add(texture); } - virtual void clearFrame() override - { - for (auto i = 0u; i < dxRenderTargetViews.Count(); i++) - dxImmediateContext->ClearRenderTargetView( - dxRenderTargetViews[i], - clearColor); - } + dxImmediateContext->OMSetRenderTargets((UINT)dxRenderTargetViews.Count(), dxRenderTargetViews.Buffer(), nullptr); - virtual void presentFrame() override - { - dxImmediateContext->CopyResource(dxBackBufferTexture, dxRenderTargetTextures[0]); - dxSwapChain->Present(0, 0); - } + // Similarly, we are going to set up a viewport once, and then never + // switch, since this is a simple test app. + D3D11_VIEWPORT dxViewport; + dxViewport.TopLeftX = 0; + dxViewport.TopLeftY = 0; + dxViewport.Width = (float)gWindowWidth; + dxViewport.Height = (float)gWindowHeight; + dxViewport.MaxDepth = 1; // TODO(tfoley): use reversed depth + dxViewport.MinDepth = 0; + dxImmediateContext->RSSetViewports(1, &dxViewport); - virtual SlangResult captureScreenShot(char const* outputPath) override - { - HRESULT hr = captureTextureToFile( - dxDevice, - dxImmediateContext, - dxRenderTargetTextures[0], - outputPath); - if( FAILED(hr) ) - { - fprintf(stderr, "error: could not capture screenshot to '%s'\n", outputPath); - SLANG_RETURN_ON_FAIL(hr); - } - return SLANG_OK; - } + return SLANG_OK; +} - virtual ShaderCompiler* getShaderCompiler() override - { - return this; - } +void D3D11Renderer::setClearColor(float const* color) +{ + memcpy(clearColor, color, sizeof(clearColor)); +} - struct D3DBuffer - { - ID3D11Buffer * buffer = nullptr; - }; +void D3D11Renderer::clearFrame() +{ + for (auto i = 0u; i < dxRenderTargetViews.Count(); i++) + dxImmediateContext->ClearRenderTargetView( + dxRenderTargetViews[i], + clearColor); +} + +void D3D11Renderer::presentFrame() +{ + dxImmediateContext->CopyResource(dxBackBufferTexture, dxRenderTargetTextures[0]); + dxSwapChain->Present(0, 0); +} - UInt RoundUpToAlignment(UInt size, UInt alignment) +SlangResult D3D11Renderer::captureScreenShot(char const* outputPath) +{ + HRESULT hr = captureTextureToFile( + dxDevice, + dxImmediateContext, + dxRenderTargetTextures[0], + outputPath); + if (FAILED(hr)) { - return ((size + alignment - 1) / alignment) * alignment; + fprintf(stderr, "error: could not capture screen-shot to '%s'\n", outputPath); + SLANG_RETURN_ON_FAIL(hr); } + return SLANG_OK; +} - virtual Buffer* createBuffer(BufferDesc const& desc) override - { - D3D11_BUFFER_DESC dxBufferDesc = { 0 }; - dxBufferDesc.ByteWidth = (UINT)RoundUpToAlignment(desc.size, 256); +ShaderCompiler* D3D11Renderer::getShaderCompiler() +{ + return this; +} - switch( desc.flavor ) - { +Buffer* D3D11Renderer::createBuffer(BufferDesc const& desc) +{ + D3D11_BUFFER_DESC dxBufferDesc = { 0 }; + dxBufferDesc.ByteWidth = (UINT)calcAligned(desc.size, 256); + + switch (desc.flavor) + { case BufferFlavor::Constant: dxBufferDesc.Usage = D3D11_USAGE_DYNAMIC; dxBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; @@ -477,64 +507,47 @@ public: break; default: return nullptr; - } + } - D3D11_SUBRESOURCE_DATA dxInitData = { 0 }; - dxInitData.pSysMem = desc.initData; + D3D11_SUBRESOURCE_DATA dxInitData = { 0 }; + dxInitData.pSysMem = desc.initData; + ID3D11Buffer* dxBuffer = nullptr; + HRESULT hr = dxDevice->CreateBuffer(&dxBufferDesc, desc.initData ? &dxInitData : nullptr, &dxBuffer); + if (FAILED(hr)) return nullptr; - ID3D11Buffer* dxBuffer = nullptr; - HRESULT hr = dxDevice->CreateBuffer( - &dxBufferDesc, - desc.initData ? &dxInitData : nullptr, - &dxBuffer); - if(FAILED(hr)) return nullptr; + BufferImpl* rs = new BufferImpl; + rs->buffer = dxBuffer; + return (Buffer*)rs; +} - D3DBuffer * rs = new D3DBuffer(); - rs->buffer = dxBuffer; - return (Buffer*) rs; - } +InputLayout* D3D11Renderer::createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) +{ + D3D11_INPUT_ELEMENT_DESC dxInputElements[16] = {}; - static DXGI_FORMAT mapFormat(Format format) + char hlslBuffer[1024]; + char* hlslCursor = &hlslBuffer[0]; + + hlslCursor += sprintf(hlslCursor, "float4 main(\n"); + + for (UInt ii = 0; ii < inputElementCount; ++ii) { - switch( format ) + dxInputElements[ii].SemanticName = inputElements[ii].semanticName; + dxInputElements[ii].SemanticIndex = (UINT)inputElements[ii].semanticIndex; + dxInputElements[ii].Format = getMapFormat(inputElements[ii].format); + dxInputElements[ii].InputSlot = 0; + dxInputElements[ii].AlignedByteOffset = (UINT)inputElements[ii].offset; + dxInputElements[ii].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + dxInputElements[ii].InstanceDataStepRate = 0; + + if (ii != 0) { - case Format::RGB_Float32: - return DXGI_FORMAT_R32G32B32_FLOAT; - case Format::RG_Float32: - return DXGI_FORMAT_R32G32_FLOAT; - default: - return DXGI_FORMAT_UNKNOWN; + hlslCursor += sprintf(hlslCursor, ",\n"); } - } - - virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override - { - D3D11_INPUT_ELEMENT_DESC dxInputElements[16] = {}; - - char hlslBuffer[1024]; - char* hlslCursor = &hlslBuffer[0]; - - hlslCursor += sprintf(hlslCursor, "float4 main(\n"); - for( UInt ii = 0; ii < inputElementCount; ++ii ) + char const* typeName = "Unknown"; + switch (inputElements[ii].format) { - dxInputElements[ii].SemanticName = inputElements[ii].semanticName; - dxInputElements[ii].SemanticIndex = (UINT) inputElements[ii].semanticIndex; - dxInputElements[ii].Format = mapFormat(inputElements[ii].format); - dxInputElements[ii].InputSlot = 0; - dxInputElements[ii].AlignedByteOffset = (UINT) inputElements[ii].offset; - dxInputElements[ii].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - dxInputElements[ii].InstanceDataStepRate = 0; - - if(ii != 0) - { - hlslCursor+= sprintf(hlslCursor, ",\n"); - } - - char const* typeName = "Unknown"; - switch(inputElements[ii].format) - { case Format::RGB_Float32: typeName = "float3"; break; @@ -543,46 +556,46 @@ public: break; default: return nullptr; - } - - hlslCursor+= sprintf(hlslCursor, "%s a%d : %s%d", - typeName, - (int) ii, - inputElements[ii].semanticName, - (int) inputElements[ii].semanticIndex); } - hlslCursor += sprintf(hlslCursor, "\n) : SV_Position { return 0; }"); + hlslCursor += sprintf(hlslCursor, "%s a%d : %s%d", + typeName, + (int)ii, + inputElements[ii].semanticName, + (int)inputElements[ii].semanticIndex); + } - auto dxVertexShaderBlob = compileHLSLShader("inputLayout", hlslBuffer, "main", "vs_5_0"); - if(!dxVertexShaderBlob) - return nullptr; + hlslCursor += sprintf(hlslCursor, "\n) : SV_Position { return 0; }"); - ID3D11InputLayout* dxInputLayout = nullptr; - HRESULT hr = dxDevice->CreateInputLayout( - &dxInputElements[0], - (UINT) inputElementCount, - dxVertexShaderBlob->GetBufferPointer(), - dxVertexShaderBlob->GetBufferSize(), - &dxInputLayout); + auto dxVertexShaderBlob = compileHLSLShader("inputLayout", hlslBuffer, "main", "vs_5_0"); + if (!dxVertexShaderBlob) + return nullptr; - dxVertexShaderBlob->Release(); + ID3D11InputLayout* dxInputLayout = nullptr; + HRESULT hr = dxDevice->CreateInputLayout( + &dxInputElements[0], + (UINT)inputElementCount, + dxVertexShaderBlob->GetBufferPointer(), + dxVertexShaderBlob->GetBufferSize(), + &dxInputLayout); - if(FAILED(hr)) - return nullptr; + dxVertexShaderBlob->Release(); - return (InputLayout*) dxInputLayout; - } + if (FAILED(hr)) + return nullptr; - void* map(ID3D11Buffer * buffer, MapFlavor flavor) - { - auto dxContext = dxImmediateContext; + return (InputLayout*)dxInputLayout; +} - auto dxBuffer = buffer; +void* D3D11Renderer::map(ID3D11Buffer * buffer, MapFlavor flavor) +{ + auto dxContext = dxImmediateContext; - D3D11_MAP dxMapFlavor; - switch (flavor) - { + auto dxBuffer = buffer; + + D3D11_MAP dxMapFlavor; + switch (flavor) + { case MapFlavor::WriteDiscard: dxMapFlavor = D3D11_MAP_WRITE_DISCARD; break; @@ -594,395 +607,380 @@ public: break; default: return nullptr; - } + } - // We update our constant buffer per-frame, just for the purposes - // of the example, but we don't actually load different data - // per-frame (we always use an identity projection). - D3D11_MAPPED_SUBRESOURCE dxMapped; - HRESULT hr = dxContext->Map(dxBuffer, 0, dxMapFlavor, 0, &dxMapped); - if (FAILED(hr)) - return nullptr; + // We update our constant buffer per-frame, just for the purposes + // of the example, but we don't actually load different data + // per-frame (we always use an identity projection). + D3D11_MAPPED_SUBRESOURCE dxMapped; + HRESULT hr = dxContext->Map(dxBuffer, 0, dxMapFlavor, 0, &dxMapped); + if (FAILED(hr)) + return nullptr; - return dxMapped.pData; - } + return dxMapped.pData; +} - virtual void* map(Buffer* buffer, MapFlavor flavor) override - { - return map(((D3DBuffer*)buffer)->buffer, flavor); - } +void* D3D11Renderer::map(Buffer* buffer, MapFlavor flavor) +{ + return map(((BufferImpl*)buffer)->buffer, flavor); +} - void unmap(ID3D11Buffer * buffer) - { - auto dxContext = dxImmediateContext; - dxContext->Unmap(buffer, 0); - } +void D3D11Renderer::unmap(ID3D11Buffer * buffer) +{ + auto dxContext = dxImmediateContext; + dxContext->Unmap(buffer, 0); +} - virtual void unmap(Buffer* buffer) override - { - auto dxBuffer = ((D3DBuffer*)buffer)->buffer; - unmap(dxBuffer); - } +void D3D11Renderer::unmap(Buffer* buffer) +{ + auto dxBuffer = ((BufferImpl*)buffer)->buffer; + unmap(dxBuffer); +} - virtual void setInputLayout(InputLayout* inputLayout) override - { - auto dxContext = dxImmediateContext; - auto dxInputLayout = (ID3D11InputLayout*) inputLayout; +void D3D11Renderer::setInputLayout(InputLayout* inputLayout) +{ + auto dxContext = dxImmediateContext; + auto dxInputLayout = (ID3D11InputLayout*)inputLayout; - dxContext->IASetInputLayout(dxInputLayout); - } + dxContext->IASetInputLayout(dxInputLayout); +} - virtual void setPrimitiveTopology(PrimitiveTopology topology) override - { - auto dxContext = dxImmediateContext; +void D3D11Renderer::setPrimitiveTopology(PrimitiveTopology topology) +{ + auto dxContext = dxImmediateContext; - D3D11_PRIMITIVE_TOPOLOGY dxTopology; - switch( topology ) - { + D3D11_PRIMITIVE_TOPOLOGY dxTopology; + switch (topology) + { case PrimitiveTopology::TriangleList: dxTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break; default: return; - } - - dxContext->IASetPrimitiveTopology(dxTopology); } - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override - { - auto dxContext = dxImmediateContext; - - static const int kMaxVertexBuffers = 16; - - UINT dxVertexStrides[kMaxVertexBuffers]; - UINT dxVertexOffsets[kMaxVertexBuffers]; + dxContext->IASetPrimitiveTopology(dxTopology); +} - for( UInt ii = 0; ii < slotCount; ++ii ) - { - dxVertexStrides[ii] = (UINT) strides[ii]; - dxVertexOffsets[ii] = (UINT) offsets[ii]; - } +void D3D11Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) +{ + auto dxContext = dxImmediateContext; - auto dxVertexBuffers = (D3DBuffer* const*) buffers; + static const int kMaxVertexBuffers = 16; - dxContext->IASetVertexBuffers( - (UINT) startSlot, - (UINT) slotCount, &(dxVertexBuffers[0])->buffer, &dxVertexStrides[0], &dxVertexOffsets[0]); - } + UINT dxVertexStrides[kMaxVertexBuffers]; + UINT dxVertexOffsets[kMaxVertexBuffers]; - virtual void setShaderProgram(ShaderProgram* inProgram) override + for (UInt ii = 0; ii < slotCount; ++ii) { - auto dxContext = dxImmediateContext; - - auto program = (D3D11ShaderProgram*) inProgram; - dxContext->CSSetShader(program->dxComputeShader, NULL, 0); - dxContext->VSSetShader(program->dxVertexShader, NULL, 0); - dxContext->PSSetShader(program->dxPixelShader, NULL, 0); + dxVertexStrides[ii] = (UINT)strides[ii]; + dxVertexOffsets[ii] = (UINT)offsets[ii]; } - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override - { - auto dxContext = dxImmediateContext; + auto dxVertexBuffers = (BufferImpl* const*)buffers; - // TODO: actually use those offsets + dxContext->IASetVertexBuffers( + (UINT)startSlot, + (UINT)slotCount, &(dxVertexBuffers[0])->buffer, &dxVertexStrides[0], &dxVertexOffsets[0]); +} - auto dxConstantBuffers = (D3DBuffer* const*) buffers; - dxContext->VSSetConstantBuffers( - (UINT) startSlot, (UINT) slotCount, &dxConstantBuffers[0]->buffer); - dxContext->VSSetConstantBuffers( - (UINT) startSlot, (UINT) slotCount, &dxConstantBuffers[0]->buffer); - } +void D3D11Renderer::setShaderProgram(ShaderProgram* inProgram) +{ + auto dxContext = dxImmediateContext; - virtual void draw(UInt vertexCount, UInt startVertex) override - { - auto dxContext = dxImmediateContext; - applyBindingState(false); - dxContext->Draw((UINT) vertexCount, (UINT) startVertex); - } + auto program = (ShaderProgramImpl*)inProgram; + dxContext->CSSetShader(program->dxComputeShader, nullptr, 0); + dxContext->VSSetShader(program->dxVertexShader, nullptr, 0); + dxContext->PSSetShader(program->dxPixelShader, nullptr, 0); +} +void D3D11Renderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) +{ + auto dxContext = dxImmediateContext; - // ShaderCompiler interface + // TODO: actually use those offsets - struct D3D11ShaderProgram - { - ID3D11VertexShader* dxVertexShader = nullptr; - ID3D11PixelShader* dxPixelShader = nullptr; - ID3D11ComputeShader* dxComputeShader = nullptr; - }; + auto dxConstantBuffers = (BufferImpl* const*)buffers; + dxContext->VSSetConstantBuffers((UINT)startSlot, (UINT)slotCount, &dxConstantBuffers[0]->buffer); + dxContext->VSSetConstantBuffers((UINT)startSlot, (UINT)slotCount, &dxConstantBuffers[0]->buffer); +} + +void D3D11Renderer::draw(UInt vertexCount, UInt startVertex) +{ + auto dxContext = dxImmediateContext; + applyBindingState(false); + dxContext->Draw((UINT)vertexCount, (UINT)startVertex); +} - virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override +ShaderProgram* D3D11Renderer::compileProgram(ShaderCompileRequest const& request) +{ + if (request.computeShader.name) { - if (request.computeShader.name) - { - auto dxComputeShaderBlob = compileHLSLShader(request.computeShader.source.path, request.computeShader.source.dataBegin, request.computeShader.name, request.computeShader.profile); - if (!dxComputeShaderBlob) - return nullptr; + auto dxComputeShaderBlob = compileHLSLShader(request.computeShader.source.path, request.computeShader.source.dataBegin, request.computeShader.name, request.computeShader.profile); + if (!dxComputeShaderBlob) + return nullptr; - ID3D11ComputeShader* dxComputeShader; + ID3D11ComputeShader* dxComputeShader; - HRESULT csResult = dxDevice->CreateComputeShader(dxComputeShaderBlob->GetBufferPointer(), dxComputeShaderBlob->GetBufferSize(), nullptr, &dxComputeShader); + HRESULT csResult = dxDevice->CreateComputeShader(dxComputeShaderBlob->GetBufferPointer(), dxComputeShaderBlob->GetBufferSize(), nullptr, &dxComputeShader); - dxComputeShaderBlob->Release(); + dxComputeShaderBlob->Release(); - if (FAILED(csResult)) return nullptr; + if (FAILED(csResult)) return nullptr; - D3D11ShaderProgram* shaderProgram = new D3D11ShaderProgram(); - shaderProgram->dxComputeShader = dxComputeShader; - return (ShaderProgram*)shaderProgram; - } - else - { - auto dxVertexShaderBlob = compileHLSLShader(request.vertexShader.source.path, request.vertexShader.source.dataBegin, request.vertexShader.name, request.vertexShader.profile); - if (!dxVertexShaderBlob) return nullptr; + ShaderProgramImpl* shaderProgram = new ShaderProgramImpl(); + shaderProgram->dxComputeShader = dxComputeShader; + return (ShaderProgram*)shaderProgram; + } + else + { + auto dxVertexShaderBlob = compileHLSLShader(request.vertexShader.source.path, request.vertexShader.source.dataBegin, request.vertexShader.name, request.vertexShader.profile); + if (!dxVertexShaderBlob) return nullptr; - auto dxFragmentShaderBlob = compileHLSLShader(request.fragmentShader.source.path, request.fragmentShader.source.dataBegin, request.fragmentShader.name, request.fragmentShader.profile); - if (!dxFragmentShaderBlob) return nullptr; + auto dxFragmentShaderBlob = compileHLSLShader(request.fragmentShader.source.path, request.fragmentShader.source.dataBegin, request.fragmentShader.name, request.fragmentShader.profile); + if (!dxFragmentShaderBlob) return nullptr; - ID3D11VertexShader* dxVertexShader; - ID3D11PixelShader* dxPixelShader; + ID3D11VertexShader* dxVertexShader; + ID3D11PixelShader* dxPixelShader; - HRESULT vsResult = dxDevice->CreateVertexShader(dxVertexShaderBlob->GetBufferPointer(), dxVertexShaderBlob->GetBufferSize(), nullptr, &dxVertexShader); - HRESULT psResult = dxDevice->CreatePixelShader(dxFragmentShaderBlob->GetBufferPointer(), dxFragmentShaderBlob->GetBufferSize(), nullptr, &dxPixelShader); + HRESULT vsResult = dxDevice->CreateVertexShader(dxVertexShaderBlob->GetBufferPointer(), dxVertexShaderBlob->GetBufferSize(), nullptr, &dxVertexShader); + HRESULT psResult = dxDevice->CreatePixelShader(dxFragmentShaderBlob->GetBufferPointer(), dxFragmentShaderBlob->GetBufferSize(), nullptr, &dxPixelShader); - dxVertexShaderBlob->Release(); - dxFragmentShaderBlob->Release(); + dxVertexShaderBlob->Release(); + dxFragmentShaderBlob->Release(); - if (FAILED(vsResult)) return nullptr; - if (FAILED(psResult)) return nullptr; + if (FAILED(vsResult)) return nullptr; + if (FAILED(psResult)) return nullptr; - D3D11ShaderProgram* shaderProgram = new D3D11ShaderProgram(); - shaderProgram->dxVertexShader = dxVertexShader; - shaderProgram->dxPixelShader = dxPixelShader; - return (ShaderProgram*)shaderProgram; - } + ShaderProgramImpl* shaderProgram = new ShaderProgramImpl(); + shaderProgram->dxVertexShader = dxVertexShader; + shaderProgram->dxPixelShader = dxPixelShader; + return (ShaderProgram*)shaderProgram; } +} + +void D3D11Renderer::dispatchCompute(int x, int y, int z) +{ + auto dxContext = dxImmediateContext; + applyBindingState(true); + dxContext->Dispatch(x, y, z); +} - virtual void dispatchCompute(int x, int y, int z) override - { - auto dxContext = dxImmediateContext; - applyBindingState(true); - dxContext->Dispatch(x, y, z); - } - - void createInputBuffer( - InputBufferDesc & bufferDesc, - List<unsigned int> & bufferData, - ID3D11Buffer * &bufferOut, - ID3D11UnorderedAccessView * &viewOut, - ID3D11ShaderResourceView * &srvOut) +void D3D11Renderer::createInputBuffer(InputBufferDesc & bufferDesc, List<unsigned int> & bufferData, ID3D11Buffer * &bufferOut, + ID3D11UnorderedAccessView * &viewOut, ID3D11ShaderResourceView * &srvOut) +{ + auto dxContext = dxImmediateContext; + D3D11_BUFFER_DESC desc = { 0 }; + List<unsigned int> newBuffer; + desc.ByteWidth = (UINT)calcAligned((bufferData.Count() * sizeof(unsigned int)), 256); + newBuffer.SetSize(desc.ByteWidth / sizeof(unsigned int)); + for (UInt i = 0; i < bufferData.Count(); i++) + newBuffer[i] = bufferData[i]; + if (bufferDesc.type == InputBufferType::ConstantBuffer) { - auto dxContext = dxImmediateContext; - D3D11_BUFFER_DESC desc = {0}; - List<unsigned int> newBuffer; - desc.ByteWidth = (UINT)RoundUpToAlignment((bufferData.Count() * sizeof(unsigned int)), 256); - newBuffer.SetSize(desc.ByteWidth / sizeof(unsigned int)); - for (UInt i = 0; i < bufferData.Count(); i++) - newBuffer[i] = bufferData[i]; - if (bufferDesc.type == InputBufferType::ConstantBuffer) + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + } + else + { + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; + if (bufferDesc.stride != 0) { - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.StructureByteStride = bufferDesc.stride; + desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; } else { - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; - if (bufferDesc.stride != 0) - { - desc.StructureByteStride = bufferDesc.stride; - desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - } - else - { - desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; - } + desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; } - D3D11_SUBRESOURCE_DATA data = {0}; - data.pSysMem = newBuffer.Buffer(); - dxDevice->CreateBuffer(&desc, &data, &bufferOut); - int elemSize = bufferDesc.stride <= 0 ? 1 : bufferDesc.stride; - if (bufferDesc.type == InputBufferType::StorageBuffer) + } + D3D11_SUBRESOURCE_DATA data = { 0 }; + data.pSysMem = newBuffer.Buffer(); + dxDevice->CreateBuffer(&desc, &data, &bufferOut); + int elemSize = bufferDesc.stride <= 0 ? 1 : bufferDesc.stride; + if (bufferDesc.type == InputBufferType::StorageBuffer) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC viewDesc; + memset(&viewDesc, 0, sizeof(viewDesc)); + viewDesc.Buffer.FirstElement = 0; + viewDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize); + viewDesc.Buffer.Flags = 0; + viewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + viewDesc.Format = DXGI_FORMAT_UNKNOWN; + + if (bufferDesc.stride == 0) { - D3D11_UNORDERED_ACCESS_VIEW_DESC viewDesc; - memset(&viewDesc, 0, sizeof(viewDesc)); - viewDesc.Buffer.FirstElement = 0; - viewDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize); - viewDesc.Buffer.Flags = 0; - viewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - viewDesc.Format = DXGI_FORMAT_UNKNOWN; - - if( bufferDesc.stride == 0 ) - { - // TODO: are there UAV cases we need to handle that are neither - // raw nor structured? RWBuffer<T> would be one... + // TODO: are there UAV cases we need to handle that are neither + // raw nor structured? RWBuffer<T> would be one... - viewDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW; - viewDesc.Format = DXGI_FORMAT_R32_TYPELESS; - } - - dxDevice->CreateUnorderedAccessView(bufferOut, &viewDesc, &viewOut); - } - if (bufferDesc.type != InputBufferType::ConstantBuffer) - { - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - memset(&srvDesc, 0, sizeof(srvDesc)); - srvDesc.Buffer.FirstElement = 0; - srvDesc.Buffer.ElementWidth = elemSize; - srvDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize); - srvDesc.Buffer.ElementOffset = 0; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - dxDevice->CreateShaderResourceView(bufferOut, &srvDesc, &srvOut); + viewDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW; + viewDesc.Format = DXGI_FORMAT_R32_TYPELESS; } + + dxDevice->CreateUnorderedAccessView(bufferOut, &viewDesc, &viewOut); } + if (bufferDesc.type != InputBufferType::ConstantBuffer) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + memset(&srvDesc, 0, sizeof(srvDesc)); + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.ElementWidth = elemSize; + srvDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize); + srvDesc.Buffer.ElementOffset = 0; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + dxDevice->CreateShaderResourceView(bufferOut, &srvDesc, &srvOut); + } +} - void createInputTexture(const InputTextureDesc & inputDesc, ID3D11ShaderResourceView * &viewOut) +void D3D11Renderer::createInputTexture(const InputTextureDesc & inputDesc, ID3D11ShaderResourceView * &viewOut) +{ + TextureData texData; + generateTextureData(texData, inputDesc); + List<D3D11_SUBRESOURCE_DATA> subRes; + for (int i = 0; i < texData.arraySize; i++) { - TextureData texData; - generateTextureData(texData, inputDesc); - List<D3D11_SUBRESOURCE_DATA> subRes; - for (int i = 0; i < texData.arraySize; i++) - { - int slice = 0; - for (int j = 0; j < texData.mipLevels; j++) - { - int size = texData.textureSize >> j; - D3D11_SUBRESOURCE_DATA res; - res.pSysMem = texData.dataBuffer[slice].Buffer(); - res.SysMemPitch = sizeof(unsigned int) * size; - res.SysMemSlicePitch = sizeof(unsigned int) * size * size; - subRes.Add(res); - slice++; - } - } - if (inputDesc.dimension == 1) - { - D3D11_TEXTURE1D_DESC desc = { 0 }; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.MiscFlags = 0; - desc.MipLevels = texData.mipLevels; - desc.ArraySize = texData.arraySize; - desc.Width = texData.textureSize; - desc.Usage = D3D11_USAGE_DEFAULT; - - ID3D11Texture1D * texture; - dxDevice->CreateTexture1D(&desc, subRes.Buffer(), &texture); - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; - - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D; - if (inputDesc.arrayLength != 0) - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY; - viewDesc.Texture1D.MipLevels = texData.mipLevels; - viewDesc.Texture1D.MostDetailedMip = 0; - viewDesc.Texture1DArray.ArraySize = texData.arraySize; - viewDesc.Texture1DArray.FirstArraySlice = 0; - viewDesc.Texture1DArray.MipLevels = texData.mipLevels; - viewDesc.Texture1DArray.MostDetailedMip = 0; - viewDesc.Format = desc.Format; - dxDevice->CreateShaderResourceView(texture, &viewDesc, &viewOut); - } - else if (inputDesc.dimension == 2) - { - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; - D3D11_TEXTURE2D_DESC desc = { 0 }; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.MiscFlags = 0; - desc.MipLevels = texData.mipLevels; - desc.ArraySize = texData.arraySize; - if (inputDesc.isCube) - { - desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - viewDesc.TextureCube.MipLevels = texData.mipLevels; - viewDesc.TextureCube.MostDetailedMip = 0; - viewDesc.TextureCubeArray.MipLevels = texData.mipLevels; - viewDesc.TextureCubeArray.MostDetailedMip = 0; - viewDesc.TextureCubeArray.First2DArrayFace = 0; - viewDesc.TextureCubeArray.NumCubes = inputDesc.arrayLength; - } - else - { - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - viewDesc.Texture2D.MipLevels = texData.mipLevels; - viewDesc.Texture2D.MostDetailedMip = 0; - viewDesc.Texture2DArray.ArraySize = texData.arraySize; - viewDesc.Texture2DArray.FirstArraySlice = 0; - viewDesc.Texture2DArray.MipLevels = texData.mipLevels; - viewDesc.Texture2DArray.MostDetailedMip = 0; - } - if (inputDesc.arrayLength != 0) - viewDesc.ViewDimension = (D3D11_SRV_DIMENSION)(int)(viewDesc.ViewDimension + 1); - desc.Width = texData.textureSize; - desc.Height = texData.textureSize; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - viewDesc.Format = desc.Format; - ID3D11Texture2D * texture; - dxDevice->CreateTexture2D(&desc, subRes.Buffer(), &texture); - dxDevice->CreateShaderResourceView(texture, &viewDesc, &viewOut); - } - else if (inputDesc.dimension == 3) + int slice = 0; + for (int j = 0; j < texData.mipLevels; j++) { - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; - D3D11_TEXTURE3D_DESC desc = { 0 }; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.MiscFlags = 0; - desc.MipLevels = 1; - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; - desc.Width = texData.textureSize; - desc.Height = texData.textureSize; - desc.Depth = texData.textureSize; - desc.Usage = D3D11_USAGE_DEFAULT; - ID3D11Texture3D * texture; - dxDevice->CreateTexture3D(&desc, subRes.Buffer(), &texture); - viewDesc.Texture3D.MipLevels = 1; - viewDesc.Texture3D.MostDetailedMip = 0; - viewDesc.Format = desc.Format; - dxDevice->CreateShaderResourceView(texture, &viewDesc, &viewOut); + int size = texData.textureSize >> j; + D3D11_SUBRESOURCE_DATA res; + res.pSysMem = texData.dataBuffer[slice].Buffer(); + res.SysMemPitch = sizeof(unsigned int) * size; + res.SysMemSlicePitch = sizeof(unsigned int) * size * size; + subRes.Add(res); + slice++; } } - - void createInputSampler(const InputSamplerDesc & inputDesc, ID3D11SamplerState * & stateOut) + if (inputDesc.dimension == 1) + { + D3D11_TEXTURE1D_DESC desc = { 0 }; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.MiscFlags = 0; + desc.MipLevels = texData.mipLevels; + desc.ArraySize = texData.arraySize; + desc.Width = texData.textureSize; + desc.Usage = D3D11_USAGE_DEFAULT; + + ID3D11Texture1D * texture; + dxDevice->CreateTexture1D(&desc, subRes.Buffer(), &texture); + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D; + if (inputDesc.arrayLength != 0) + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY; + viewDesc.Texture1D.MipLevels = texData.mipLevels; + viewDesc.Texture1D.MostDetailedMip = 0; + viewDesc.Texture1DArray.ArraySize = texData.arraySize; + viewDesc.Texture1DArray.FirstArraySlice = 0; + viewDesc.Texture1DArray.MipLevels = texData.mipLevels; + viewDesc.Texture1DArray.MostDetailedMip = 0; + viewDesc.Format = desc.Format; + dxDevice->CreateShaderResourceView(texture, &viewDesc, &viewOut); + } + else if (inputDesc.dimension == 2) { - D3D11_SAMPLER_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - if (inputDesc.isCompareSampler) + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + D3D11_TEXTURE2D_DESC desc = { 0 }; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.MiscFlags = 0; + desc.MipLevels = texData.mipLevels; + desc.ArraySize = texData.arraySize; + if (inputDesc.isCube) { - desc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; - desc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - desc.MinLOD = desc.MaxLOD = 0.0f; + desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + viewDesc.TextureCube.MipLevels = texData.mipLevels; + viewDesc.TextureCube.MostDetailedMip = 0; + viewDesc.TextureCubeArray.MipLevels = texData.mipLevels; + viewDesc.TextureCubeArray.MostDetailedMip = 0; + viewDesc.TextureCubeArray.First2DArrayFace = 0; + viewDesc.TextureCubeArray.NumCubes = inputDesc.arrayLength; } else { - desc.Filter = D3D11_FILTER_ANISOTROPIC; - desc.MaxAnisotropy = 8; - desc.MinLOD = 0.0f; - desc.MaxLOD = 100.0f; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MipLevels = texData.mipLevels; + viewDesc.Texture2D.MostDetailedMip = 0; + viewDesc.Texture2DArray.ArraySize = texData.arraySize; + viewDesc.Texture2DArray.FirstArraySlice = 0; + viewDesc.Texture2DArray.MipLevels = texData.mipLevels; + viewDesc.Texture2DArray.MostDetailedMip = 0; } - dxDevice->CreateSamplerState(&desc, &stateOut); + if (inputDesc.arrayLength != 0) + viewDesc.ViewDimension = (D3D11_SRV_DIMENSION)(int)(viewDesc.ViewDimension + 1); + desc.Width = texData.textureSize; + desc.Height = texData.textureSize; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + viewDesc.Format = desc.Format; + ID3D11Texture2D * texture; + dxDevice->CreateTexture2D(&desc, subRes.Buffer(), &texture); + dxDevice->CreateShaderResourceView(texture, &viewDesc, &viewOut); + } + else if (inputDesc.dimension == 3) + { + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + D3D11_TEXTURE3D_DESC desc = { 0 }; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.MiscFlags = 0; + desc.MipLevels = 1; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + desc.Width = texData.textureSize; + desc.Height = texData.textureSize; + desc.Depth = texData.textureSize; + desc.Usage = D3D11_USAGE_DEFAULT; + ID3D11Texture3D * texture; + dxDevice->CreateTexture3D(&desc, subRes.Buffer(), &texture); + viewDesc.Texture3D.MipLevels = 1; + viewDesc.Texture3D.MostDetailedMip = 0; + viewDesc.Format = desc.Format; + dxDevice->CreateShaderResourceView(texture, &viewDesc, &viewOut); + } +} + +void D3D11Renderer::createInputSampler(const InputSamplerDesc & inputDesc, ID3D11SamplerState * & stateOut) +{ + D3D11_SAMPLER_DESC desc; + memset(&desc, 0, sizeof(desc)); + desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + if (inputDesc.isCompareSampler) + { + desc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; + desc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + desc.MinLOD = desc.MaxLOD = 0.0f; + } + else + { + desc.Filter = D3D11_FILTER_ANISOTROPIC; + desc.MaxAnisotropy = 8; + desc.MinLOD = 0.0f; + desc.MaxLOD = 100.0f; } - virtual BindingState * createBindingState(const ShaderInputLayout & layout) + dxDevice->CreateSamplerState(&desc, &stateOut); +} + +BindingState * D3D11Renderer::createBindingState(const ShaderInputLayout& layout) +{ + BindingStateImpl * rs = new BindingStateImpl(); + rs->numRenderTargets = layout.numRenderTargets; + for (auto & entry : layout.entries) { - D3DBindingState * rs = new D3DBindingState(); - rs->numRenderTargets = layout.numRenderTargets; - for (auto & entry : layout.entries) + BindingImpl rsEntry; + rsEntry.type = entry.type; + rsEntry.binding = entry.hlslBinding; + rsEntry.isOutput = entry.isOutput; + switch (entry.type) { - D3DBinding rsEntry; - rsEntry.type = entry.type; - rsEntry.binding = entry.hlslBinding; - rsEntry.isOutput = entry.isOutput; - switch (entry.type) - { case ShaderInputType::Buffer: { createInputBuffer(entry.bufferDesc, entry.bufferData, rsEntry.buffer, rsEntry.uav, rsEntry.srv); @@ -1005,133 +1003,127 @@ public: throw "not implemented"; } break; - } - rs->bindings.Add(rsEntry); } - - return (BindingState*)rs; + rs->bindings.Add(rsEntry); } - void applyBindingState(bool isCompute) + return (BindingState*)rs; +} + +void D3D11Renderer::applyBindingState(bool isCompute) +{ + auto dxContext = dxImmediateContext; + for (auto & binding : currentBindings->bindings) { - auto dxContext = dxImmediateContext; - for (auto & binding : currentBindings->bindings) + if (binding.type == ShaderInputType::Buffer) { - if (binding.type == ShaderInputType::Buffer) + if (binding.bufferType == InputBufferType::ConstantBuffer) { - if (binding.bufferType == InputBufferType::ConstantBuffer) - { - if (isCompute) - dxContext->CSSetConstantBuffers(binding.binding, 1, &binding.buffer); - else - { - dxContext->VSSetConstantBuffers(binding.binding, 1, &binding.buffer); - dxContext->PSSetConstantBuffers(binding.binding, 1, &binding.buffer); - } - } - else if (binding.uav) - { - if (isCompute) - dxContext->CSSetUnorderedAccessViews(binding.binding, 1, &binding.uav, nullptr); - else - dxContext->OMSetRenderTargetsAndUnorderedAccessViews(currentBindings->numRenderTargets, - dxRenderTargetViews.Buffer(), nullptr, binding.binding, 1, &binding.uav, nullptr); - } + if (isCompute) + dxContext->CSSetConstantBuffers(binding.binding, 1, &binding.buffer); else { - if (isCompute) - dxContext->CSSetShaderResources(binding.binding, 1, &binding.srv); - else - { - dxContext->PSSetShaderResources(binding.binding, 1, &binding.srv); - dxContext->VSSetShaderResources(binding.binding, 1, &binding.srv); - } + dxContext->VSSetConstantBuffers(binding.binding, 1, &binding.buffer); + dxContext->PSSetConstantBuffers(binding.binding, 1, &binding.buffer); } } - else if (binding.type == ShaderInputType::Texture) + else if (binding.uav) { - if (binding.uav) - { - if (isCompute) - dxContext->CSSetUnorderedAccessViews(binding.binding, 1, &binding.uav, nullptr); - else - dxContext->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, - nullptr, nullptr, binding.binding, 1, &binding.uav, nullptr); - } + if (isCompute) + dxContext->CSSetUnorderedAccessViews(binding.binding, 1, &binding.uav, nullptr); + else + dxContext->OMSetRenderTargetsAndUnorderedAccessViews(currentBindings->numRenderTargets, + dxRenderTargetViews.Buffer(), nullptr, binding.binding, 1, &binding.uav, nullptr); + } + else + { + if (isCompute) + dxContext->CSSetShaderResources(binding.binding, 1, &binding.srv); else { - if (isCompute) - dxContext->CSSetShaderResources(binding.binding, 1, &binding.srv); - else - { - dxContext->PSSetShaderResources(binding.binding, 1, &binding.srv); - dxContext->VSSetShaderResources(binding.binding, 1, &binding.srv); - } + dxContext->PSSetShaderResources(binding.binding, 1, &binding.srv); + dxContext->VSSetShaderResources(binding.binding, 1, &binding.srv); } } - else if (binding.type == ShaderInputType::Sampler) + } + else if (binding.type == ShaderInputType::Texture) + { + if (binding.uav) + { + if (isCompute) + dxContext->CSSetUnorderedAccessViews(binding.binding, 1, &binding.uav, nullptr); + else + dxContext->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, + nullptr, nullptr, binding.binding, 1, &binding.uav, nullptr); + } + else { if (isCompute) - dxContext->CSSetSamplers(binding.binding, 1, &binding.samplerState); + dxContext->CSSetShaderResources(binding.binding, 1, &binding.srv); else { - dxContext->PSSetSamplers(binding.binding, 1, &binding.samplerState); - dxContext->VSSetSamplers(binding.binding, 1, &binding.samplerState); + dxContext->PSSetShaderResources(binding.binding, 1, &binding.srv); + dxContext->VSSetShaderResources(binding.binding, 1, &binding.srv); } } + } + else if (binding.type == ShaderInputType::Sampler) + { + if (isCompute) + dxContext->CSSetSamplers(binding.binding, 1, &binding.samplerState); else - throw "not implemented"; + { + dxContext->PSSetSamplers(binding.binding, 1, &binding.samplerState); + dxContext->VSSetSamplers(binding.binding, 1, &binding.samplerState); + } } + else + throw "not implemented"; } +} - virtual void setBindingState(BindingState * state) - { - auto dxBindingState = (D3DBindingState*) state; - currentBindings = dxBindingState; - } +void D3D11Renderer::setBindingState(BindingState* state) +{ + auto dxBindingState = (BindingStateImpl*)state; + currentBindings = dxBindingState; +} - virtual void serializeOutput(BindingState* state, const char * fileName) +void D3D11Renderer::serializeOutput(BindingState* state, const char* fileName) +{ + auto dxContext = dxImmediateContext; + auto dxBindingState = (BindingStateImpl*)state; + FILE * f = fopen(fileName, "wb"); + int id = 0; + for (auto & binding : dxBindingState->bindings) { - auto dxContext = dxImmediateContext; - auto dxBindingState = (D3DBindingState*)state; - FILE * f = fopen(fileName, "wb"); - int id = 0; - for (auto & binding : dxBindingState->bindings) + if (binding.isOutput) { - if (binding.isOutput) + if (binding.buffer) { - if (binding.buffer) - { - // create staging buffer - ID3D11Buffer* stageBuf; - D3D11_BUFFER_DESC bufDesc; - memset(&bufDesc, 0, sizeof(bufDesc)); - bufDesc.BindFlags = 0; - bufDesc.ByteWidth = (UINT)RoundUpToAlignment(binding.bufferLength, 256); - bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - bufDesc.Usage = D3D11_USAGE_STAGING; - dxDevice->CreateBuffer(&bufDesc, nullptr, &stageBuf); - dxContext->CopyResource(stageBuf, binding.buffer); - auto ptr = (unsigned int *)map(stageBuf, MapFlavor::HostRead); - for (auto i = 0u; i < binding.bufferLength / sizeof(unsigned int); i++) - fprintf(f, "%X\n", ptr[i]); - unmap(stageBuf); - stageBuf->Release(); - } - else - { - printf("invalid output type at %d.\n", id); - } + // create staging buffer + ID3D11Buffer* stageBuf; + D3D11_BUFFER_DESC bufDesc; + memset(&bufDesc, 0, sizeof(bufDesc)); + bufDesc.BindFlags = 0; + bufDesc.ByteWidth = (UINT)calcAligned(binding.bufferLength, 256); + bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bufDesc.Usage = D3D11_USAGE_STAGING; + dxDevice->CreateBuffer(&bufDesc, nullptr, &stageBuf); + dxContext->CopyResource(stageBuf, binding.buffer); + auto ptr = (unsigned int *)map(stageBuf, MapFlavor::HostRead); + for (auto i = 0u; i < binding.bufferLength / sizeof(unsigned int); i++) + fprintf(f, "%X\n", ptr[i]); + unmap(stageBuf); + stageBuf->Release(); + } + else + { + printf("invalid output type at %d.\n", id); } - id++; } - fclose(f); + id++; } -}; - -Renderer* createD3D11Renderer() -{ - return new D3D11Renderer(); + fclose(f); } } // renderer_test diff --git a/tools/render-test/render-d3d12.cpp b/tools/render-test/render-d3d12.cpp index f0b0eb478..d481d7084 100644 --- a/tools/render-test/render-d3d12.cpp +++ b/tools/render-test/render-d3d12.cpp @@ -1,4 +1,4 @@ -// render-d3d12.cpp +// render-d3d12.cpp #include "render-d3d12.h" #include "options.h" @@ -46,279 +46,300 @@ ID3DBlob* compileHLSLShader( char const* entryPointName, char const* dxProfileName); -static char const* vertexProfileName = "vs_4_0"; -static char const* fragmentProfileName = "ps_4_0"; +//static char const* vertexProfileName = "vs_4_0"; +//static char const* fragmentProfileName = "ps_4_0"; // - class D3D12Renderer : public Renderer, public ShaderCompiler { public: - IDXGISwapChain* dxSwapChain = nullptr; + // Renderer implementation + virtual SlangResult initialize(void* inWindowHandle) override; + virtual void setClearColor(float const* color) override; + virtual void clearFrame() override; + virtual void presentFrame() override; + virtual SlangResult captureScreenShot(char const* outputPath) override; + virtual void serializeOutput(BindingState* state, const char * fileName) override; + virtual Buffer* createBuffer(BufferDesc const& desc) override; + virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override; + virtual BindingState * createBindingState(const ShaderInputLayout & layout) override; + virtual ShaderCompiler* getShaderCompiler() override; + virtual void* map(Buffer* buffer, MapFlavor flavor) override; + virtual void unmap(Buffer* buffer) override; + virtual void setInputLayout(InputLayout* inputLayout) override; + virtual void setPrimitiveTopology(PrimitiveTopology topology) override; + virtual void setBindingState(BindingState * state); + 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; + + // ShaderCompiler implementation + virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override; + + protected: + PROC loadProc(HMODULE module, char const* name); + static DXGI_FORMAT mapFormat(Format format); + float clearColor[4] = { 0, 0, 0, 0 }; + IDXGISwapChain* dxSwapChain = nullptr; ID3D12Device* dxDevice = nullptr; +}; + +Renderer* createD3D12Renderer() +{ + return new D3D12Renderer; +} - virtual PROC loadProc( - HMODULE module, - char const* name) +PROC D3D12Renderer::loadProc(HMODULE module, char const* name) +{ + PROC proc = ::GetProcAddress(module, name); + if (!proc) { - PROC proc = GetProcAddress(module, name); - if( !proc ) - { - fprintf(stderr, - "error: failed load symbol '%s'\n", name); - return nullptr; - } - return proc; + fprintf(stderr, "error: failed load symbol '%s'\n", name); + return nullptr; } + return proc; +} - virtual SlangResult initialize(void* inWindowHandle) override +/* static */DXGI_FORMAT D3D12Renderer::mapFormat(Format format) +{ + switch (format) { - auto windowHandle = (HWND) inWindowHandle; - // Rather than statically link against D3D, we load it dynamically. + case Format::RGB_Float32: + return DXGI_FORMAT_R32G32B32_FLOAT; + case Format::RG_Float32: + return DXGI_FORMAT_R32G32_FLOAT; + default: + return DXGI_FORMAT_UNKNOWN; + } +} - HMODULE d3d12 = LoadLibraryA("d3d12.dll"); - if(!d3d12) - { - fprintf(stderr, "error: failed load 'd3d12.dll'\n"); - return SLANG_FAIL; - } +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! + +SlangResult D3D12Renderer::initialize(void* inWindowHandle) +{ + 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"); + return SLANG_FAIL; + } #define LOAD_PROC(TYPE, NAME) \ TYPE NAME##_ = (TYPE) loadProc(d3d12, #NAME); \ - if (NAME##_ == nullptr) return SLANG_FAIL; + if (NAME##_ == nullptr) return SLANG_FAIL; - UINT dxgiFactoryFlags = 0; + UINT dxgiFactoryFlags = 0; #if ENABLE_DEBUG_LAYER - LOAD_PROC(PFN_D3D12_GET_DEBUG_INTERFACE, D3D12GetDebugInterface); + LOAD_PROC(PFN_D3D12_GET_DEBUG_INTERFACE, D3D12GetDebugInterface); - ID3D12Debug* debugController; - if(SUCCEEDED(D3D12GetDebugInterface_(IID_PPV_ARGS(&debugController)))) - { - debugController->EnableDebugLayer(); - dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; - } + 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); + typedef HRESULT(WINAPI *PFN_DXGI_CREATE_FACTORY_2)(UINT Flags, REFIID riid, _COM_Outptr_ void **ppFactory); - IDXGIFactory4* dxgiFactory; - SLANG_RETURN_ON_FAIL(CreateDXGIFactory2_(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory))); + LOAD_PROC(PFN_DXGI_CREATE_FACTORY_2, CreateDXGIFactory2); - D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; + IDXGIFactory4* dxgiFactory; + SLANG_RETURN_ON_FAIL(CreateDXGIFactory2_(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory))); - // Search for an adapter that meets our requirements - IDXGIAdapter* adapter = nullptr; + D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; - LOAD_PROC(PFN_D3D12_CREATE_DEVICE, D3D12CreateDevice); + // Search for an adapter that meets our requirements + IDXGIAdapter* adapter = nullptr; - UINT adapterCounter = 0; - for(;;) + 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) { - 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(); + // TODO: may want to allow software driver as fallback } - - if(!adapter) + else if (SUCCEEDED(D3D12CreateDevice_(candidateAdapter, featureLevel, IID_PPV_ARGS(&dxDevice)))) { - // Couldn't find an adapter - return SLANG_FAIL; + // We found one! + adapter = candidateAdapter; + break; } - // Command Queue - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + candidateAdapter->Release(); + } - ID3D12CommandQueue* commandQueue; - SLANG_RETURN_ON_FAIL(dxDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue))); + if (!adapter) + { + // Couldn't find an adapter + return SLANG_FAIL; + } - // Swap Chain - UINT frameCount = 2; // TODO: configure + // Command Queue + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - 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; + ID3D12CommandQueue* commandQueue; + SLANG_RETURN_ON_FAIL(dxDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue))); - IDXGISwapChain1* swapChain; - SLANG_RETURN_ON_FAIL(dxgiFactory->CreateSwapChainForHwnd( - commandQueue, - windowHandle, - &swapChainDesc, - nullptr, - nullptr, - &swapChain)); + // Swap Chain + UINT frameCount = 2; // TODO: configure - // Is this needed? - dxgiFactory->MakeWindowAssociation(windowHandle, DXGI_MWA_NO_ALT_ENTER); + 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; - IDXGISwapChain3* swapChainEx; - SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(IID_PPV_ARGS(&swapChainEx))); + IDXGISwapChain1* swapChain; + SLANG_RETURN_ON_FAIL(dxgiFactory->CreateSwapChainForHwnd(commandQueue, windowHandle, &swapChainDesc, nullptr, nullptr, &swapChain)); - UINT frameIndex = swapChainEx->GetCurrentBackBufferIndex(); + // Is this needed? + dxgiFactory->MakeWindowAssociation(windowHandle, DXGI_MWA_NO_ALT_ENTER); - // Descriptor heaps + IDXGISwapChain3* swapChainEx; + SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(IID_PPV_ARGS(&swapChainEx))); - D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; - rtvHeapDesc.NumDescriptors = frameCount; - rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + UINT frameIndex = swapChainEx->GetCurrentBackBufferIndex(); - ID3D12DescriptorHeap* rtvHeap; - SLANG_RETURN_ON_FAIL(dxDevice->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvHeap))); + // Descriptor heaps - UINT rtvDescriptorSize = dxDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; + rtvHeapDesc.NumDescriptors = frameCount; + rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart(); + ID3D12DescriptorHeap* rtvHeap; + SLANG_RETURN_ON_FAIL(dxDevice->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvHeap))); - // Create per-frame RTVs - ID3D12Resource* backBufferResources[2]; - for( UINT ff = 0; ff < frameCount; ++ff ) - { - SLANG_RETURN_ON_FAIL(swapChainEx->GetBuffer(ff, IID_PPV_ARGS(&backBufferResources[ff]))); - dxDevice->CreateRenderTargetView(backBufferResources[ff], nullptr, rtvHandle); - rtvHandle.ptr += rtvDescriptorSize; - } + UINT rtvDescriptorSize = dxDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - ID3D12CommandAllocator* commandAllocator; - SLANG_RETURN_ON_FAIL(dxDevice->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator))); - return SLANG_OK; - } + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart(); - float clearColor[4] = { 0, 0, 0, 0 }; - virtual void setClearColor(float const* color) override + // Create per-frame RTVs + ID3D12Resource* backBufferResources[2]; + for (UINT ff = 0; ff < frameCount; ++ff) { - memcpy(clearColor, color, sizeof(clearColor)); + SLANG_RETURN_ON_FAIL(swapChainEx->GetBuffer(ff, IID_PPV_ARGS(&backBufferResources[ff]))); + dxDevice->CreateRenderTargetView(backBufferResources[ff], nullptr, rtvHandle); + rtvHandle.ptr += rtvDescriptorSize; } - virtual void clearFrame() override - { - } + ID3D12CommandAllocator* commandAllocator; + SLANG_RETURN_ON_FAIL(dxDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator))); + return SLANG_OK; +} - virtual void presentFrame() override - { - } +void D3D12Renderer::setClearColor(float const* color) +{ + memcpy(clearColor, color, sizeof(clearColor)); +} - virtual SlangResult captureScreenShot(char const* outputPath) override - { - return SLANG_FAIL; - } +void D3D12Renderer::clearFrame() +{ +} - virtual ShaderCompiler* getShaderCompiler() override - { - return this; - } +void D3D12Renderer::presentFrame() +{ +} - virtual Buffer* createBuffer(BufferDesc const& desc) override - { - return nullptr; - } +SlangResult D3D12Renderer::captureScreenShot(char const* outputPath) +{ + return SLANG_FAIL; +} - 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; - } - } +ShaderCompiler* D3D12Renderer::getShaderCompiler() +{ + return this; +} - virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override - { - return nullptr; - } +Buffer* D3D12Renderer::createBuffer(BufferDesc const& desc) +{ + return nullptr; +} - virtual void* map(Buffer* buffer, MapFlavor flavor) override - { - return nullptr; - } - virtual void unmap(Buffer* buffer) override - { - } +InputLayout* D3D12Renderer::createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) +{ + return nullptr; +} - virtual void setInputLayout(InputLayout* inputLayout) override - { - } +void* D3D12Renderer::map(Buffer* buffer, MapFlavor flavor) +{ + return nullptr; +} - virtual void setPrimitiveTopology(PrimitiveTopology topology) override - { - } +void D3D12Renderer::unmap(Buffer* buffer) +{ +} - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override - { - } +void D3D12Renderer::setInputLayout(InputLayout* inputLayout) +{ +} - virtual void setShaderProgram(ShaderProgram* inProgram) override - { - } +void D3D12Renderer::setPrimitiveTopology(PrimitiveTopology topology) +{ +} - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override - { - } +void D3D12Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) +{ +} - virtual void draw(UInt vertexCount, UInt startVertex) override - { - } +void D3D12Renderer::setShaderProgram(ShaderProgram* inProgram) +{ +} +void D3D12Renderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) +{ +} - virtual void dispatchCompute(int x, int y, int z) override - { - } +void D3D12Renderer::draw(UInt vertexCount, UInt startVertex) +{ +} - virtual BindingState * createBindingState(const ShaderInputLayout & layout) - { - return nullptr; - } - virtual void setBindingState(BindingState * state) - { - } +void D3D12Renderer::dispatchCompute(int x, int y, int z) +{ +} - virtual void serializeOutput(BindingState* state, const char * fileName) - { - } +BindingState* D3D12Renderer::createBindingState(const ShaderInputLayout & layout) +{ + return nullptr; +} - // ShaderCompiler interface +void D3D12Renderer::setBindingState(BindingState * state) +{ +} - virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override - { - return nullptr; - } +void D3D12Renderer::serializeOutput(BindingState* state, const char * fileName) +{ +} -}; +// ShaderCompiler interface -Renderer* createD3D12Renderer() +ShaderProgram* D3D12Renderer::compileProgram(ShaderCompileRequest const& request) { - return new D3D12Renderer(); + return nullptr; } } // renderer_test + diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp index c2195f4f0..7f6e401e5 100644 --- a/tools/render-test/render-gl.cpp +++ b/tools/render-test/render-gl.cpp @@ -59,8 +59,8 @@ F(glEnableVertexAttribArray, PFNGLENABLEVERTEXATTRIBARRAYPROC) \ F(glDisableVertexAttribArray, PFNGLDISABLEVERTEXATTRIBARRAYPROC) \ F(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \ - F(glDispatchCompute, PFNGLDISPATCHCOMPUTEPROC) \ - F(glActiveTexture, PFNGLACTIVETEXTUREPROC) \ + F(glDispatchCompute, PFNGLDISPATCHCOMPUTEPROC) \ + F(glActiveTexture, PFNGLACTIVETEXTUREPROC) \ F(glCreateSamplers, PFNGLCREATESAMPLERSPROC) \ F(glBindSampler, PFNGLBINDSAMPLERPROC) \ F(glTexImage3D, PFNGLTEXIMAGE3DPROC) \ @@ -74,189 +74,37 @@ namespace renderer_test { class GLRenderer : public Renderer, public ShaderCompiler { public: - HDC deviceContext; - HGLRC glContext; - - // Declre a function pointer for each OpenGL - // extension function we need to load - -#define DECLARE_GL_EXTENSION_FUNC(NAME, TYPE) TYPE NAME; - MAP_GL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC) -#undef DECLARE_GL_EXTENSION_FUNC - - // Renderer interface - - virtual SlangResult initialize(void* inWindowHandle) override - { - auto windowHandle = (HWND) inWindowHandle; - - deviceContext = GetDC(windowHandle); - - PIXELFORMATDESCRIPTOR pixelFormatDesc = { sizeof(PIXELFORMATDESCRIPTOR) }; - pixelFormatDesc.nVersion = 1; - pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pixelFormatDesc.iPixelType = PFD_TYPE_RGBA; - pixelFormatDesc.cColorBits = 32; - pixelFormatDesc.cDepthBits = 24; - pixelFormatDesc.cStencilBits = 8; - pixelFormatDesc.iLayerType = PFD_MAIN_PLANE; - - int pixelFormatIndex = ChoosePixelFormat(deviceContext, &pixelFormatDesc); - SetPixelFormat(deviceContext, pixelFormatIndex, &pixelFormatDesc); - - glContext = wglCreateContext(deviceContext); - wglMakeCurrent(deviceContext, glContext); - - auto renderer = glGetString(GL_RENDERER); - auto extensions = glGetString(GL_EXTENSIONS); - - // Load ech of our etension functions by name - - #define LOAD_GL_EXTENSION_FUNC(NAME, TYPE) NAME = (TYPE) wglGetProcAddress(#NAME); - MAP_GL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC) - #undef LOAD_GL_EXTENSION_FUNC - - - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - glViewport(0, 0, gWindowWidth, gWindowHeight); - - if (glDebugMessageCallback) - { - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(staticDebugCallback, this); - } - - return SLANG_OK; - } - - void debugCallback( - GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - GLchar const* message) - { - OutputDebugStringA("GL: "); - OutputDebugStringA(message); - OutputDebugStringA("\n"); - - switch (type) - { - case GL_DEBUG_TYPE_ERROR: - break; - - default: - break; - } - } - - static void APIENTRY staticDebugCallback( - GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - GLchar const* message, - void const* userParam) - { - ((GLRenderer*) userParam)->debugCallback( - source, type, id, severity, length, message); - } - - float clearColor[4] = { 0, 0, 0, 0 }; - virtual void setClearColor(float const* color) override - { - glClearColor(color[0], color[1], color[2], color[3]); - } - - virtual void clearFrame() override - { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - - virtual void presentFrame() override - { - glFlush(); - SwapBuffers(deviceContext); - } - - virtual SlangResult captureScreenShot(char const* outputPath) override - { - int width = gWindowWidth; - int height = gWindowHeight; - - int components = 4; - int rowStride = width*components; - - GLubyte* buffer = (GLubyte*)::malloc(components * width * height); - - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); - - // OpenGL's "upside down" convention bites us here, so we need - // to flip the data in the buffer by swapping rows - int halfHeight = height / 2; - for (int hh = 0; hh < halfHeight; ++hh) - { - // Get a pointer to the row data, and a pointer - // to the row on the "other end" of the image - GLubyte* rowA = buffer + rowStride*hh; - GLubyte* rowB = buffer + rowStride*(height - (hh + 1)); - - for (int ii = 0; ii < rowStride; ++ii) - { - auto a = rowA[ii]; - auto b = rowB[ii]; - - rowA[ii] = b; - rowB[ii] = a; - } - } - - // - - int stbResult = stbi_write_png( - outputPath, - width, - height, - components, - buffer, - rowStride); - - ::free(buffer); - - if( !stbResult ) - { - assert(!"unexpected"); - return SLANG_FAIL; - } - - return SLANG_OK; - } - - virtual ShaderCompiler* getShaderCompiler() override - { - return this; - } - - virtual Buffer* createBuffer(BufferDesc const& desc) override + + // Renderer implementation + virtual SlangResult initialize(void* inWindowHandle) override; + virtual void setClearColor(float const* color) override; + virtual void clearFrame() override; + virtual void presentFrame() override; + virtual SlangResult captureScreenShot(char const* outputPath) override; + virtual void serializeOutput(BindingState* state, const char * fileName) override; + virtual Buffer* createBuffer(BufferDesc const& desc) override; + virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override; + virtual BindingState * createBindingState(const ShaderInputLayout & layout) override; + virtual ShaderCompiler* getShaderCompiler() override; + virtual void* map(Buffer* buffer, MapFlavor flavor) override; + virtual void unmap(Buffer* buffer) override; + virtual void setInputLayout(InputLayout* inputLayout) override; + virtual void setPrimitiveTopology(PrimitiveTopology topology) override; + virtual void setBindingState(BindingState * state); + 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; + + // ShaderCompiler implementation + virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override; + + protected: + enum { - // TODO: should derive target from desc... - GLenum target = GL_UNIFORM_BUFFER; - - // TODO: should derive from desc... - GLenum usage = GL_DYNAMIC_DRAW; - - GLuint bufferID = 0; - glGenBuffers(1, &bufferID); - glBindBuffer(target, bufferID); - - glBufferData(target, desc.size, desc.initData, usage); - - return (Buffer*)(uintptr_t)bufferID; - } + kMaxVertexStreams = 16, + }; struct VertexAttributeFormat { @@ -272,290 +120,185 @@ public: GLsizei offset; }; - enum - { - kMaxVertexStreams = 16, - }; - struct InputLayoutImpl { VertexAttributeDesc attributes[kMaxVertexStreams]; UInt attributeCount = 0; }; - static VertexAttributeFormat getVertexAttributeFormat( - Format format) + struct BindingEntryImpl { - switch (format) - { - default: assert(!"unexpected"); return VertexAttributeFormat(); - - #define CASE(NAME, COUNT, TYPE, NORMALIZED) \ - case Format::NAME: do { VertexAttributeFormat result = {COUNT, TYPE, NORMALIZED}; return result; } while (0) - - CASE(RGB_Float32, 3, GL_FLOAT, GL_FALSE); - CASE(RG_Float32, 2, GL_FLOAT, GL_FALSE); - - #undef CASE - - } - } - - virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override - { - InputLayoutImpl* inputLayout = new InputLayoutImpl(); - - inputLayout->attributeCount = inputElementCount; - for (UInt ii = 0; ii < inputElementCount; ++ii) - { - auto& inputAttr = inputElements[ii]; - auto& glAttr = inputLayout->attributes[ii]; - - glAttr.streamIndex = 0; - glAttr.format = getVertexAttributeFormat(inputAttr.format); - glAttr.offset = (GLsizei) inputAttr.offset; - } - - return (InputLayout*)inputLayout; - } - - virtual void* map(Buffer* buffer, MapFlavor flavor) override + ShaderInputType type; + GLuint handle; + List<int> binding; + int bindTarget; + int bufferSize; + bool isOutput = false; + }; + struct BindingStateImpl { - GLenum target = GL_UNIFORM_BUFFER; - - GLuint access = 0; - switch (flavor) - { - case MapFlavor::WriteDiscard: - case MapFlavor::HostWrite: - access = GL_WRITE_ONLY; - break; - case MapFlavor::HostRead: - access = GL_READ_ONLY; - break; - } - - auto bufferID = (GLuint)(uintptr_t)buffer; - glBindBuffer(target, bufferID); - - return glMapBuffer(target, access); - } + List<BindingEntryImpl> entries; + }; - virtual void unmap(Buffer* buffer) override - { - GLenum target = GL_UNIFORM_BUFFER; + void bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets); + void flushStateForDraw(); + GLuint loadShader(GLenum stage, char const* source); + void createInputBuffer(BindingEntryImpl& rs, InputBufferDesc bufDesc, List<unsigned int>& bufferData); + void debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, GLchar const* message); + void createInputTexture(BindingEntryImpl& rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc); + void createInputSampler(BindingEntryImpl& rs, InputSamplerDesc samplerDesc); - auto bufferID = (GLuint)(uintptr_t)buffer; - glUnmapBuffer(target); - } + static void APIENTRY staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, GLchar const* message, void const* userParam); + static VertexAttributeFormat getVertexAttributeFormat(Format format); InputLayoutImpl* boundInputLayout = nullptr; - virtual void setInputLayout(InputLayout* inputLayout) override - { - boundInputLayout = (InputLayoutImpl*) inputLayout; - } - GLenum boundPrimitiveTopology = GL_TRIANGLES; - virtual void setPrimitiveTopology(PrimitiveTopology topology) override - { - GLenum glTopology = 0; - switch (topology) - { - #define CASE(NAME, VALUE) case PrimitiveTopology::NAME: glTopology = VALUE; break - - CASE(TriangleList, GL_TRIANGLES); - - #undef CASE - } - boundPrimitiveTopology = glTopology; - } - + HDC deviceContext; + HGLRC glContext; + float clearColor[4] = { 0, 0, 0, 0 }; GLuint boundVertexStreamBuffers[kMaxVertexStreams]; UInt boundVertexStreamStrides[kMaxVertexStreams]; UInt boundVertexStreamOffsets[kMaxVertexStreams]; - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override - { - for (UInt ii = 0; ii < slotCount; ++ii) - { - UInt slot = startSlot + ii; + // Declare a function pointer for each OpenGL + // extension function we need to load +#define DECLARE_GL_EXTENSION_FUNC(NAME, TYPE) TYPE NAME; + MAP_GL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC) +#undef DECLARE_GL_EXTENSION_FUNC +}; - Buffer* buffer = buffers[ii]; - GLuint bufferID = (GLuint)(uintptr_t)buffer; +Renderer* createGLRenderer() +{ + return new GLRenderer(); +} - boundVertexStreamBuffers[slot] = bufferID; - boundVertexStreamStrides[slot] = strides[ii]; - boundVertexStreamOffsets[slot] = offsets[ii]; - } - } +void GLRenderer::debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, GLchar const* message) +{ + ::OutputDebugStringA("GL: "); + ::OutputDebugStringA(message); + ::OutputDebugStringA("\n"); - virtual void setShaderProgram(ShaderProgram* program) override + switch (type) { - GLuint programID = (GLuint)(uintptr_t)program; - glUseProgram(programID); + case GL_DEBUG_TYPE_ERROR: + break; + default: + break; } +} - void bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) - { - for (UInt ii = 0; ii < slotCount; ++ii) - { - UInt slot = startSlot + ii; - - Buffer* buffer = buffers[ii]; - GLuint bufferID = (GLuint)(uintptr_t)buffer; +/* static */void APIENTRY GLRenderer::staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, GLchar const* message, void const* userParam) +{ + ((GLRenderer*)userParam)->debugCallback(source, type, id, severity, length, message); +} - assert(!offsets || !offsets[ii]); +/* static */GLRenderer::VertexAttributeFormat GLRenderer::getVertexAttributeFormat(Format format) +{ + switch (format) + { + default: assert(!"unexpected"); return VertexAttributeFormat(); - glBindBufferBase(target, (GLuint)slot, bufferID); - } - } +#define CASE(NAME, COUNT, TYPE, NORMALIZED) \ + case Format::NAME: do { VertexAttributeFormat result = {COUNT, TYPE, NORMALIZED}; return result; } while (0) - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override - { - bindBufferImpl(GL_UNIFORM_BUFFER, startSlot, slotCount, buffers, offsets); + CASE(RGB_Float32, 3, GL_FLOAT, GL_FALSE); + CASE(RG_Float32, 2, GL_FLOAT, GL_FALSE); +#undef CASE } +} - void flushStateForDraw() +void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) +{ + for (UInt ii = 0; ii < slotCount; ++ii) { - auto layout = this->boundInputLayout; - auto attrCount = layout->attributeCount; - for (UInt ii = 0; ii < attrCount; ++ii) - { - auto& attr = layout->attributes[ii]; - - auto streamIndex = attr.streamIndex; + UInt slot = startSlot + ii; - glBindBuffer(GL_ARRAY_BUFFER, boundVertexStreamBuffers[streamIndex]); + Buffer* buffer = buffers[ii]; + GLuint bufferID = (GLuint)(uintptr_t)buffer; - glVertexAttribPointer( - (GLuint) ii, - attr.format.componentCount, - attr.format.componentType, - attr.format.normalized, - (GLsizei) boundVertexStreamStrides[streamIndex], - (GLvoid*)(attr.offset + boundVertexStreamOffsets[streamIndex])); + assert(!offsets || !offsets[ii]); - glEnableVertexAttribArray((GLuint)ii); - } - for (UInt ii = attrCount; ii < kMaxVertexStreams; ++ii) - { - glDisableVertexAttribArray((GLuint)ii); - } + glBindBufferBase(target, (GLuint)slot, bufferID); } +} - virtual void draw(UInt vertexCount, UInt startVertex = 0) override - { - flushStateForDraw(); - - glDrawArrays(boundPrimitiveTopology, (GLint) startVertex, (GLsizei) vertexCount); - } - - // ShaderCompiler interface - - virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override +void GLRenderer::flushStateForDraw() +{ + auto layout = this->boundInputLayout; + auto attrCount = layout->attributeCount; + for (UInt ii = 0; ii < attrCount; ++ii) { - auto programID = glCreateProgram(); - if (request.computeShader.name) - { - auto computeShaderID = loadShader(GL_COMPUTE_SHADER, request.computeShader.source.dataBegin); - - glAttachShader(programID, computeShaderID); - - - glLinkProgram(programID); - - glDeleteShader(computeShaderID); - } - else - { - auto vertexShaderID = loadShader(GL_VERTEX_SHADER, request.vertexShader.source.dataBegin); - auto fragmentShaderID = loadShader(GL_FRAGMENT_SHADER, request.fragmentShader.source.dataBegin); - - glAttachShader(programID, vertexShaderID); - glAttachShader(programID, fragmentShaderID); + auto& attr = layout->attributes[ii]; + auto streamIndex = attr.streamIndex; - glLinkProgram(programID); + glBindBuffer(GL_ARRAY_BUFFER, boundVertexStreamBuffers[streamIndex]); - glDeleteShader(vertexShaderID); - glDeleteShader(fragmentShaderID); - } - GLint success = GL_FALSE; - glGetProgramiv(programID, GL_LINK_STATUS, &success); - if( !success ) - { - int maxSize = 0; - glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &maxSize); - - auto infoBuffer = (char*)::malloc(maxSize); - - int infoSize = 0; - glGetProgramInfoLog(programID, maxSize, &infoSize, infoBuffer); - if( infoSize > 0 ) - { - fprintf(stderr, "%s", infoBuffer); - OutputDebugStringA(infoBuffer); - } - - ::free(infoBuffer); + glVertexAttribPointer( + (GLuint)ii, + attr.format.componentCount, + attr.format.componentType, + attr.format.normalized, + (GLsizei)boundVertexStreamStrides[streamIndex], + (GLvoid*)(attr.offset + boundVertexStreamOffsets[streamIndex])); - glDeleteProgram(programID); - return nullptr; - } - - return (ShaderProgram*) (uintptr_t) programID; + glEnableVertexAttribArray((GLuint)ii); } - - GLuint loadShader(GLenum stage, char const* source) + for (UInt ii = attrCount; ii < kMaxVertexStreams; ++ii) { + glDisableVertexAttribArray((GLuint)ii); + } +} - // GLSL in monumentally stupid. It officially requires the `#version` directive - // to be the first thing in the file, which wouldn't be so bad but the API - // doesn't provide a way to pass a `#define` into your shader other than by - // prepending it to the whole thing. - // - // We are going to solve this problem by doing some surgery on the source - // that was passed in. - - char const* sourceBegin = source; - char const* sourceEnd = source + strlen(source); - - // Look for a version directive in the user-provided source. - char const* versionBegin = strstr(source, "#version"); - char const* versionEnd = nullptr; - if( versionBegin ) +GLuint GLRenderer::loadShader(GLenum stage, char const* source) +{ + // GLSL is monumentally stupid. It officially requires the `#version` directive + // to be the first thing in the file, which wouldn't be so bad but the API + // doesn't provide a way to pass a `#define` into your shader other than by + // prepending it to the whole thing. + // + // We are going to solve this problem by doing some surgery on the source + // that was passed in. + + char const* sourceBegin = source; + char const* sourceEnd = source + strlen(source); + + // Look for a version directive in the user-provided source. + char const* versionBegin = strstr(source, "#version"); + char const* versionEnd = nullptr; + if (versionBegin) + { + // If we found a directive, then scan for the end-of-line + // after it, and use that to specify the slice. + versionEnd = strchr(versionBegin, '\n'); + if (!versionEnd) { - // If we found a directive, then scan for the end-of-line - // after it, and use that to specify the slice. - versionEnd = strchr(versionBegin, '\n'); - if( !versionEnd ) - { - versionEnd = sourceEnd; - } - else - { - versionEnd = versionEnd + 1; - } + versionEnd = sourceEnd; } else { - // If we didn't find a directive, then treat it as being - // a zero-byte slice at the start of the string - versionBegin = sourceBegin; - versionEnd = sourceBegin; + versionEnd = versionEnd + 1; } + } + else + { + // If we didn't find a directive, then treat it as being + // a zero-byte slice at the start of the string + versionBegin = sourceBegin; + versionEnd = sourceBegin; + } - enum { kMaxSourceStringCount = 16 }; - GLchar const* sourceStrings[kMaxSourceStringCount]; - GLint sourceStringLengths[kMaxSourceStringCount]; + enum { kMaxSourceStringCount = 16 }; + GLchar const* sourceStrings[kMaxSourceStringCount]; + GLint sourceStringLengths[kMaxSourceStringCount]; - int sourceStringCount = 0; + int sourceStringCount = 0; - char const* stagePrelude = "\n"; - switch (stage) - { + char const* stagePrelude = "\n"; + switch (stage) + { #define CASE(NAME) case GL_##NAME##_SHADER: stagePrelude = "#define __GLSL_" #NAME "__ 1\n"; break CASE(VERTEX); @@ -566,11 +309,11 @@ public: CASE(COMPUTE); #undef CASE - } + } - char const* prelude = - "#define __GLSL__ 1\n" - ; + char const* prelude = + "#define __GLSL__ 1\n" + ; #define ADD_SOURCE_STRING_SPAN(BEGIN, END) \ sourceStrings[sourceStringCount] = BEGIN; \ @@ -582,79 +325,61 @@ public: sourceStringLengths[sourceStringCount++] = GLint(strlen(BEGIN)) \ /* end */ - ADD_SOURCE_STRING_SPAN(versionBegin, versionEnd); - ADD_SOURCE_STRING(stagePrelude); - ADD_SOURCE_STRING(prelude); - ADD_SOURCE_STRING_SPAN(sourceBegin, versionBegin); - ADD_SOURCE_STRING_SPAN(versionEnd, sourceEnd); - - auto shaderID = glCreateShader(stage); - glShaderSource( - shaderID, - sourceStringCount, - &sourceStrings[0], - &sourceStringLengths[0]); - glCompileShader(shaderID); - - GLint success = GL_FALSE; - glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success); - if( !success ) - { - int maxSize = 0; - glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &maxSize); + ADD_SOURCE_STRING_SPAN(versionBegin, versionEnd); + ADD_SOURCE_STRING(stagePrelude); + ADD_SOURCE_STRING(prelude); + ADD_SOURCE_STRING_SPAN(sourceBegin, versionBegin); + ADD_SOURCE_STRING_SPAN(versionEnd, sourceEnd); - auto infoBuffer = (char*) malloc(maxSize); + auto shaderID = glCreateShader(stage); + glShaderSource( + shaderID, + sourceStringCount, + &sourceStrings[0], + &sourceStringLengths[0]); + glCompileShader(shaderID); - int infoSize = 0; - glGetShaderInfoLog(shaderID, maxSize, &infoSize, infoBuffer); - if( infoSize > 0 ) - { - fprintf(stderr, "%s", infoBuffer); - OutputDebugStringA(infoBuffer); - } + GLint success = GL_FALSE; + glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success); + if (!success) + { + int maxSize = 0; + glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &maxSize); + + auto infoBuffer = (char*)malloc(maxSize); - glDeleteShader(shaderID); - return 0; + int infoSize = 0; + glGetShaderInfoLog(shaderID, maxSize, &infoSize, infoBuffer); + if (infoSize > 0) + { + fprintf(stderr, "%s", infoBuffer); + OutputDebugStringA(infoBuffer); } - return shaderID; - } + glDeleteShader(shaderID); + return 0; + } - virtual void dispatchCompute(int x, int y, int z) override - { - glDispatchCompute(x, y, z); - } + return shaderID; +} - struct GLBindingEntry - { - ShaderInputType type; - GLuint handle; - List<int> binding; - int bindTarget; - int bufferSize; - bool isOutput = false; - }; - struct GLBindingState - { - List<GLBindingEntry> entries; - }; +void GLRenderer::createInputBuffer(BindingEntryImpl& rs, InputBufferDesc bufDesc, List<unsigned int>& bufferData) +{ + rs.bindTarget = (bufDesc.type == InputBufferType::StorageBuffer ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER); + glGenBuffers(1, &rs.handle); + glBindBuffer(rs.bindTarget, rs.handle); + glBufferData(rs.bindTarget, bufferData.Count() * sizeof(unsigned int), bufferData.Buffer(), GL_STATIC_READ); + glBindBuffer(rs.bindTarget, 0); +} - void createInputBuffer(GLBindingEntry & rs, InputBufferDesc bufDesc, List<unsigned int> & bufferData) - { - rs.bindTarget = (bufDesc.type == InputBufferType::StorageBuffer ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER); - glGenBuffers(1, &rs.handle); - glBindBuffer(rs.bindTarget, rs.handle); - glBufferData(rs.bindTarget, bufferData.Count() * sizeof(unsigned int), bufferData.Buffer(), GL_STATIC_READ); - glBindBuffer(rs.bindTarget, 0); - } - void createInputTexture(GLBindingEntry & rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc) +void GLRenderer::createInputTexture(BindingEntryImpl& rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc) +{ + TextureData texData; + generateTextureData(texData, texDesc); + glGenTextures(1, &rs.handle); + switch (texDesc.dimension) { - TextureData texData; - generateTextureData(texData, texDesc); - glGenTextures(1, &rs.handle); - switch (texDesc.dimension) - { case 1: if (texDesc.arrayLength > 0) { @@ -714,59 +439,295 @@ public: for (int i = 0; i < texData.mipLevels; i++) glTexImage3D(rs.bindTarget, i, GL_RGBA8, texData.textureSize, texData.textureSize, texData.textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.dataBuffer[i].Buffer()); break; - } - glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_R, GL_REPEAT); + } + glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(rs.bindTarget, GL_TEXTURE_WRAP_R, GL_REPEAT); - if (samplerDesc.isCompareSampler) - { - glTexParameteri(rs.bindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(rs.bindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(rs.bindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); - } - else - { - glTexParameteri(rs.bindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(rs.bindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(rs.bindTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(rs.bindTarget, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - } + if (samplerDesc.isCompareSampler) + { + glTexParameteri(rs.bindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(rs.bindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(rs.bindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); + } + else + { + glTexParameteri(rs.bindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(rs.bindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(rs.bindTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(rs.bindTarget, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } +} - void createInputSampler(GLBindingEntry & rs, InputSamplerDesc samplerDesc) +void GLRenderer::createInputSampler(BindingEntryImpl& rs, InputSamplerDesc samplerDesc) +{ + glCreateSamplers(1, &rs.handle); + glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_T, GL_REPEAT); + glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_R, GL_REPEAT); + + if (samplerDesc.isCompareSampler) + { + glSamplerParameteri(rs.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glSamplerParameteri(rs.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(rs.handle, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8); + } + else { - glCreateSamplers(1, &rs.handle); - glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_S, GL_REPEAT); - glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_T, GL_REPEAT); - glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_R, GL_REPEAT); + glSamplerParameteri(rs.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(rs.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(rs.handle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glSamplerParameteri(rs.handle, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + } +} - if (samplerDesc.isCompareSampler) - { - glSamplerParameteri(rs.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glSamplerParameteri(rs.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(rs.handle, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8); - } - else + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! + +SlangResult GLRenderer::initialize(void* inWindowHandle) +{ + auto windowHandle = (HWND)inWindowHandle; + + deviceContext = ::GetDC(windowHandle); + + PIXELFORMATDESCRIPTOR pixelFormatDesc = { sizeof(PIXELFORMATDESCRIPTOR) }; + pixelFormatDesc.nVersion = 1; + pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pixelFormatDesc.iPixelType = PFD_TYPE_RGBA; + pixelFormatDesc.cColorBits = 32; + pixelFormatDesc.cDepthBits = 24; + pixelFormatDesc.cStencilBits = 8; + pixelFormatDesc.iLayerType = PFD_MAIN_PLANE; + + int pixelFormatIndex = ChoosePixelFormat(deviceContext, &pixelFormatDesc); + SetPixelFormat(deviceContext, pixelFormatIndex, &pixelFormatDesc); + + glContext = wglCreateContext(deviceContext); + wglMakeCurrent(deviceContext, glContext); + + auto renderer = glGetString(GL_RENDERER); + auto extensions = glGetString(GL_EXTENSIONS); + + // Load each of our extension functions by name + +#define LOAD_GL_EXTENSION_FUNC(NAME, TYPE) NAME = (TYPE) wglGetProcAddress(#NAME); + MAP_GL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC) +#undef LOAD_GL_EXTENSION_FUNC + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glViewport(0, 0, gWindowWidth, gWindowHeight); + + if (glDebugMessageCallback) + { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(staticDebugCallback, this); + } + + return SLANG_OK; +} + +void GLRenderer::setClearColor(float const* color) +{ + glClearColor(color[0], color[1], color[2], color[3]); +} + +void GLRenderer::clearFrame() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +} + +void GLRenderer::presentFrame() +{ + glFlush(); + ::SwapBuffers(deviceContext); +} + +SlangResult GLRenderer::captureScreenShot(char const* outputPath) +{ + int width = gWindowWidth; + int height = gWindowHeight; + + int components = 4; + int rowStride = width*components; + + GLubyte* buffer = (GLubyte*)::malloc(components * width * height); + + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + // OpenGL's "upside down" convention bites us here, so we need + // to flip the data in the buffer by swapping rows + int halfHeight = height / 2; + for (int hh = 0; hh < halfHeight; ++hh) + { + // Get a pointer to the row data, and a pointer + // to the row on the "other end" of the image + GLubyte* rowA = buffer + rowStride*hh; + GLubyte* rowB = buffer + rowStride*(height - (hh + 1)); + + for (int ii = 0; ii < rowStride; ++ii) { - glSamplerParameteri(rs.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glSamplerParameteri(rs.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(rs.handle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glSamplerParameteri(rs.handle, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + auto a = rowA[ii]; + auto b = rowB[ii]; + + rowA[ii] = b; + rowB[ii] = a; } } - virtual BindingState * createBindingState(const ShaderInputLayout & layout) + // + int stbResult = stbi_write_png(outputPath, width, height, components, buffer, rowStride); + + ::free(buffer); + + if (!stbResult) + { + assert(!"unexpected"); + return SLANG_FAIL; + } + + return SLANG_OK; +} + +ShaderCompiler* GLRenderer::getShaderCompiler() +{ + return this; +} + +Buffer* GLRenderer::createBuffer(BufferDesc const& desc) +{ + // TODO: should derive target from desc... + GLenum target = GL_UNIFORM_BUFFER; + + // TODO: should derive from desc... + GLenum usage = GL_DYNAMIC_DRAW; + + GLuint bufferID = 0; + glGenBuffers(1, &bufferID); + glBindBuffer(target, bufferID); + + glBufferData(target, desc.size, desc.initData, usage); + + return (Buffer*)(uintptr_t)bufferID; +} + +InputLayout* GLRenderer::createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) +{ + InputLayoutImpl* inputLayout = new InputLayoutImpl(); + + inputLayout->attributeCount = inputElementCount; + for (UInt ii = 0; ii < inputElementCount; ++ii) + { + auto& inputAttr = inputElements[ii]; + auto& glAttr = inputLayout->attributes[ii]; + + glAttr.streamIndex = 0; + glAttr.format = getVertexAttributeFormat(inputAttr.format); + glAttr.offset = (GLsizei)inputAttr.offset; + } + + return (InputLayout*)inputLayout; +} + +void* GLRenderer::map(Buffer* buffer, MapFlavor flavor) +{ + GLenum target = GL_UNIFORM_BUFFER; + + GLuint access = 0; + switch (flavor) + { + case MapFlavor::WriteDiscard: + case MapFlavor::HostWrite: + access = GL_WRITE_ONLY; + break; + case MapFlavor::HostRead: + access = GL_READ_ONLY; + break; + } + + auto bufferID = (GLuint)(uintptr_t)buffer; + glBindBuffer(target, bufferID); + + return glMapBuffer(target, access); +} + +void GLRenderer::unmap(Buffer* buffer) +{ + GLenum target = GL_UNIFORM_BUFFER; + + auto bufferID = (GLuint)(uintptr_t)buffer; + glUnmapBuffer(target); +} + +void GLRenderer::setInputLayout(InputLayout* inputLayout) +{ + boundInputLayout = (InputLayoutImpl*)inputLayout; +} + +void GLRenderer::setPrimitiveTopology(PrimitiveTopology topology) +{ + GLenum glTopology = 0; + switch (topology) + { +#define CASE(NAME, VALUE) case PrimitiveTopology::NAME: glTopology = VALUE; break + + CASE(TriangleList, GL_TRIANGLES); + +#undef CASE + } + boundPrimitiveTopology = glTopology; +} + +void GLRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) +{ + for (UInt ii = 0; ii < slotCount; ++ii) { - GLBindingState * rs = new GLBindingState(); - for (auto & entry : layout.entries) + UInt slot = startSlot + ii; + + Buffer* buffer = buffers[ii]; + GLuint bufferID = (GLuint)(uintptr_t)buffer; + + boundVertexStreamBuffers[slot] = bufferID; + boundVertexStreamStrides[slot] = strides[ii]; + boundVertexStreamOffsets[slot] = offsets[ii]; + } +} + +void GLRenderer::setShaderProgram(ShaderProgram* program) +{ + GLuint programID = (GLuint)(uintptr_t)program; + glUseProgram(programID); +} + +void GLRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) +{ + bindBufferImpl(GL_UNIFORM_BUFFER, startSlot, slotCount, buffers, offsets); +} + +void GLRenderer::draw(UInt vertexCount, UInt startVertex = 0) +{ + flushStateForDraw(); + + glDrawArrays(boundPrimitiveTopology, (GLint)startVertex, (GLsizei)vertexCount); +} + +void GLRenderer::dispatchCompute(int x, int y, int z) +{ + glDispatchCompute(x, y, z); +} + +BindingState* GLRenderer::createBindingState(const ShaderInputLayout & layout) +{ + BindingStateImpl * rs = new BindingStateImpl(); + for (auto & entry : layout.entries) + { + BindingEntryImpl rsEntry; + rsEntry.isOutput = entry.isOutput; + rsEntry.binding = entry.glslBinding; + rsEntry.type = entry.type; + switch (entry.type) { - GLBindingEntry rsEntry; - rsEntry.isOutput = entry.isOutput; - rsEntry.binding = entry.glslBinding; - rsEntry.type = entry.type; - switch (entry.type) - { case ShaderInputType::Buffer: createInputBuffer(rsEntry, entry.bufferDesc, entry.bufferData); break; @@ -779,19 +740,19 @@ public: case ShaderInputType::Sampler: createInputSampler(rsEntry, entry.samplerDesc); break; - } - rs->entries.Add(rsEntry); } - return (BindingState*)rs; + rs->entries.Add(rsEntry); } + return (BindingState*)rs; +} - virtual void setBindingState(BindingState * state) +void GLRenderer::setBindingState(BindingState * state) +{ + BindingStateImpl * glState = (BindingStateImpl*)state; + for (auto & entry : glState->entries) { - GLBindingState * glState = (GLBindingState*)state; - for (auto & entry : glState->entries) + switch (entry.type) { - switch (entry.type) - { case ShaderInputType::Buffer: glBindBufferBase(entry.bindTarget, entry.binding[0], entry.handle); break; @@ -804,35 +765,81 @@ public: glActiveTexture(GL_TEXTURE0 + entry.binding[0]); glBindTexture(entry.bindTarget, entry.handle); break; - } } } +} - virtual void serializeOutput(BindingState* state, const char * fileName) +void GLRenderer::serializeOutput(BindingState* state, const char * fileName) +{ + BindingStateImpl * glState = (BindingStateImpl*)state; + FILE * f; + fopen_s(&f, fileName, "wt"); + for (auto & entry : glState->entries) { - GLBindingState * glState = (GLBindingState*)state; - FILE * f; - fopen_s(&f, fileName, "wt"); - for (auto & entry : glState->entries) + if (entry.isOutput) { - if (entry.isOutput) - { - glBindBuffer(entry.bindTarget, entry.handle); - auto ptr = (unsigned int *)glMapBuffer(entry.bindTarget, GL_READ_ONLY); - for (auto i = 0u; i < entry.bufferSize / sizeof(unsigned int); i++) - fprintf(f, "%X\n", ptr[i]); - glUnmapBuffer(entry.bindTarget); - } + glBindBuffer(entry.bindTarget, entry.handle); + auto ptr = (unsigned int *)glMapBuffer(entry.bindTarget, GL_READ_ONLY); + for (auto i = 0u; i < entry.bufferSize / sizeof(unsigned int); i++) + fprintf(f, "%X\n", ptr[i]); + glUnmapBuffer(entry.bindTarget); } - fclose(f); } -}; + fclose(f); +} +// ShaderCompiler interface -Renderer* createGLRenderer() +ShaderProgram* GLRenderer::compileProgram(ShaderCompileRequest const& request) { - return new GLRenderer(); + auto programID = glCreateProgram(); + if (request.computeShader.name) + { + auto computeShaderID = loadShader(GL_COMPUTE_SHADER, request.computeShader.source.dataBegin); + glAttachShader(programID, computeShaderID); + glLinkProgram(programID); + glDeleteShader(computeShaderID); + } + else + { + auto vertexShaderID = loadShader(GL_VERTEX_SHADER, request.vertexShader.source.dataBegin); + auto fragmentShaderID = loadShader(GL_FRAGMENT_SHADER, request.fragmentShader.source.dataBegin); + + glAttachShader(programID, vertexShaderID); + glAttachShader(programID, fragmentShaderID); + + + glLinkProgram(programID); + + glDeleteShader(vertexShaderID); + glDeleteShader(fragmentShaderID); + } + GLint success = GL_FALSE; + glGetProgramiv(programID, GL_LINK_STATUS, &success); + if (!success) + { + int maxSize = 0; + glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &maxSize); + + auto infoBuffer = (char*)::malloc(maxSize); + + int infoSize = 0; + glGetProgramInfoLog(programID, maxSize, &infoSize, infoBuffer); + if (infoSize > 0) + { + fprintf(stderr, "%s", infoBuffer); + OutputDebugStringA(infoBuffer); + } + + ::free(infoBuffer); + + glDeleteProgram(programID); + return nullptr; + } + + return (ShaderProgram*)(uintptr_t)programID; } + } // renderer_test diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp index 1f8e11aa6..2c74c8883 100644 --- a/tools/render-test/render-vk.cpp +++ b/tools/render-test/render-vk.cpp @@ -81,6 +81,92 @@ namespace renderer_test { class VKRenderer : public Renderer, public ShaderCompiler { public: + // Renderer implementation + virtual SlangResult initialize(void* inWindowHandle) override; + virtual void setClearColor(float const* color) override; + virtual void clearFrame() override; + virtual void presentFrame() override; + virtual SlangResult captureScreenShot(char const* outputPath) override; + virtual void serializeOutput(BindingState* state, const char * fileName) override; + virtual Buffer* createBuffer(BufferDesc const& desc) override; + virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override; + virtual BindingState * createBindingState(const ShaderInputLayout & layout) override; + virtual ShaderCompiler* getShaderCompiler() override; + virtual void* map(Buffer* buffer, MapFlavor flavor) override; + virtual void unmap(Buffer* buffer) override; + virtual void setInputLayout(InputLayout* inputLayout) override; + virtual void setPrimitiveTopology(PrimitiveTopology topology) override; + virtual void setBindingState(BindingState * state); + 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; + + // ShaderCompiler implementation + virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override; + + protected: + + struct BufferImpl + { + VkBuffer buffer; + VkDeviceMemory memory; + }; + + struct ShaderProgramImpl + { + VkPipelineShaderStageCreateInfo compute; + VkPipelineShaderStageCreateInfo vertex; + VkPipelineShaderStageCreateInfo fragment; + }; + + struct BindingImpl + { + ShaderInputType type; + InputBufferType bufferType; // Only valid if `type` is `Buffer` + + VkImageView srv; + VkBufferView uav; + VkBuffer buffer; + VkSampler samplerState; + + int binding = 0; + bool isOutput = false; + int bufferLength = 0; + }; + + struct BindingStateImpl + { + Slang::List<BindingImpl> bindings; + int numRenderTargets; + }; + + struct InputLayoutImpl + { + }; + + VkBool32 handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, + size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg); + BufferImpl createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, void const* initData = nullptr); + + VkCommandBuffer getCommandBuffer(); + VkCommandBuffer beginCommandBuffer(); + void flushCommandBuffer(VkCommandBuffer commandBuffer); + + uint32_t getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties); + + VkPipelineShaderStageCreateInfo compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage); + + void createInputTexture(const InputTextureDesc& inputDesc, VkImageView& viewOut); + void createInputSampler(const InputSamplerDesc& inputDesc, VkSampler& stateOut); + void createInputBuffer(const ShaderInputLayoutEntry& entry, const InputBufferDesc& bufferDesc, const Slang::List<unsigned int>& bufferData, + VkBuffer& bufferOut, VkBufferView& uavOut, VkImageView& srvOut); + + static SlangResult toSlangResult(VkResult res); + static void checkResult(VkResult result); + static VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, + size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData); VkInstance instance; VkPhysicalDevice physicalDevice; @@ -94,6 +180,10 @@ public: VkSubmitInfo submitInfo; VkDebugReportCallbackEXT debugReportCallback; + BindingStateImpl* currentBindingState = nullptr; + ShaderProgramImpl* currentProgram = nullptr; + + float clearColor[4]; #define DECLARE_PROC(NAME) PFN_##NAME NAME; DECLARE_PROC(vkGetInstanceProcAddr); @@ -101,605 +191,555 @@ public: FOREACH_INSTANCE_PROC(DECLARE_PROC) FOREACH_DEVICE_PROC(DECLARE_PROC) #undef DECLARE_PROC + +}; - // Renderer interface - - static SlangResult toSlangResult(VkResult res) - { - return (res == VK_SUCCESS) ? SLANG_OK : SLANG_FAIL; - } - void checkResult(VkResult result) - { - assert(result == VK_SUCCESS); - } - - VkBool32 handleDebugMessage( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objType, - uint64_t srcObject, - size_t location, - int32_t msgCode, - const char* pLayerPrefix, - const char* pMsg) - { - char const* severity = "message"; - if(flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) - severity = "warning"; - if(flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) - severity = "error"; - - char buffer[1024]; - sprintf_s(buffer, - "%s: %s %d: %s\n", - pLayerPrefix, - severity, - msgCode, - pMsg); - - fprintf(stderr, "%s", buffer); - fflush(stderr); - - OutputDebugStringA(buffer); - - return VK_FALSE; - } +Renderer* createVKRenderer() +{ + return new VKRenderer(); +} - static VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objType, - uint64_t srcObject, - size_t location, - int32_t msgCode, - const char* pLayerPrefix, - const char* pMsg, - void* pUserData) - { - return ((VKRenderer*) pUserData)->handleDebugMessage( - flags, objType, srcObject, location, msgCode, pLayerPrefix, pMsg); - } +/* static */SlangResult VKRenderer::toSlangResult(VkResult res) +{ + return (res == VK_SUCCESS) ? SLANG_OK : SLANG_FAIL; +} - virtual SlangResult initialize(void* inWindowHandle) override - { - char const* dynamicLibraryName = "vulkan-1.dll"; - HMODULE vulkan = LoadLibraryA(dynamicLibraryName); - if(!vulkan) - { - fprintf(stderr, "error: failed load '%s'\n", dynamicLibraryName); - return SLANG_FAIL; - } +void VKRenderer::checkResult(VkResult result) +{ + assert(result == VK_SUCCESS); +} - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) GetProcAddress(vulkan, "vkGetInstanceProcAddr"); - if(!vkGetInstanceProcAddr) - { - fprintf(stderr, "error: failed load symbol 'vkGetInstanceProcAddr'\n"); - return SLANG_FAIL; - } +VkBool32 VKRenderer::handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, + size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg) +{ + char const* severity = "message"; + if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) + severity = "warning"; + if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) + severity = "error"; + + char buffer[1024]; + sprintf_s(buffer, + "%s: %s %d: %s\n", + pLayerPrefix, + severity, + msgCode, + pMsg); + + fprintf(stderr, "%s", buffer); + fflush(stderr); + + OutputDebugStringA(buffer); + + return VK_FALSE; +} - VkApplicationInfo applicationInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; - applicationInfo.pApplicationName = "slang-render-test"; - applicationInfo.pEngineName = "slang-render-test"; - applicationInfo.apiVersion = VK_API_VERSION_1_0; +/* static */VKAPI_ATTR VkBool32 VKAPI_CALL VKRenderer::debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, + size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData) +{ + return ((VKRenderer*)pUserData)->handleDebugMessage(flags, objType, srcObject, location, msgCode, pLayerPrefix, pMsg); +} - char const* instanceExtensions[] = { - VK_KHR_SURFACE_EXTENSION_NAME, -#ifdef _WIN32 - VK_KHR_WIN32_SURFACE_EXTENSION_NAME, -#else -#endif +VkCommandBuffer VKRenderer::getCommandBuffer() +{ + VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + info.commandPool = commandPool; + info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + info.commandBufferCount = 1; -#if ENABLE_VALIDATION_LAYER - VK_EXT_DEBUG_REPORT_EXTENSION_NAME, -#endif - }; + VkCommandBuffer commandBuffer; + checkResult(vkAllocateCommandBuffers( + device, &info, &commandBuffer)); - VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; - instanceCreateInfo.pApplicationInfo = &applicationInfo; + return commandBuffer; +} - instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensions) / sizeof(instanceExtensions[0]); - instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0]; +VkCommandBuffer VKRenderer::beginCommandBuffer() +{ + VkCommandBuffer commandBuffer = getCommandBuffer(); -#if ENABLE_VALIDATION_LAYER + VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + checkResult(vkBeginCommandBuffer(commandBuffer, &beginInfo)); - uint32_t layerCount = 1; - const char *layerNames[] = { - "VK_LAYER_LUNARG_standard_validation" - }; + return commandBuffer; +} - instanceCreateInfo.enabledLayerCount = layerCount; - instanceCreateInfo.ppEnabledLayerNames = layerNames; -#endif +void VKRenderer::flushCommandBuffer(VkCommandBuffer commandBuffer) +{ + checkResult(vkEndCommandBuffer(commandBuffer)); - instance = 0; + VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; -#define LOAD_INSTANCE_PROC(NAME) NAME = (PFN_##NAME) vkGetInstanceProcAddr(instance, #NAME); + checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + checkResult(vkQueueWaitIdle(queue)); - FOREACH_GLOBAL_PROC(LOAD_INSTANCE_PROC); + vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); +} - RETURN_ON_VK_FAIL(vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); +VKRenderer::BufferImpl VKRenderer::createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, void const* initData) +{ + if (initData) + { + // TODO: what if we are allocating it as CPU-writable anyway? + usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + } - FOREACH_INSTANCE_PROC(LOAD_INSTANCE_PROC); + VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + bufferCreateInfo.size = bufferSize; + bufferCreateInfo.usage = usage; -#undef LOAD_INSTANCE_PROC + VkBuffer buffer; + checkResult(vkCreateBuffer( + device, &bufferCreateInfo, nullptr, &buffer)); + VkMemoryRequirements memoryReqs = {}; + vkGetBufferMemoryRequirements(device, buffer, &memoryReqs); -#if ENABLE_VALIDATION_LAYER - VkDebugReportFlagsEXT debugFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; + uint32_t memoryTypeIndex = getMemoryTypeIndex( + memoryReqs.memoryTypeBits, reqMemoryProperties); - VkDebugReportCallbackCreateInfoEXT debugCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT }; - debugCreateInfo.pfnCallback = &debugMessageCallback; - debugCreateInfo.pUserData = this; - debugCreateInfo.flags = debugFlags; + VkMemoryPropertyFlags actualMemoryProperites = deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; - RETURN_ON_VK_FAIL(vkCreateDebugReportCallbackEXT(instance, &debugCreateInfo, nullptr, &debugReportCallback)); + VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocateInfo.allocationSize = memoryReqs.size; + allocateInfo.memoryTypeIndex = memoryTypeIndex; -#endif + VkDeviceMemory memory; + checkResult(vkAllocateMemory( + device, &allocateInfo, nullptr, &memory)); - uint32_t physicalDeviceCount = 0; - RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr)); + checkResult(vkBindBufferMemory( + device, buffer, memory, 0)); - VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*)alloca( - physicalDeviceCount * sizeof(VkPhysicalDevice)); - RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices( - instance, &physicalDeviceCount, physicalDevices)); + if (initData) + { + // TODO: only create staging buffer if the memory type + // used for the buffer doesn't let us fill things in + // directly. - uint32_t selectedDeviceIndex = 0; - // TODO: allow override of selected device - physicalDevice = physicalDevices[selectedDeviceIndex]; + BufferImpl staging = createBufferImpl(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); - vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); + // Copy into staging buffer + void* mappedData = nullptr; + checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData)); + memcpy(mappedData, initData, bufferSize); + vkUnmapMemory(device, staging.memory); - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, &queueFamilyCount, nullptr); + // Copy from staging buffer to real buffer + VkCommandBuffer commandBuffer = beginCommandBuffer(); - VkQueueFamilyProperties* queueFamilies = (VkQueueFamilyProperties*)alloca( - queueFamilyCount * sizeof(VkQueueFamilyProperties)); - vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, &queueFamilyCount, queueFamilies); + VkBufferCopy copyInfo = {}; + copyInfo.size = bufferSize; + vkCmdCopyBuffer(commandBuffer, staging.buffer, buffer, 1, ©Info); - // Find a queue that can service our needs - VkQueueFlags reqQueueFlags = - VK_QUEUE_GRAPHICS_BIT - | VK_QUEUE_COMPUTE_BIT; + flushCommandBuffer(commandBuffer); - uint32_t queueFamilyIndex = uint32_t(-1); - for (uint32_t qq = 0; qq < queueFamilyCount; ++qq) - { - if ((queueFamilies[qq].queueFlags & reqQueueFlags) == reqQueueFlags) - { - queueFamilyIndex = qq; - break; - } - } - assert(queueFamilyIndex < queueFamilyCount); + // Now destroy the staging buffer + vkDestroyBuffer(device, staging.buffer, nullptr); + vkFreeMemory(device, staging.memory, nullptr); + } - float queuePriority = 0.0f; - VkDeviceQueueCreateInfo queueCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; - queueCreateInfo.queueFamilyIndex = queueFamilyIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.pQueuePriorities = &queuePriority; + BufferImpl impl; + impl.buffer = buffer; + impl.memory = memory; + return impl; +} - char const* const deviceExtensions[] = +uint32_t VKRenderer::getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties) +{ + uint32_t typeBits = inTypeBits; + uint32_t typeIndex = 0; + while (typeBits) + { + if ((deviceMemoryProperties.memoryTypes[typeIndex].propertyFlags & properties) == properties) { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - }; + return typeIndex; + } + typeIndex++; + typeBits >>= 1; + } - VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; - deviceCreateInfo.queueCreateInfoCount = 1; - deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.pEnabledFeatures = &enabledFeatures; + assert(!"failed to find a usable memory type"); + return uint32_t(-1); +} - deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0]); - deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions[0]; +void VKRenderer::createInputTexture(const InputTextureDesc& inputDesc, VkImageView& viewOut) +{ + TextureData texData; + generateTextureData(texData, inputDesc); + assert(!"unimplemented"); +} - RETURN_ON_VK_FAIL(vkCreateDevice( - physicalDevice, &deviceCreateInfo, nullptr, &device)); +void VKRenderer::createInputSampler(const InputSamplerDesc& inputDesc, VkSampler& stateOut) +{ + assert(!"unimplemented"); +} -#define LOAD_DEVICE_PROC(NAME) NAME = (PFN_##NAME) vkGetDeviceProcAddr(device, #NAME); - FOREACH_DEVICE_PROC(LOAD_DEVICE_PROC) -#undef LOAD_DEVICE_PROC +void VKRenderer::createInputBuffer(const ShaderInputLayoutEntry& entry, const InputBufferDesc& bufferDesc, const Slang::List<unsigned int>& bufferData, + VkBuffer& bufferOut, VkBufferView& uavOut, VkImageView& srvOut) +{ + size_t bufferSize = bufferData.Count() * sizeof(unsigned int); + void const* initData = bufferData.Buffer(); - // Create a command pool + VkBufferUsageFlags usage = 0; + VkMemoryPropertyFlags reqMemoryProperties = 0; - VkCommandPoolCreateInfo commandPoolCreateInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; - commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex; - commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + switch (bufferDesc.type) + { + case InputBufferType::ConstantBuffer: + usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + break; - RETURN_ON_VK_FAIL(vkCreateCommandPool( - device, &commandPoolCreateInfo, nullptr, &commandPool)); + case InputBufferType::StorageBuffer: + usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + reqMemoryProperties = 0; + break; + } - vkGetDeviceQueue( - device, - queueFamilyIndex, - 0, - &queue); + // If we are going to read back from the buffer, be sure to request + // the required access. + if (entry.isOutput) + { + usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + } - // set up swap chain + BufferImpl bufferImpl = createBufferImpl(bufferSize, usage, reqMemoryProperties, initData); + // TODO: need to hang onto the `memory` field so + // that we can release it when we are done. + bufferOut = bufferImpl.buffer; - // create command buffers + // Fill in any views needed + switch (bufferDesc.type) + { + case InputBufferType::ConstantBuffer: + break; - // depth/stencil? + case InputBufferType::StorageBuffer: + { + } + break; + } +} - // render pass? +VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage) +{ + char const* dataBegin = entryPointRequest.source.dataBegin; + char const* dataEnd = entryPointRequest.source.dataEnd; - // pipeline cache + // We need to make a copy of the code, since the Slang compiler + // will free the memory after a compile request is closed. + size_t codeSize = dataEnd - dataBegin; + char* codeBegin = (char*)malloc(codeSize); + memcpy(codeBegin, dataBegin, codeSize); - // frame buffer + VkShaderModuleCreateInfo moduleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + moduleCreateInfo.pCode = (uint32_t*)codeBegin; + moduleCreateInfo.codeSize = codeSize; + VkShaderModule module; + checkResult(vkCreateShaderModule(device, &moduleCreateInfo, nullptr, &module)); + //::free(codeBegin); - // create semaphores for sync + VkPipelineShaderStageCreateInfo shaderStageCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; + shaderStageCreateInfo.stage = stage; - return SLANG_OK; - } + shaderStageCreateInfo.module = module; + shaderStageCreateInfo.pName = "main"; + return shaderStageCreateInfo; +} - float clearColor[4]; - virtual void setClearColor(float const* color) override - { - for(int ii = 0; ii < 4; ++ii) - clearColor[ii] = color[ii]; - } +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! - virtual void clearFrame() override +SlangResult VKRenderer::initialize(void* inWindowHandle) +{ + char const* dynamicLibraryName = "vulkan-1.dll"; + HMODULE vulkan = LoadLibraryA(dynamicLibraryName); + if (!vulkan) { + fprintf(stderr, "error: failed load '%s'\n", dynamicLibraryName); + return SLANG_FAIL; } - virtual void presentFrame() override + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(vulkan, "vkGetInstanceProcAddr"); + if (!vkGetInstanceProcAddr) { + fprintf(stderr, "error: failed load symbol 'vkGetInstanceProcAddr'\n"); + return SLANG_FAIL; } - virtual SlangResult captureScreenShot(char const* outputPath) override - { - return SLANG_FAIL; - } + VkApplicationInfo applicationInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; + applicationInfo.pApplicationName = "slang-render-test"; + applicationInfo.pEngineName = "slang-render-test"; + applicationInfo.apiVersion = VK_API_VERSION_1_0; - virtual ShaderCompiler* getShaderCompiler() override - { - return this; - } + char const* instanceExtensions[] = { + VK_KHR_SURFACE_EXTENSION_NAME, +#ifdef _WIN32 + VK_KHR_WIN32_SURFACE_EXTENSION_NAME, +#else +#endif - VkCommandBuffer getCommandBuffer() - { - VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; - info.commandPool = commandPool; - info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - info.commandBufferCount = 1; +#if ENABLE_VALIDATION_LAYER + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, +#endif + }; - VkCommandBuffer commandBuffer; - checkResult(vkAllocateCommandBuffers( - device, &info, &commandBuffer)); + VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; + instanceCreateInfo.pApplicationInfo = &applicationInfo; - return commandBuffer; - } + instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensions) / sizeof(instanceExtensions[0]); + instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0]; - VkCommandBuffer beginCommandBuffer() - { - VkCommandBuffer commandBuffer = getCommandBuffer(); +#if ENABLE_VALIDATION_LAYER - VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - checkResult(vkBeginCommandBuffer(commandBuffer, &beginInfo)); + uint32_t layerCount = 1; + const char *layerNames[] = { + "VK_LAYER_LUNARG_standard_validation" + }; - return commandBuffer; - } + instanceCreateInfo.enabledLayerCount = layerCount; + instanceCreateInfo.ppEnabledLayerNames = layerNames; +#endif - void flushCommandBuffer(VkCommandBuffer commandBuffer) - { - checkResult(vkEndCommandBuffer(commandBuffer)); + instance = 0; - VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; +#define LOAD_INSTANCE_PROC(NAME) NAME = (PFN_##NAME) vkGetInstanceProcAddr(instance, #NAME); - checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - checkResult(vkQueueWaitIdle(queue)); + FOREACH_GLOBAL_PROC(LOAD_INSTANCE_PROC); - vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); - } + RETURN_ON_VK_FAIL(vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); - struct BufferImpl - { - VkBuffer buffer; - VkDeviceMemory memory; - }; + FOREACH_INSTANCE_PROC(LOAD_INSTANCE_PROC); - BufferImpl createBufferImpl( - size_t bufferSize, - VkBufferUsageFlags usage, - VkMemoryPropertyFlags reqMemoryProperties, - void const* initData = nullptr) - { - if( initData ) - { - // TODO: what if we are allocating it as CPU-writable anyway? - usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - } +#undef LOAD_INSTANCE_PROC - VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufferCreateInfo.size = bufferSize; - bufferCreateInfo.usage = usage; - VkBuffer buffer; - checkResult(vkCreateBuffer( - device, &bufferCreateInfo, nullptr, &buffer)); +#if ENABLE_VALIDATION_LAYER + VkDebugReportFlagsEXT debugFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; - VkMemoryRequirements memoryReqs = {}; - vkGetBufferMemoryRequirements(device, buffer, &memoryReqs); + VkDebugReportCallbackCreateInfoEXT debugCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT }; + debugCreateInfo.pfnCallback = &debugMessageCallback; + debugCreateInfo.pUserData = this; + debugCreateInfo.flags = debugFlags; - uint32_t memoryTypeIndex = getMemoryTypeIndex( - memoryReqs.memoryTypeBits, reqMemoryProperties); + RETURN_ON_VK_FAIL(vkCreateDebugReportCallbackEXT(instance, &debugCreateInfo, nullptr, &debugReportCallback)); - VkMemoryPropertyFlags actualMemoryProperites = deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; +#endif - VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocateInfo.allocationSize = memoryReqs.size; - allocateInfo.memoryTypeIndex = memoryTypeIndex; + uint32_t physicalDeviceCount = 0; + RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr)); - VkDeviceMemory memory; - checkResult(vkAllocateMemory( - device, &allocateInfo, nullptr, &memory)); + VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*)alloca( + physicalDeviceCount * sizeof(VkPhysicalDevice)); + RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices( + instance, &physicalDeviceCount, physicalDevices)); - checkResult(vkBindBufferMemory( - device, buffer, memory, 0)); + uint32_t selectedDeviceIndex = 0; + // TODO: allow override of selected device + physicalDevice = physicalDevices[selectedDeviceIndex]; - if( initData ) - { - // TODO: only create staging buffer if the memory type - // used for the buffer doesn't let us fill things in - // directly. - - BufferImpl staging = createBufferImpl( - bufferSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - // Copy into staging buffer - void* mappedData = nullptr; - checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData)); - memcpy(mappedData, initData, bufferSize); - vkUnmapMemory(device, staging.memory); - - // Copy from staging buffer to real buffer - VkCommandBuffer commandBuffer = beginCommandBuffer(); - - VkBufferCopy copyInfo = {}; - copyInfo.size = bufferSize; - vkCmdCopyBuffer( - commandBuffer, - staging.buffer, - buffer, - 1, - ©Info); - - flushCommandBuffer(commandBuffer); - - // Now destroy the staging buffer - vkDestroyBuffer(device, staging.buffer, nullptr); - vkFreeMemory(device, staging.memory, nullptr); - } + vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); + vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); - BufferImpl impl; - impl.buffer = buffer; - impl.memory = memory; - return impl; - } + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties( + physicalDevice, &queueFamilyCount, nullptr); - virtual Buffer* createBuffer(BufferDesc const& desc) override - { - size_t bufferSize = desc.size; + VkQueueFamilyProperties* queueFamilies = (VkQueueFamilyProperties*)alloca( + queueFamilyCount * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties( + physicalDevice, &queueFamilyCount, queueFamilies); - VkBufferUsageFlags usage = 0; - VkMemoryPropertyFlags reqMemoryProperties = 0; + // Find a queue that can service our needs + VkQueueFlags reqQueueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT; - switch( desc.flavor ) + uint32_t queueFamilyIndex = uint32_t(-1); + for (uint32_t qq = 0; qq < queueFamilyCount; ++qq) + { + if ((queueFamilies[qq].queueFlags & reqQueueFlags) == reqQueueFlags) { - case BufferFlavor::Constant: - usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - break; - - case BufferFlavor::Vertex: - usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - reqMemoryProperties = 0; + queueFamilyIndex = qq; break; } - - BufferImpl bufferImpl = createBufferImpl( - bufferSize, - usage, - reqMemoryProperties, - desc.initData); - - BufferImpl* bufferPtr = new BufferImpl(); - *bufferPtr = bufferImpl; - return (Buffer*) bufferPtr; } + assert(queueFamilyIndex < queueFamilyCount); - struct InputLayoutImpl + float queuePriority = 0.0f; + VkDeviceQueueCreateInfo queueCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; + queueCreateInfo.queueFamilyIndex = queueFamilyIndex; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &queuePriority; + + char const* const deviceExtensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; - virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override - { - InputLayoutImpl* impl = new InputLayoutImpl(); + VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; + deviceCreateInfo.queueCreateInfoCount = 1; + deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; + deviceCreateInfo.pEnabledFeatures = &enabledFeatures; - // TODO: actually initialize things + deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0]); + deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions[0]; - return (InputLayout*) impl; - } + RETURN_ON_VK_FAIL(vkCreateDevice( + physicalDevice, &deviceCreateInfo, nullptr, &device)); - virtual void* map(Buffer* buffer, MapFlavor flavor) override - { - return nullptr; - } +#define LOAD_DEVICE_PROC(NAME) NAME = (PFN_##NAME) vkGetDeviceProcAddr(device, #NAME); + FOREACH_DEVICE_PROC(LOAD_DEVICE_PROC) +#undef LOAD_DEVICE_PROC - virtual void unmap(Buffer* buffer) override - { - } + // Create a command pool - virtual void setInputLayout(InputLayout* inputLayout) override - { - } + VkCommandPoolCreateInfo commandPoolCreateInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; + commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex; + commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - virtual void setPrimitiveTopology(PrimitiveTopology topology) override - { - } + RETURN_ON_VK_FAIL(vkCreateCommandPool( + device, &commandPoolCreateInfo, nullptr, &commandPool)); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override - { - } + vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue); - struct ShaderProgramImpl - { - VkPipelineShaderStageCreateInfo compute; - VkPipelineShaderStageCreateInfo vertex; - VkPipelineShaderStageCreateInfo fragment; - }; + // set up swap chain - ShaderProgramImpl* currentProgram = nullptr; - virtual void setShaderProgram(ShaderProgram* program) override - { - currentProgram = (ShaderProgramImpl*) program; - } - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override - { - } - virtual void draw(UInt vertexCount, UInt startVertex = 0) override - { - } + // create command buffers - struct BindingImpl - { - ShaderInputType type; - InputBufferType bufferType; // Only valid if `type` is `Buffer` + // depth/stencil? - VkImageView srv; - VkBufferView uav; - VkBuffer buffer; - VkSampler samplerState; + // render pass? - int binding = 0; - bool isOutput = false; - int bufferLength = 0; - }; + // pipeline cache - struct BindingStateImpl - { - Slang::List<BindingImpl> bindings; - int numRenderTargets; - }; + // frame buffer - uint32_t getMemoryTypeIndex( - uint32_t inTypeBits, - VkMemoryPropertyFlags properties) - { - uint32_t typeBits = inTypeBits; - uint32_t typeIndex = 0; - while( typeBits ) - { - if((deviceMemoryProperties.memoryTypes[typeIndex].propertyFlags & properties) == properties) - { - return typeIndex; - } - typeIndex++; - typeBits >>= 1; - } - assert(!"failed to find a usable memory type"); - return uint32_t(-1); - } - void createInputBuffer( - ShaderInputLayoutEntry const& entry, - InputBufferDesc const& bufferDesc, - Slang::List<unsigned int> const& bufferData, - VkBuffer &bufferOut, - VkBufferView &uavOut, - VkImageView &srvOut) - { - size_t bufferSize = bufferData.Count() * sizeof(unsigned int); - void const* initData = bufferData.Buffer(); + // create semaphores for sync + + return SLANG_OK; +} - VkBufferUsageFlags usage = 0; - VkMemoryPropertyFlags reqMemoryProperties = 0; +void VKRenderer::setClearColor(float const* color) +{ + for (int ii = 0; ii < 4; ++ii) + clearColor[ii] = color[ii]; +} - switch( bufferDesc.type ) - { - case InputBufferType::ConstantBuffer: +void VKRenderer::clearFrame() +{ +} + +void VKRenderer::presentFrame() +{ +} + +SlangResult VKRenderer::captureScreenShot(char const* outputPath) +{ + return SLANG_FAIL; +} + +ShaderCompiler* VKRenderer::getShaderCompiler() +{ + return this; +} + +Buffer* VKRenderer::createBuffer(BufferDesc const& desc) +{ + size_t bufferSize = desc.size; + + VkBufferUsageFlags usage = 0; + VkMemoryPropertyFlags reqMemoryProperties = 0; + + switch (desc.flavor) + { + case BufferFlavor::Constant: usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; break; - case InputBufferType::StorageBuffer: - usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + case BufferFlavor::Vertex: + usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; reqMemoryProperties = 0; break; - } + } - // If we are going to read back from the buffer, be sure to request - // the required access. - if(entry.isOutput) - { - usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - } + BufferImpl bufferImpl = createBufferImpl( + bufferSize, + usage, + reqMemoryProperties, + desc.initData); - BufferImpl bufferImpl = createBufferImpl( - bufferSize, - usage, - reqMemoryProperties, - initData); + BufferImpl* bufferPtr = new BufferImpl(); + *bufferPtr = bufferImpl; + return (Buffer*)bufferPtr; +} - // TODO: need to hang onto the `memory` field so - // that we can release it when we are done. +InputLayout* VKRenderer::createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) +{ + InputLayoutImpl* impl = new InputLayoutImpl; - bufferOut = bufferImpl.buffer; + // TODO: actually initialize things - // Fill in any views needed - switch( bufferDesc.type ) - { - case InputBufferType::ConstantBuffer: - break; + return (InputLayout*)impl; +} - case InputBufferType::StorageBuffer: - { - } - break; - } - } +void* VKRenderer::map(Buffer* buffer, MapFlavor flavor) +{ + return nullptr; +} - void createInputTexture( - InputTextureDesc const& inputDesc, - VkImageView& viewOut) - { - TextureData texData; - generateTextureData(texData, inputDesc); - assert(!"unimplemented"); - } +void VKRenderer::unmap(Buffer* buffer) +{ +} - void createInputSampler( - InputSamplerDesc const& inputDesc, - VkSampler& stateOut) - { - assert(!"unimplemented"); - } +void VKRenderer::setInputLayout(InputLayout* inputLayout) +{ +} + +void VKRenderer::setPrimitiveTopology(PrimitiveTopology topology) +{ +} - virtual BindingState* createBindingState(const ShaderInputLayout & layout) +void VKRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) +{ +} + +void VKRenderer::setShaderProgram(ShaderProgram* program) +{ + currentProgram = (ShaderProgramImpl*)program; +} + +void VKRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) +{ +} + +void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0) +{ +} + +BindingState* VKRenderer::createBindingState(const ShaderInputLayout& layout) +{ + BindingStateImpl* bindingState = new BindingStateImpl; + bindingState->numRenderTargets = layout.numRenderTargets; + for (auto & entry : layout.entries) { - BindingStateImpl* bindingState = new BindingStateImpl(); - bindingState->numRenderTargets = layout.numRenderTargets; - for (auto & entry : layout.entries) + BindingImpl binding; + binding.type = entry.type; + binding.binding = entry.hlslBinding; + binding.isOutput = entry.isOutput; + switch (entry.type) { - BindingImpl binding; - binding.type = entry.type; - binding.binding = entry.hlslBinding; - binding.isOutput = entry.isOutput; - switch (entry.type) - { case ShaderInputType::Buffer: { createInputBuffer(entry, entry.bufferDesc, entry.bufferData, binding.buffer, binding.uav, binding.srv); @@ -710,328 +750,276 @@ public: case ShaderInputType::Texture: { createInputTexture(entry.textureDesc, binding.srv); + break; } - break; case ShaderInputType::Sampler: { createInputSampler(entry.samplerDesc, binding.samplerState); + break; } - break; case ShaderInputType::CombinedTextureSampler: { throw "not implemented"; + break; } - break; - } - bindingState->bindings.Add(binding); } - - return (BindingState*) bindingState; + bindingState->bindings.Add(binding); } - BindingStateImpl* currentBindingState = nullptr; - virtual void setBindingState(BindingState * state) - { - currentBindingState = (BindingStateImpl*) state; - } + return (BindingState*)bindingState; +} - virtual void serializeOutput(BindingState* s, const char * fileName) - { - auto state = (BindingStateImpl*) s; +void VKRenderer::setBindingState(BindingState * state) +{ + currentBindingState = (BindingStateImpl*)state; +} + +void VKRenderer::serializeOutput(BindingState* s, const char * fileName) +{ + auto state = (BindingStateImpl*)s; - FILE * f = fopen(fileName, "wb"); - int id = 0; - for (auto& bb: state->bindings) + FILE * f = fopen(fileName, "wb"); + int id = 0; + for (auto& bb : state->bindings) + { + if (bb.isOutput) { - if (bb.isOutput) + if (bb.buffer) { - if (bb.buffer) - { - // create staging buffer - size_t bufferSize = bb.bufferLength; - BufferImpl staging = createBufferImpl( - bufferSize, - VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - // Copy from real buffer to staging buffer - VkCommandBuffer commandBuffer = beginCommandBuffer(); - - VkBufferCopy copyInfo = {}; - copyInfo.size = bufferSize; - vkCmdCopyBuffer( - commandBuffer, - bb.buffer, - staging.buffer, - 1, - ©Info); - - flushCommandBuffer(commandBuffer); - - // Write out the data from the buffer - void* mappedData = nullptr; - checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData)); - - auto ptr = (unsigned int *) mappedData; - for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++) - fprintf(f, "%X\n", ptr[i]); - - vkUnmapMemory(device, staging.memory); - - // Now destroy the staging buffer - vkDestroyBuffer(device, staging.buffer, nullptr); - vkFreeMemory(device, staging.memory, nullptr); - } - else - { - printf("invalid output type at %d.\n", id); - } + // create staging buffer + size_t bufferSize = bb.bufferLength; + BufferImpl staging = createBufferImpl( + bufferSize, + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + // Copy from real buffer to staging buffer + VkCommandBuffer commandBuffer = beginCommandBuffer(); + + VkBufferCopy copyInfo = {}; + copyInfo.size = bufferSize; + vkCmdCopyBuffer( + commandBuffer, + bb.buffer, + staging.buffer, + 1, + ©Info); + + flushCommandBuffer(commandBuffer); + + // Write out the data from the buffer + void* mappedData = nullptr; + checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData)); + + auto ptr = (unsigned int *)mappedData; + for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++) + fprintf(f, "%X\n", ptr[i]); + + vkUnmapMemory(device, staging.memory); + + // Now destroy the staging buffer + vkDestroyBuffer(device, staging.buffer, nullptr); + vkFreeMemory(device, staging.memory, nullptr); + } + else + { + printf("invalid output type at %d.\n", id); } - id++; } - fclose(f); - - + id++; } + fclose(f); +} - virtual void dispatchCompute(int x, int y, int z) override - { - - - // HACK: create a new pipeline for every call +void VKRenderer::dispatchCompute(int x, int y, int z) +{ + // HACK: create a new pipeline for every call - // First create a pipeline layout based on what is bound + // First create a pipeline layout based on what is bound - Slang::List<VkDescriptorSetLayoutBinding> bindings; + Slang::List<VkDescriptorSetLayoutBinding> bindings; - for( auto bb : currentBindingState->bindings ) + for (auto bb : currentBindingState->bindings) + { + switch (bb.type) { - switch( bb.type ) - { case ShaderInputType::Buffer: + { + switch (bb.bufferType) { - switch(bb.bufferType) - { case InputBufferType::StorageBuffer: - { - VkDescriptorSetLayoutBinding binding = {}; - binding.binding = bb.binding; - binding.descriptorCount = 1; - binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - binding.stageFlags = VK_SHADER_STAGE_ALL; - - bindings.Add(binding); - } - break; + { + VkDescriptorSetLayoutBinding binding = {}; + binding.binding = bb.binding; + binding.descriptorCount = 1; + binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + binding.stageFlags = VK_SHADER_STAGE_ALL; + + bindings.Add(binding); + } + break; default: // handle other cases break; - } } - break; + } + break; default: // TODO: handle the other cases break; - } } + } - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; - descriptorSetLayoutInfo.bindingCount = uint32_t(bindings.Count()); - descriptorSetLayoutInfo.pBindings = bindings.Buffer(); + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + descriptorSetLayoutInfo.bindingCount = uint32_t(bindings.Count()); + descriptorSetLayoutInfo.pBindings = bindings.Buffer(); - VkDescriptorSetLayout descriptorSetLayout = 0; - checkResult(vkCreateDescriptorSetLayout( - device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout)); + VkDescriptorSetLayout descriptorSetLayout = 0; + checkResult(vkCreateDescriptorSetLayout( + device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout)); - // Create a descriptor pool for allocating sets + // Create a descriptor pool for allocating sets - VkDescriptorPoolSize poolSizes[] = - { - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 128 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128 }, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128 }, - }; + VkDescriptorPoolSize poolSizes[] = + { + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 128 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128 }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128 }, + }; - VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; - descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size - descriptorPoolInfo.poolSizeCount = sizeof(poolSizes) / sizeof(poolSizes[0]); - descriptorPoolInfo.pPoolSizes = poolSizes; + VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size + descriptorPoolInfo.poolSizeCount = sizeof(poolSizes) / sizeof(poolSizes[0]); + descriptorPoolInfo.pPoolSizes = poolSizes; - VkDescriptorPool descriptorPool; - checkResult(vkCreateDescriptorPool( - device, &descriptorPoolInfo, nullptr, &descriptorPool)); + VkDescriptorPool descriptorPool; + checkResult(vkCreateDescriptorPool( + device, &descriptorPoolInfo, nullptr, &descriptorPool)); - // Create a descriptor set based on our layout + // Create a descriptor set based on our layout - VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; - descriptorSetAllocInfo.descriptorPool = descriptorPool; - descriptorSetAllocInfo.descriptorSetCount = 1; - descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout; + VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.descriptorSetCount = 1; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout; - VkDescriptorSet descriptorSet; - checkResult(vkAllocateDescriptorSets( - device, &descriptorSetAllocInfo, &descriptorSet)); + VkDescriptorSet descriptorSet; + checkResult(vkAllocateDescriptorSets( + device, &descriptorSetAllocInfo, &descriptorSet)); - // Fill in the descritpor set, using our binding information - for( auto bb : currentBindingState->bindings ) + // Fill in the descritpor set, using our binding information + for (auto bb : currentBindingState->bindings) + { + switch (bb.type) { - switch( bb.type ) - { case ShaderInputType::Buffer: + { + switch (bb.bufferType) { - switch(bb.bufferType) - { case InputBufferType::StorageBuffer: - { - VkDescriptorBufferInfo bufferInfo; - bufferInfo.buffer = bb.buffer; - bufferInfo.offset = 0; - bufferInfo.range = bb.bufferLength; - - VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - writeInfo.descriptorCount = 1; - writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - writeInfo.dstSet = descriptorSet; - writeInfo.dstBinding = bb.binding; - writeInfo.dstArrayElement = 0; - writeInfo.pBufferInfo = &bufferInfo; - - vkUpdateDescriptorSets( - device, - 1, - &writeInfo, - 0, - nullptr); - } - break; + { + VkDescriptorBufferInfo bufferInfo; + bufferInfo.buffer = bb.buffer; + bufferInfo.offset = 0; + bufferInfo.range = bb.bufferLength; + + VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + writeInfo.descriptorCount = 1; + writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writeInfo.dstSet = descriptorSet; + writeInfo.dstBinding = bb.binding; + writeInfo.dstArrayElement = 0; + writeInfo.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets( + device, + 1, + &writeInfo, + 0, + nullptr); + } + break; default: // handle other cases break; - } } - break; + } + break; default: // TODO: handle the other cases break; - } } + } - // Create a pipeline layout based on our descriptor set layout(s) + // Create a pipeline layout based on our descriptor set layout(s) - VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; - pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - VkPipelineLayout pipelineLayout = 0; - checkResult(vkCreatePipelineLayout( - device, &pipelineLayoutInfo, nullptr, &pipelineLayout)); + VkPipelineLayout pipelineLayout = 0; + checkResult(vkCreatePipelineLayout( + device, &pipelineLayoutInfo, nullptr, &pipelineLayout)); - // Then create a pipeline to use that layout + // Then create a pipeline to use that layout - VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; - computePipelineInfo.stage = currentProgram->compute; - computePipelineInfo.layout = pipelineLayout; + VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; + computePipelineInfo.stage = currentProgram->compute; + computePipelineInfo.layout = pipelineLayout; - VkPipelineCache pipelineCache = 0; + VkPipelineCache pipelineCache = 0; - VkPipeline pipeline; - checkResult(vkCreateComputePipelines( - device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline)); + VkPipeline pipeline; + checkResult(vkCreateComputePipelines( + device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline)); - // Also create descriptor sets based on the given pipeline layout + // Also create descriptor sets based on the given pipeline layout - VkCommandBuffer commandBuffer = beginCommandBuffer(); + VkCommandBuffer commandBuffer = beginCommandBuffer(); - vkCmdBindPipeline( - commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); + vkCmdBindPipeline( + commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); - vkCmdBindDescriptorSets( - commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - pipelineLayout, - 0, 1, - &descriptorSet, - 0, - nullptr); + vkCmdBindDescriptorSets( + commandBuffer, + VK_PIPELINE_BIND_POINT_COMPUTE, + pipelineLayout, + 0, 1, + &descriptorSet, + 0, + nullptr); - vkCmdDispatch(commandBuffer, x, y, z); + vkCmdDispatch(commandBuffer, x, y, z); - flushCommandBuffer(commandBuffer); + flushCommandBuffer(commandBuffer); - vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipeline(device, pipeline, nullptr); - // TODO: need to free up the other resources too... - } + // TODO: need to free up the other resources too... +} - // ShaderCompiler interface - VkPipelineShaderStageCreateInfo compileEntryPoint( - ShaderCompileRequest::EntryPoint const& entryPointRequest, - VkShaderStageFlagBits stage) + +// ShaderCompiler interface +ShaderProgram* VKRenderer::compileProgram(const ShaderCompileRequest & request) +{ + ShaderProgramImpl* impl = new ShaderProgramImpl; + if (request.computeShader.name) { - char const* dataBegin = entryPointRequest.source.dataBegin; - char const* dataEnd = entryPointRequest.source.dataEnd; - - // We need to make a copy of the code, since the Slang compiler - // will free the memory after a compile request is closed. - size_t codeSize = dataEnd - dataBegin; - char* codeBegin = (char*) malloc(codeSize); - memcpy(codeBegin, dataBegin, codeSize); - - VkShaderModuleCreateInfo moduleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; - moduleCreateInfo.pCode = (uint32_t*) codeBegin; - moduleCreateInfo.codeSize = codeSize; - - VkShaderModule module; - checkResult(vkCreateShaderModule( - device, - &moduleCreateInfo, - nullptr, - &module)); - - VkPipelineShaderStageCreateInfo shaderStageCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; - shaderStageCreateInfo.stage = stage; - - shaderStageCreateInfo.module = module; - shaderStageCreateInfo.pName = "main"; - return shaderStageCreateInfo; + impl->compute = compileEntryPoint(request.computeShader, VK_SHADER_STAGE_COMPUTE_BIT); } - - virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override + else { - ShaderProgramImpl* impl = new ShaderProgramImpl(); - - if( request.computeShader.name ) - { - impl->compute = compileEntryPoint( - request.computeShader, - VK_SHADER_STAGE_COMPUTE_BIT); - } - else - { - impl->vertex = compileEntryPoint( - request.vertexShader, - VK_SHADER_STAGE_VERTEX_BIT); - - impl->fragment = compileEntryPoint( - request.fragmentShader, - VK_SHADER_STAGE_FRAGMENT_BIT); - } - - return (ShaderProgram*) impl; + impl->vertex = compileEntryPoint(request.vertexShader, VK_SHADER_STAGE_VERTEX_BIT); + impl->fragment = compileEntryPoint(request.fragmentShader, VK_SHADER_STAGE_FRAGMENT_BIT); } -}; - - - -Renderer* createVKRenderer() -{ - return new VKRenderer(); + return (ShaderProgram*)impl; } + } // renderer_test diff --git a/tools/render-test/render.h b/tools/render-test/render.h index 902067d62..bc63caa77 100644 --- a/tools/render-test/render.h +++ b/tools/render-test/render.h @@ -9,10 +9,12 @@ namespace renderer_test { -typedef struct Buffer Buffer; -typedef struct InputLayout InputLayout; -typedef struct ShaderProgram ShaderProgram; -typedef struct BindingState BindingState; +// Declare opaque type +struct Buffer; +struct InputLayout; +struct ShaderProgram; +struct BindingState; + struct ShaderCompileRequest { struct SourceInfo @@ -39,7 +41,7 @@ struct ShaderCompileRequest SourceInfo source; EntryPoint vertexShader; EntryPoint fragmentShader; - EntryPoint computeShader; + EntryPoint computeShader; Slang::List<Slang::String> entryPointTypeArguments; }; @@ -79,8 +81,8 @@ struct InputElementDesc enum class MapFlavor { - HostRead, - HostWrite, + HostRead, + HostWrite, WriteDiscard, }; @@ -115,20 +117,28 @@ public: virtual void setBindingState(BindingState * state) = 0; virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) = 0; - inline void setVertexBuffer(UInt slot, Buffer* buffer, UInt stride, UInt offset = 0) - { - setVertexBuffers(slot, 1, &buffer, &stride, &offset); - } + inline void setVertexBuffer(UInt slot, Buffer* buffer, UInt stride, UInt offset = 0); virtual void setShaderProgram(ShaderProgram* program) = 0; virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) = 0; - inline void setConstantBuffer(UInt slot, Buffer* buffer, UInt offset = 0) - { - setConstantBuffers(slot, 1, &buffer, &offset); - } + inline void setConstantBuffer(UInt slot, Buffer* buffer, UInt offset = 0); + virtual void draw(UInt vertexCount, UInt startVertex = 0) = 0; - virtual void dispatchCompute(int x, int y, int z) = 0; + virtual void dispatchCompute(int x, int y, int z) = 0; }; + +// ---------------------------------------------------------------------------------------- +inline void Renderer::setVertexBuffer(UInt slot, Buffer* buffer, UInt stride, UInt offset) +{ + setVertexBuffers(slot, 1, &buffer, &stride, &offset); +} +// ---------------------------------------------------------------------------------------- +inline void Renderer::setConstantBuffer(UInt slot, Buffer* buffer, UInt offset) +{ + setConstantBuffers(slot, 1, &buffer, &offset); +} + + } // renderer_test |
