From c4004b32ca2c0effb455ec847114240db3cb993b Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Tue, 10 Apr 2018 17:53:03 -0400 Subject: Feature/dx12 compute (#482) * Dx12 rendering works in test framework. * Turn on dx12 render tests. * Getting simpler dx12 compute tests to work. * With expected data in test - check for specialized and then for the default, so that multiple test can share the same expected data, but specialized cases can still be set. * Fixed construction and binding on dx12 textures. * Control which render apis used in test from command line. * Small aesthetic fixes in render-test/main.cpp. * Fix binding problem for uavs/srvs dx12. Previously tried to create srv/uav for StorageBuffers (like dx11 does), but the binding breaks as you can end up with two srvs using the same register. First pass at fixing problems with Texture creation for dx12 - assertions were hit with 3d or array textures. * Fixes to improve Dx12 setup shader resource views for cubemaps/arrays. * Fixed d3d12 textureSamplingTest - problem was that cubemap/array textures were not being uploaded correctly. * Changed the order of how binding of constant buffers (as just set on the Renderer) indexes. Previously they were given the lowest indices, but they clashed with the indices from the 'Binding'. Changing this means all tests run on d3d12. * Add code to allow use of warp (although not command line switchable yet). Fix problem setting up raw UAV - as identified by warp. * Added RenderApiUtil - which can detect if a render api is potentially available. * Moved render flag testing/parsing into RenderApiUtil. * Fix signed/unsigned warning. * Fixes around enums prefixed with k on the review of feature/dx12 compute branch. --- tools/render-test/d3d-util.h | 6 +- tools/render-test/main.cpp | 12 +- tools/render-test/options.cpp | 27 +- tools/render-test/options.h | 3 +- tools/render-test/render-d3d12.cpp | 542 +++++++++++++++++++------------- tools/render-test/resource-d3d12.h | 10 +- tools/render-test/shader-input-layout.h | 131 ++++---- 7 files changed, 427 insertions(+), 304 deletions(-) (limited to 'tools/render-test') diff --git a/tools/render-test/d3d-util.h b/tools/render-test/d3d-util.h index 95ccf4b18..6ac39aefb 100644 --- a/tools/render-test/d3d-util.h +++ b/tools/render-test/d3d-util.h @@ -26,8 +26,8 @@ class D3DUtil }; enum UsageFlag { - USAGE_FLAG_MULTI_SAMPLE = 0x1, - USAGE_FLAG_SRV = 0x2, + USAGE_FLAG_MULTI_SAMPLE = 0x1, ///< If set will be used form multi sampling (such as MSAA) + USAGE_FLAG_SRV = 0x2, ///< If set means will be used as a shader resource view (SRV) }; /// Get primitive topology as D3D primitive topology @@ -41,9 +41,9 @@ class D3DUtil /// Definition of the HLSL-to-bytecode compilation logic. static Slang::Result compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName, Slang::ComPtr& shaderBlobOut); + /// Given a slang pixel format returns the equivalent DXGI_ pixel format. If the format is not known, will return DXGI_FORMAT_UNKNOWN static DXGI_FORMAT getMapFormat(Format format); - /// Given the usage, flags, and format will return the most suitable format. Will return DXGI_UNKNOWN if combination is not possible static DXGI_FORMAT calcFormat(UsageType usage, DXGI_FORMAT format); /// Calculate appropriate format for creating a buffer for usage and flags diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp index 6233b7617..12160ae78 100644 --- a/tools/render-test/main.cpp +++ b/tools/render-test/main.cpp @@ -41,12 +41,13 @@ struct Vertex float uv[2]; }; -static const int kVertexCount = 3; -static const Vertex kVertexData[kVertexCount] = { +static const Vertex kVertexData[] = +{ { { 0, 0, 0.5 }, {1, 0, 0} , {0, 0} }, { { 0, 1, 0.5 }, {0, 0, 1} , {1, 0} }, { { 1, 0, 0.5 }, {0, 1, 0} , {1, 1} }, }; +static const int kVertexCount = SLANG_COUNT_OF(kVertexData); using namespace Slang; @@ -79,7 +80,6 @@ class RenderTestApp RefPtr m_bindingState; ShaderInputLayout m_shaderInputLayout; - }; // Entry point name to use for vertex/fragment shader @@ -116,13 +116,13 @@ SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shader // Input Assembler (IA) - InputElementDesc inputElements[] = { + const InputElementDesc inputElements[] = { { "A", 0, Format::RGB_Float32, offsetof(Vertex, position) }, { "A", 1, Format::RGB_Float32, offsetof(Vertex, color) }, { "A", 2, Format::RG_Float32, offsetof(Vertex, uv) }, }; - m_inputLayout = renderer->createInputLayout(&inputElements[0], sizeof(inputElements)/sizeof(inputElements[0])); + m_inputLayout = renderer->createInputLayout(inputElements, SLANG_COUNT_OF(inputElements)); if(!m_inputLayout) return SLANG_FAIL; @@ -437,7 +437,7 @@ SlangResult innerMain(int argc, char** argv) return SLANG_OK; } -} // renderer_test +} // namespace renderer_test int main(int argc, char** argv) { diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp index 30aeca6b0..bdf635620 100644 --- a/tools/render-test/options.cpp +++ b/tools/render-test/options.cpp @@ -10,6 +10,12 @@ namespace renderer_test { Options gOptions; +// Only set it, if the +void setDefaultRendererID(RendererID id) +{ + gOptions.rendererID = (gOptions.rendererID == RendererID::NONE) ? id : gOptions.rendererID; +} + SlangResult parseOptions(int* argc, char** argv) { int argCount = *argc; @@ -54,32 +60,32 @@ SlangResult parseOptions(int* argc, char** argv) } else if( strcmp(arg, "-hlsl") == 0 ) { - gOptions.rendererID = RendererID::D3D11; + setDefaultRendererID( RendererID::D3D11); gOptions.inputLanguageID = InputLanguageID::Native; } else if( strcmp(arg, "-glsl") == 0 ) { - gOptions.rendererID = RendererID::GL; + setDefaultRendererID(RendererID::GL); gOptions.inputLanguageID = InputLanguageID::Native; } else if( strcmp(arg, "-hlsl-rewrite") == 0 ) { - gOptions.rendererID = RendererID::D3D11; + setDefaultRendererID(RendererID::D3D11); gOptions.inputLanguageID = InputLanguageID::NativeRewrite; } else if( strcmp(arg, "-glsl-rewrite") == 0 ) { - gOptions.rendererID = RendererID::GL; + setDefaultRendererID(RendererID::GL); gOptions.inputLanguageID = InputLanguageID::NativeRewrite; } else if( strcmp(arg, "-slang") == 0 ) { - gOptions.rendererID = RendererID::D3D11; + setDefaultRendererID(RendererID::D3D11); gOptions.inputLanguageID = InputLanguageID::Slang; } else if( strcmp(arg, "-glsl-cross") == 0 ) { - gOptions.rendererID = RendererID::GL; + setDefaultRendererID(RendererID::GL); gOptions.inputLanguageID = InputLanguageID::Slang; } else if( strcmp(arg, "-xslang") == 0 ) @@ -120,6 +126,15 @@ SlangResult parseOptions(int* argc, char** argv) { gOptions.rendererID = RendererID::D3D12; } + else if(strcmp(arg, "-gl") == 0) + { + gOptions.rendererID = RendererID::GL; + } + else if (strcmp(arg, "-d3d11") == 0 + || strcmp(arg, "-dx11") == 0) + { + gOptions.rendererID = RendererID::D3D11; + } else { fprintf(stderr, "unknown option '%s'\n", arg); diff --git a/tools/render-test/options.h b/tools/render-test/options.h index a33172c6b..8dbff76ea 100644 --- a/tools/render-test/options.h +++ b/tools/render-test/options.h @@ -12,6 +12,7 @@ typedef uintptr_t UInt; enum class RendererID { + NONE, D3D11, D3D12, GL, @@ -50,7 +51,7 @@ struct Options char const* outputPath = nullptr; ShaderProgramType shaderType = ShaderProgramType::Graphics; - RendererID rendererID; + RendererID rendererID = RendererID::NONE; InputLanguageID inputLanguageID = InputLanguageID::Slang; char const* slangArgs[kMaxSlangArgs]; diff --git a/tools/render-test/render-d3d12.cpp b/tools/render-test/render-d3d12.cpp index 6d79cb8e5..9d4fdf03c 100644 --- a/tools/render-test/render-d3d12.cpp +++ b/tools/render-test/render-d3d12.cpp @@ -455,7 +455,7 @@ Result D3D12Renderer::createInputSampler(const InputSamplerDesc& inputDesc, D3D1 return SLANG_OK; } -static void _initSrvDesc(const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut) +static void _initSrvDesc(const InputTextureDesc& inputDesc, const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut) { // create SRV descOut = D3D12_SHADER_RESOURCE_VIEW_DESC(); @@ -477,17 +477,39 @@ static void _initSrvDesc(const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelForma descOut.Texture2D.PlaneSlice = 0; descOut.Texture2D.ResourceMinLODClamp = 0.0f; } - else if (desc.DepthOrArraySize == 6) + else if (inputDesc.isCube) { - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; + if (inputDesc.arrayLength > 1) + { + descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; - descOut.TextureCube.MipLevels = desc.MipLevels; - descOut.TextureCube.MostDetailedMip = 0; - descOut.TextureCube.ResourceMinLODClamp = 0; + descOut.TextureCubeArray.NumCubes = inputDesc.arrayLength; + descOut.TextureCubeArray.First2DArrayFace = 0; + descOut.TextureCubeArray.MipLevels = desc.MipLevels; + descOut.TextureCubeArray.MostDetailedMip = 0; + descOut.TextureCubeArray.ResourceMinLODClamp = 0; + } + else + { + descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; + + descOut.TextureCube.MipLevels = desc.MipLevels; + descOut.TextureCube.MostDetailedMip = 0; + descOut.TextureCube.ResourceMinLODClamp = 0; + } } else { - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + assert(desc.DepthOrArraySize > 1); + + switch (desc.Dimension) + { + case D3D12_RESOURCE_DIMENSION_TEXTURE1D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; break; + case D3D12_RESOURCE_DIMENSION_TEXTURE2D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; break; + case D3D12_RESOURCE_DIMENSION_TEXTURE3D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; break; + + default: assert(!"Unknown dimension"); + } descOut.Texture2DArray.ArraySize = desc.DepthOrArraySize; descOut.Texture2DArray.MostDetailedMip = 0; @@ -498,7 +520,7 @@ static void _initSrvDesc(const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelForma } } -void _initBufferResourceDesc(size_t bufferSize, D3D12_RESOURCE_DESC& out) +static void _initBufferResourceDesc(size_t bufferSize, D3D12_RESOURCE_DESC& out) { out = {}; @@ -540,7 +562,10 @@ Result D3D12Renderer::createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, cons heapProps.CreationNodeMask = 1; heapProps.VisibleNodeMask = 1; - SLANG_RETURN_ON_FAIL(uploadResource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr)); + D3D12_RESOURCE_DESC uploadResourceDesc(resourceDesc); + uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + SLANG_RETURN_ON_FAIL(uploadResource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr)); } if (srcData) @@ -572,13 +597,16 @@ Result D3D12Renderer::createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, cons Result D3D12Renderer::createTexture(const InputTextureDesc& inputDesc, const TextureData& texData, D3D12Resource& resourceOut) { - // generateTextureData(texData, inputDesc); + // Description of uploading on Dx12 + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn899215%28v=vs.85%29.aspx const DXGI_FORMAT pixelFormat = DXGI_FORMAT_R8G8B8A8_UNORM; const int numMipMaps = texData.mipLevels; const int width = inputDesc.size; - const int height = width; + // If the dimension is 1, then we have no height + const int height = (inputDesc.dimension <= 1) ? 1 : width; + const int depth = (inputDesc.dimension <= 2) ? 1 : width; // Setup desc D3D12_RESOURCE_DESC resourceDesc; @@ -587,7 +615,8 @@ Result D3D12Renderer::createTexture(const InputTextureDesc& inputDesc, const Tex resourceDesc.Format = pixelFormat; resourceDesc.Width = width; resourceDesc.Height = height; - resourceDesc.DepthOrArraySize = texData.arraySize; + resourceDesc.DepthOrArraySize = (depth > 1) ? depth : texData.arraySize; + resourceDesc.MipLevels = numMipMaps; resourceDesc.SampleDesc.Count = 1; resourceDesc.SampleDesc.Quality = 0; @@ -602,7 +631,22 @@ Result D3D12Renderer::createTexture(const InputTextureDesc& inputDesc, const Tex case 3: resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; break; default: return SLANG_FAIL; } - + + // Create the target resource + { + D3D12_HEAP_PROPERTIES heapProps; + + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + + SLANG_RETURN_ON_FAIL(resourceOut.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); + + resourceOut.setDebugName(L"Texture"); + } + // Calculate the layout List layouts; layouts.SetSize(numMipMaps); @@ -614,108 +658,131 @@ Result D3D12Renderer::createTexture(const InputTextureDesc& inputDesc, const Tex UInt64 requiredSize = 0; m_device->GetCopyableFootprints(&resourceDesc, 0, texData.mipLevels, 0, layouts.begin(), mipNumRows.begin(), mipRowSizeInBytes.begin(), &requiredSize); +#if 0 List subData; subData.SetSize(numMipMaps); // Zero it all initially ::memset(subData.Buffer(), 0, numMipMaps * sizeof(D3D12_SUBRESOURCE_DATA)); - - // Create the upload texture - D3D12Resource uploadTexture; - { - D3D12_HEAP_PROPERTIES heapProps; - - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; +#endif - D3D12_RESOURCE_DESC uploadResourceDesc; - - uploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - uploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN; - uploadResourceDesc.Width = requiredSize; - uploadResourceDesc.Height = 1; - uploadResourceDesc.DepthOrArraySize = 1; - uploadResourceDesc.MipLevels = 1; - uploadResourceDesc.SampleDesc.Count = 1; - uploadResourceDesc.SampleDesc.Quality = 0; - uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - uploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - uploadResourceDesc.Alignment = 0; + // + assert(texData.dataBuffer.Count() == numMipMaps * texData.arraySize); - SLANG_RETURN_ON_FAIL(uploadTexture.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr)); - - uploadTexture.setDebugName(L"TextureUpload"); - } + // Sub resource indexing + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn705766(v=vs.85).aspx#subresource_indexing - // Map it all + int subResourceIndex = 0; + for (int i = 0; i < texData.arraySize; i++) { + // Create the upload texture + D3D12Resource uploadTexture; + { + D3D12_HEAP_PROPERTIES heapProps; + + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + + D3D12_RESOURCE_DESC uploadResourceDesc; + + uploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + uploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN; + uploadResourceDesc.Width = requiredSize; + uploadResourceDesc.Height = 1; + uploadResourceDesc.DepthOrArraySize = 1; + uploadResourceDesc.MipLevels = 1; + uploadResourceDesc.SampleDesc.Count = 1; + uploadResourceDesc.SampleDesc.Quality = 0; + uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + uploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + uploadResourceDesc.Alignment = 0; + + SLANG_RETURN_ON_FAIL(uploadTexture.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr)); + + uploadTexture.setDebugName(L"TextureUpload"); + } + ID3D12Resource* uploadResource = uploadTexture; uint8_t* p; uploadResource->Map(0, nullptr, reinterpret_cast(&p)); + + for (int j = 0; j < numMipMaps; ++j) + { + const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& layout = layouts[j]; + const D3D12_SUBRESOURCE_FOOTPRINT& footprint = layout.Footprint; - // Strictly speaking it should be bigger - assert(texData.dataBuffer.Count() == numMipMaps); + int mipWidth = width >> j; + mipWidth = (mipWidth <= 0) ? 1 : mipWidth; + + int mipHeight = height >> j; + mipHeight = (mipHeight <= 0) ? 1 : mipHeight; - for (int i = 0; i < texData.arraySize; i++) - { - for (int j = 0; j < numMipMaps; ++j) - { - int size = texData.textureSize >> j; + int mipDepth = depth >> j; + mipDepth = (mipDepth <= 0) ? 1 : mipDepth; - const size_t mipSizeInBytes = layouts[j].Footprint.RowPitch * mipNumRows[j]; + assert(footprint.Width == mipWidth && footprint.Height == mipHeight && footprint.Depth == mipDepth); - // NOTE! Like the D3D11 implementation -> this repeats the same mip pixels to every target + // NOTE! Like the D3D11 implementation -> this repeats the same mip pixels to every target (!) + const List& srcMip = texData.dataBuffer[j]; - const uint8_t* srcPixels = (const uint8_t*)texData.dataBuffer[j].Buffer(); - assert(mipSizeInBytes == texData.dataBuffer[j].Count() * sizeof(uint32_t)); + // Check the input data is the same size as expected + assert(mipWidth * mipHeight * mipDepth == srcMip.Count()); - ::memcpy(p + layouts[j].Offset, srcPixels, mipSizeInBytes); - } - } - uploadResource->Unmap(0, nullptr); - } + const ptrdiff_t dstMipRowPitch = ptrdiff_t(layouts[j].Footprint.RowPitch); + const ptrdiff_t srcMipRowPitch = ptrdiff_t(sizeof(uint32_t) * mipWidth); - { - D3D12_HEAP_PROPERTIES heapProps; + assert(dstMipRowPitch >= srcMipRowPitch); + + const uint8_t* srcRow = (const uint8_t*)srcMip.Buffer(); + uint8_t* dstRow = p + layouts[j].Offset; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; + // Copy the depth each mip + for (int l = 0; l < mipDepth; l++) + { + // Copy rows + for (int k = 0; k < mipHeight; ++k) + { + ::memcpy(dstRow, srcRow, srcMipRowPitch); - SLANG_RETURN_ON_FAIL(resourceOut.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); - - resourceOut.setDebugName(L"Texture"); - } + srcRow += srcMipRowPitch; + dstRow += dstMipRowPitch; + } + } - { - for (int i = 0; i < numMipMaps; ++i) + assert(srcRow == (const uint8_t*)(srcMip.Buffer() + srcMip.Count())); + } + uploadResource->Unmap(0, nullptr); + + for (int mipIndex = 0; mipIndex < numMipMaps; ++mipIndex) { + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn903862(v=vs.85).aspx + D3D12_TEXTURE_COPY_LOCATION src; src.pResource = uploadTexture; src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.PlacedFootprint = layouts[i]; + src.PlacedFootprint = layouts[mipIndex]; D3D12_TEXTURE_COPY_LOCATION dst; dst.pResource = resourceOut; dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst.SubresourceIndex = UINT(i); + dst.SubresourceIndex = subResourceIndex; m_commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + + subResourceIndex++; + } + + { + D3D12BarrierSubmitter submitter(m_commandList); + resourceOut.transition(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, submitter); } - } - { - D3D12BarrierSubmitter submitter(m_commandList); - resourceOut.transition(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, submitter); + // Block - waiting for copy to complete (so can drop upload texture) + submitGpuWorkAndWait(); } - // Block - waiting for copy to complete (so can drop upload texture) - submitGpuWorkAndWait(); - return SLANG_OK; } @@ -733,7 +800,7 @@ Result D3D12Renderer::createInputTexture(const InputTextureDesc& inputDesc, D3D1 DXGI_FORMAT pixelFormat = resourceDesc.Format; D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; - _initSrvDesc(resourceDesc, pixelFormat, srvDesc); + _initSrvDesc(inputDesc, resourceDesc, pixelFormat, srvDesc); // Copy to the descriptor m_device->CreateShaderResourceView(resourceOut, &srvDesc, viewHeap.getCpuHandle(srvIndex)); @@ -746,6 +813,7 @@ Result D3D12Renderer::createInputBuffer(InputBufferDesc& bufferDesc, const List< D3D12Resource& bufferOut) { const size_t bufferSize = bufferData.Count() * sizeof(unsigned int); + //bufferSize = D3DUtil::calcAligned(bufferSize, 256); D3D12_RESOURCE_DESC resourceDesc; _initBufferResourceDesc(bufferSize, resourceDesc); @@ -775,36 +843,45 @@ Result D3D12Renderer::createInputBuffer(InputBufferDesc& bufferDesc, const List< D3D12Resource uploadBuffer; SLANG_RETURN_ON_FAIL(createBuffer(resourceDesc, bufferData.Buffer(), uploadBuffer, finalState, bufferOut)); - const int elemSize = bufferDesc.stride <= 0 ? 1 : bufferDesc.stride; + const int elemSize = bufferDesc.stride <= 0 ? sizeof(uint32_t) : bufferDesc.stride; - if (bufferDesc.type == InputBufferType::StorageBuffer) + if (uavIndex >= 0) { - D3D12_UNORDERED_ACCESS_VIEW_DESC viewDesc = {}; + assert(bufferDesc.type == InputBufferType::StorageBuffer); - viewDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - viewDesc.Format = DXGI_FORMAT_UNKNOWN; + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - viewDesc.Buffer.FirstElement = 0; - viewDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize); - viewDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + + uavDesc.Buffer.StructureByteStride = elemSize; + + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize); + uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; if (bufferDesc.stride == 0) { // TODO: are there UAV cases we need to handle that are neither // raw nor structured? RWBuffer would be one... - viewDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW; - viewDesc.Format = DXGI_FORMAT_R32_TYPELESS; + uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW; + uavDesc.Format = DXGI_FORMAT_R32_TYPELESS; + + uavDesc.Buffer.StructureByteStride = 0; } - m_device->CreateUnorderedAccessView(bufferOut.getResource(), nullptr, &viewDesc, viewHeap.getCpuHandle(uavIndex)); + m_device->CreateUnorderedAccessView(bufferOut.getResource(), nullptr, &uavDesc, viewHeap.getCpuHandle(uavIndex)); } - if (bufferDesc.type != InputBufferType::ConstantBuffer) + if (srvIndex >= 0) { + //bufferDesc.type != InputBufferType::ConstantBuffer + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Buffer.FirstElement = 0; srvDesc.Buffer.NumElements = (UINT)(bufferData.Count() * sizeof(unsigned int) / elemSize); @@ -1091,9 +1168,11 @@ Result D3D12Renderer::calcGraphicsPipelineState(ComPtr& sig psoDesc.PrimitiveTopologyType = m_primitiveTopologyType; { + const int numRenderTargets = m_boundBindingState ? m_boundBindingState->m_numRenderTargets : 1; + psoDesc.DSVFormat = m_depthStencilFormat; - psoDesc.NumRenderTargets = m_boundBindingState->m_numRenderTargets; - for (Int i = 0; i < m_boundBindingState->m_numRenderTargets; i++) + psoDesc.NumRenderTargets = numRenderTargets; + for (Int i = 0; i < numRenderTargets; i++) { psoDesc.RTVFormats[i] = m_targetFormat; } @@ -1288,23 +1367,7 @@ Result D3D12Renderer::_calcBindParameters(BindParameters& params) { int numConstantBuffers = 0; { - // Okay we need to try and create a render state - for (int i = 0; i < int(m_boundConstantBuffers.Count()); i++) - { - const BufferImpl* buffer = m_boundConstantBuffers[i]; - if (buffer) - { - D3D12_ROOT_PARAMETER& param = params.nextParameter(); - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - D3D12_ROOT_DESCRIPTOR& descriptor = param.Descriptor; - descriptor.ShaderRegister = numConstantBuffers; - descriptor.RegisterSpace = 0; - - numConstantBuffers++; - } - } if (m_boundBindingState) { @@ -1312,68 +1375,86 @@ Result D3D12Renderer::_calcBindParameters(BindParameters& params) for (int i = 0; i < int(m_boundBindingState->m_bindings.Count()); i++) { const Binding& binding = m_boundBindingState->m_bindings[i]; - if (binding.m_type == ShaderInputType::Buffer) + if (binding.m_type == ShaderInputType::Buffer && binding.m_bufferType == InputBufferType::ConstantBuffer) { - if (binding.m_bufferType == InputBufferType::ConstantBuffer) - { - // Make sure it's not overlapping the ones we just statically defined - assert(binding.m_binding < numBoundConstantBuffers); + // Make sure it's not overlapping the ones we just statically defined + //assert(binding.m_binding < numBoundConstantBuffers); - D3D12_ROOT_PARAMETER& param = params.nextParameter(); - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + D3D12_ROOT_PARAMETER& param = params.nextParameter(); + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - D3D12_ROOT_DESCRIPTOR& descriptor = param.Descriptor; - descriptor.ShaderRegister = binding.m_binding; - descriptor.RegisterSpace = 0; + D3D12_ROOT_DESCRIPTOR& descriptor = param.Descriptor; + descriptor.ShaderRegister = binding.m_binding; + descriptor.RegisterSpace = 0; - numConstantBuffers++; - } + numConstantBuffers++; + } - if (binding.m_bufferType == InputBufferType::StorageBuffer) - { - D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); + if (binding.m_srvIndex >= 0) + { + D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); - range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - range.NumDescriptors = 1; - range.BaseShaderRegister = binding.m_binding; - range.RegisterSpace = 0; - range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + range.NumDescriptors = 1; + range.BaseShaderRegister = binding.m_binding; + range.RegisterSpace = 0; + range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - D3D12_ROOT_PARAMETER& param = params.nextParameter(); + D3D12_ROOT_PARAMETER& param = params.nextParameter(); - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable; - table.NumDescriptorRanges = 1; - table.pDescriptorRanges = ⦥ - } + D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable; + table.NumDescriptorRanges = 1; + table.pDescriptorRanges = ⦥ + } - if (binding.m_uavIndex >= 0) - { - D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); + if (binding.m_uavIndex >= 0) + { + D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); - range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - range.NumDescriptors = 1; - range.BaseShaderRegister = binding.m_binding; - range.RegisterSpace = 0; - range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + range.NumDescriptors = 1; + range.BaseShaderRegister = binding.m_binding; + range.RegisterSpace = 0; + range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - D3D12_ROOT_PARAMETER& param = params.nextParameter(); + D3D12_ROOT_PARAMETER& param = params.nextParameter(); - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable; - table.NumDescriptorRanges = 1; - table.pDescriptorRanges = ⦥ - } + D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable; + table.NumDescriptorRanges = 1; + table.pDescriptorRanges = ⦥ } } } } +#if 1 + // Okay we need to try and create a render state + for (int i = 0; i < int(m_boundConstantBuffers.Count()); i++) + { + const BufferImpl* buffer = m_boundConstantBuffers[i]; + if (buffer) + { + D3D12_ROOT_PARAMETER& param = params.nextParameter(); + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + D3D12_ROOT_DESCRIPTOR& descriptor = param.Descriptor; + descriptor.ShaderRegister = numConstantBuffers; + descriptor.RegisterSpace = 0; + + numConstantBuffers++; + } + } +#endif + + // All the samplers are in one continuous section of the sampler heap if (m_boundBindingState && m_boundBindingState->m_samplerHeap.getUsedSize() > 0) { D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); @@ -1403,11 +1484,50 @@ Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsC submitter->setRootSignature(renderState->m_rootSignature); commandList->SetPipelineState(renderState->m_pipelineState); + if (bindingState) + { + ID3D12DescriptorHeap* heaps[] = + { + bindingState->m_viewHeap.getHeap(), + bindingState->m_samplerHeap.getHeap(), + }; + commandList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps); + } + else + { + commandList->SetDescriptorHeaps(0, nullptr); + } + { int index = 0; int numConstantBuffers = 0; { + if (bindingState) + { + D3D12DescriptorHeap& heap = bindingState->m_viewHeap; + + for (int i = 0; i < int(bindingState->m_bindings.Count()); i++) + { + const Binding& binding = bindingState->m_bindings[i]; + if (binding.m_type == ShaderInputType::Buffer && binding.m_bufferType == InputBufferType::ConstantBuffer) + { + submitter->setRootConstantBufferView(index++, binding.m_resource.getResource()->GetGPUVirtualAddress()); + numConstantBuffers++; + } + + if (binding.m_srvIndex >= 0) + { + submitter->setRootDescriptorTable(index++, heap.getGpuHandle(binding.m_srvIndex)); + } + + if (binding.m_uavIndex >= 0) + { + submitter->setRootDescriptorTable(index++, heap.getGpuHandle(binding.m_uavIndex)); + } + } + } + // Okay we need to try and create a render state for (int i = 0; i < int(m_boundConstantBuffers.Count()); i++) { @@ -1420,37 +1540,8 @@ Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsC ::memcpy(cursor.m_position, buffer->m_memory.Buffer(), bufferSize); // Set the constant buffer submitter->setRootConstantBufferView(index++, m_circularResourceHeap.getGpuHandle(cursor)); - - numConstantBuffers++; - } - } - - if (bindingState) - { - D3D12DescriptorHeap& heap = bindingState->m_viewHeap; - - for (int i = 0; i < int(bindingState->m_bindings.Count()); i++) - { - const Binding& binding = bindingState->m_bindings[i]; - if (binding.m_type == ShaderInputType::Buffer) - { - if (binding.m_bufferType == InputBufferType::ConstantBuffer) - { - submitter->setRootConstantBufferView(index++, binding.m_resource.getResource()->GetGPUVirtualAddress()); - numConstantBuffers++; - } - - if (binding.m_bufferType == InputBufferType::StorageBuffer) - { - submitter->setRootDescriptorTable(index++, heap.getGpuHandle(binding.m_srvIndex)); - } - - if (binding.m_uavIndex >= 0) - { - submitter->setRootDescriptorTable(index++, heap.getGpuHandle(binding.m_uavIndex)); - } - } + numConstantBuffers++; } } } @@ -1461,19 +1552,7 @@ Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsC } } - if (bindingState) - { - ID3D12DescriptorHeap* heaps[] = - { - bindingState->m_viewHeap.getHeap(), - bindingState->m_samplerHeap.getHeap(), - }; - commandList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps); - } - else - { - commandList->SetDescriptorHeaps(0, nullptr); - } + return SLANG_OK; } @@ -1550,27 +1629,37 @@ Result D3D12Renderer::initialize(void* inWindowHandle) return SLANG_FAIL; } - UINT adapterCounter = 0; - for (;;) + const bool useWarp = false; + + if (useWarp) { - UINT adapterIndex = adapterCounter++; + SLANG_RETURN_ON_FAIL(dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(adapter.writeRef()))); + SLANG_RETURN_ON_FAIL(D3D12CreateDevice_(adapter, featureLevel, IID_PPV_ARGS(m_device.writeRef()))); + } + else + { + UINT adapterCounter = 0; + for (;;) + { + UINT adapterIndex = adapterCounter++; - ComPtr candidateAdapter; - if (dxgiFactory->EnumAdapters1(adapterIndex, candidateAdapter.writeRef()) == DXGI_ERROR_NOT_FOUND) - break; + ComPtr candidateAdapter; + if (dxgiFactory->EnumAdapters1(adapterIndex, candidateAdapter.writeRef()) == DXGI_ERROR_NOT_FOUND) + break; - DXGI_ADAPTER_DESC1 desc; - candidateAdapter->GetDesc1(&desc); + 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(m_device.writeRef())))) - { - // We found one! - adapter = candidateAdapter; - break; + 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(m_device.writeRef())))) + { + // We found one! + adapter = candidateAdapter; + break; + } } } @@ -2155,6 +2244,12 @@ void D3D12Renderer::draw(UInt vertexCount, UInt startVertex) ID3D12GraphicsCommandList* commandList = m_commandList; RenderState* renderState = calcRenderState(); + if (!renderState) + { + assert(!"Couldn't create render state"); + return; + } + BindingStateImpl* bindingState = m_boundBindingState; // Submit - setting for graphics @@ -2227,12 +2322,17 @@ BindingState* D3D12Renderer::createBindingState(const ShaderInputLayout& layout) { case ShaderInputType::Buffer: { - dstEntry.m_uavIndex = bindingState->m_viewHeap.allocate(); - dstEntry.m_srvIndex = bindingState->m_viewHeap.allocate(); - - if (dstEntry.m_uavIndex < 0 || dstEntry.m_srvIndex < 0) + // NOTE! In this arrangement the buffer can either be a ConstantBuffer or a 'StorageBuffer'. + // If it's a storage buffer then it has a 'uav'. + // In neither circumstance is there an associated srv + // This departs a little from dx11 code - in that it will create srv and uav for a storage buffer. + if (srcEntry.bufferDesc.type == InputBufferType::StorageBuffer) { - return nullptr; + dstEntry.m_uavIndex = bindingState->m_viewHeap.allocate(); + if (dstEntry.m_uavIndex < 0) + { + return nullptr; + } } SLANG_RETURN_NULL_ON_FAIL(createInputBuffer(srcEntry.bufferDesc, srcEntry.bufferData, bindingState->m_viewHeap, dstEntry.m_uavIndex, dstEntry.m_srvIndex, dstEntry.m_resource)); @@ -2299,8 +2399,8 @@ void D3D12Renderer::serializeOutput(BindingState* stateIn, const char* fileName) if (binding.m_resource.getResource()) { // create staging buffer - - size_t bufferSize = D3DUtil::calcAligned(binding.m_bufferLength, 256); + //size_t bufferSize = D3DUtil::calcAligned(binding.m_bufferLength, 256); + const size_t bufferSize = binding.m_bufferLength; D3D12_RESOURCE_DESC stagingDesc; _initBufferResourceDesc(bufferSize, stagingDesc); diff --git a/tools/render-test/resource-d3d12.h b/tools/render-test/resource-d3d12.h index a6537a7d7..1de915489 100644 --- a/tools/render-test/resource-d3d12.h +++ b/tools/render-test/resource-d3d12.h @@ -108,12 +108,12 @@ struct D3D12ResourceBase /// True if a resource is set SLANG_FORCE_INLINE bool isSet() const { return m_resource != nullptr; } - /// Coercable into ID3D12Resource + /// Coercible into ID3D12Resource SLANG_FORCE_INLINE operator ID3D12Resource*() const { return m_resource; } /// restore previous state #if SLANG_ENABLE_CONSERVATIVE_RESOURCE_BARRIERS - NV_FORCE_INLINE Void restore(Dx12BarrierSubmitter& submitter) { transition(m_prevState, submitter); } + SLANG_FORCE_INLINE Void restore(D3D12BarrierSubmitter& submitter) { transition(m_prevState, submitter); } #else SLANG_FORCE_INLINE void restore(D3D12BarrierSubmitter& submitter) { SLANG_UNUSED(submitter) } #endif @@ -132,9 +132,9 @@ protected: /// This is protected so as clients cannot slice the class, and so state tracking is lost ~D3D12ResourceBase() {} - ID3D12Resource* m_resource; - D3D12_RESOURCE_STATES m_state; - D3D12_RESOURCE_STATES m_prevState; + ID3D12Resource* m_resource; ///< The resource (ref counted) + D3D12_RESOURCE_STATES m_state; ///< The current tracked expected state, if all associated transitions have completed on ID3D12CommandList + D3D12_RESOURCE_STATES m_prevState; ///< The previous state }; struct D3D12Resource : public D3D12ResourceBase diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h index c4c3d9d8c..0f5a54326 100644 --- a/tools/render-test/shader-input-layout.h +++ b/tools/render-test/shader-input-layout.h @@ -3,70 +3,77 @@ #include "core/basic.h" -namespace renderer_test +namespace renderer_test { + +enum class ShaderInputType +{ + Buffer, Texture, Sampler, CombinedTextureSampler +}; + +enum class InputTextureContent +{ + Zero, One, ChessBoard, Gradient +}; + +struct InputTextureDesc +{ + int dimension = 2; + int arrayLength = 0; + bool isCube = false; + bool isDepthTexture = false; + bool isRWTexture = false; + int size = 4; + InputTextureContent content = InputTextureContent::One; +}; + +enum class InputBufferType +{ + ConstantBuffer, StorageBuffer +}; + +struct InputBufferDesc +{ + InputBufferType type = InputBufferType::ConstantBuffer; + int stride = 0; // stride == 0 indicates an unstructured buffer. +}; + +struct InputSamplerDesc +{ + bool isCompareSampler = false; +}; + +class ShaderInputLayoutEntry +{ +public: + ShaderInputType type; + Slang::List bufferData; + InputTextureDesc textureDesc; + InputBufferDesc bufferDesc; + InputSamplerDesc samplerDesc; + bool isOutput = false; + int hlslBinding = -1; + Slang::List glslBinding; +}; + +struct TextureData +{ + Slang::List> dataBuffer; + int textureSize; + int mipLevels; + int arraySize; +}; + +class ShaderInputLayout { - enum class ShaderInputType - { - Buffer, Texture, Sampler, CombinedTextureSampler - }; - enum class InputTextureContent - { - Zero, One, ChessBoard, Gradient - }; - struct InputTextureDesc - { - int dimension = 2; - int arrayLength = 0; - bool isCube = false; - bool isDepthTexture = false; - bool isRWTexture = false; - int size = 4; - InputTextureContent content = InputTextureContent::One; - }; - enum class InputBufferType - { - ConstantBuffer, StorageBuffer - }; - struct InputBufferDesc - { - InputBufferType type = InputBufferType::ConstantBuffer; - int stride = 0; // stride == 0 indicates an unstructured buffer. - }; - struct InputSamplerDesc - { - bool isCompareSampler = false; - }; - class ShaderInputLayoutEntry - { - public: - ShaderInputType type; - Slang::List bufferData; - InputTextureDesc textureDesc; - InputBufferDesc bufferDesc; - InputSamplerDesc samplerDesc; - bool isOutput = false; - int hlslBinding = -1; - Slang::List glslBinding; - - }; +public: + Slang::List entries; + Slang::List globalTypeArguments; + int numRenderTargets = 1; + void Parse(const char * source); +}; - struct TextureData - { - Slang::List> dataBuffer; - int textureSize; - int mipLevels; - int arraySize; - }; - void generateTextureData(TextureData & output, const InputTextureDesc & desc); +void generateTextureData(TextureData & output, const InputTextureDesc & desc); - class ShaderInputLayout - { - public: - Slang::List entries; - Slang::List globalTypeArguments; - int numRenderTargets = 1; - void Parse(const char * source); - }; -} +} // namespace render_test #endif \ No newline at end of file -- cgit v1.2.3