diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-04-10 17:53:03 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-04-10 17:53:03 -0400 |
| commit | c4004b32ca2c0effb455ec847114240db3cb993b (patch) | |
| tree | 7530f131892e2973929948e61e46e957d38510a2 | |
| parent | 5298ccf7da486d0010c6157974d5dd9a5556f265 (diff) | |
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.
| -rw-r--r-- | source/core/core.vcxproj | 2 | ||||
| -rw-r--r-- | source/core/list.h | 2 | ||||
| -rw-r--r-- | source/core/slang-string-util.cpp | 29 | ||||
| -rw-r--r-- | source/core/slang-string-util.h | 17 | ||||
| -rw-r--r-- | source/core/slang-string.h | 29 | ||||
| -rw-r--r-- | tests/compute/array-param.slang | 1 | ||||
| -rw-r--r-- | tools/render-test/d3d-util.h | 6 | ||||
| -rw-r--r-- | tools/render-test/main.cpp | 12 | ||||
| -rw-r--r-- | tools/render-test/options.cpp | 27 | ||||
| -rw-r--r-- | tools/render-test/options.h | 3 | ||||
| -rw-r--r-- | tools/render-test/render-d3d12.cpp | 542 | ||||
| -rw-r--r-- | tools/render-test/resource-d3d12.h | 10 | ||||
| -rw-r--r-- | tools/render-test/shader-input-layout.h | 131 | ||||
| -rw-r--r-- | tools/slang-test/main.cpp | 153 | ||||
| -rw-r--r-- | tools/slang-test/render-api-util.cpp | 210 | ||||
| -rw-r--r-- | tools/slang-test/render-api-util.h | 61 | ||||
| -rw-r--r-- | tools/slang-test/slang-test.vcxproj | 2 | ||||
| -rw-r--r-- | tools/slang-test/slang-test.vcxproj.filters | 6 |
18 files changed, 926 insertions, 317 deletions
diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj index 77e91b32f..803c1ab12 100644 --- a/source/core/core.vcxproj +++ b/source/core/core.vcxproj @@ -36,6 +36,7 @@ <ClInclude Include="slang-io.h" /> <ClInclude Include="slang-math.h" /> <ClInclude Include="slang-result.h" /> + <ClInclude Include="slang-string-util.h" /> <ClInclude Include="slang-string.h" /> <ClInclude Include="smart-pointer.h" /> <ClInclude Include="stream.h" /> @@ -47,6 +48,7 @@ <ClCompile Include="platform.cpp" /> <ClCompile Include="slang-free-list.cpp" /> <ClCompile Include="slang-io.cpp" /> + <ClCompile Include="slang-string-util.cpp" /> <ClCompile Include="slang-string.cpp" /> <ClCompile Include="stream.cpp" /> <ClCompile Include="text-io.cpp" /> diff --git a/source/core/list.h b/source/core/list.h index 6c4a04fc7..3a325955a 100644 --- a/source/core/list.h +++ b/source/core/list.h @@ -504,7 +504,7 @@ namespace Slang template<typename T2> UInt IndexOf(const T2 & val) const { - for (int i = 0; i < _count; i++) + for (UInt i = 0; i < _count; i++) { if (buffer[i] == val) return i; diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp new file mode 100644 index 000000000..c60ad9683 --- /dev/null +++ b/source/core/slang-string-util.cpp @@ -0,0 +1,29 @@ +#include "slang-string-util.h" + +namespace Slang { + +/* static */void StringUtil::split(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& slicesOut) +{ + slicesOut.Clear(); + + const char* start = in.begin(); + const char* end = in.end(); + + while (start < end) + { + // Move cur so it's either at the end or at next split character + const char* cur = start; + while (cur < end && *cur != splitChar) + { + cur++; + } + + // Add to output + slicesOut.Add(UnownedStringSlice(start, cur)); + + // Skip the split character, if at end we are okay anyway + start = cur + 1; + } +} + +} // namespace Slang diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h new file mode 100644 index 000000000..bae576370 --- /dev/null +++ b/source/core/slang-string-util.h @@ -0,0 +1,17 @@ +#ifndef SLANG_STRING_UTIL_H +#define SLANG_STRING_UTIL_H + +#include "slang-string.h" +#include "list.h" + +namespace Slang { + +struct StringUtil +{ + static void split(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& slicesOut); +}; + +} // namespace Slang + + +#endif // SLANG_STRING_UTIL_H diff --git a/source/core/slang-string.h b/source/core/slang-string.h index 7d8d3eb81..9f18554f6 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -135,10 +135,14 @@ namespace Slang { public: UnownedStringSlice() - : beginData(0) + : beginData(nullptr) , endData(0) {} + explicit UnownedStringSlice(char const* a): + beginData(a), + endData(a + strlen(a)) + {} UnownedStringSlice(char const* b, char const* e) : beginData(b) , endData(e) @@ -159,13 +163,32 @@ namespace Slang return endData - beginData; } - bool operator==(UnownedStringSlice const& other) + int indexOf(char c) const + { + const int size = int(endData - beginData); + for (int i = 0; i < size; ++i) + { + if (beginData[i] == c) + { + return i; + } + } + return -1; + } + + const char& operator[](int i) const + { + assert(i >= 0 && i < int(endData - beginData)); + return beginData[i]; + } + + bool operator==(UnownedStringSlice const& other) const { return size() == other.size() && memcmp(begin(), other.begin(), size()) == 0; } - bool operator==(char const* str) + bool operator==(char const* str) const { return (*this) == UnownedStringSlice(str, str + strlen(str)); } diff --git a/tests/compute/array-param.slang b/tests/compute/array-param.slang index f6b9fd474..deead3aeb 100644 --- a/tests/compute/array-param.slang +++ b/tests/compute/array-param.slang @@ -1,4 +1,5 @@ //TEST(compute):COMPARE_COMPUTE_EX:-slang -compute +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 //TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute //TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out 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<ID3DBlob>& 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<BindingState> 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<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> 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<D3D12_SUBRESOURCE_DATA> 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<void**>(&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<uint32_t>& 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<T> 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<ID3D12RootSignature>& 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<IDXGIAdapter1> candidateAdapter; - if (dxgiFactory->EnumAdapters1(adapterIndex, candidateAdapter.writeRef()) == DXGI_ERROR_NOT_FOUND) - break; + ComPtr<IDXGIAdapter1> 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<unsigned int> bufferData; + InputTextureDesc textureDesc; + InputBufferDesc bufferDesc; + InputSamplerDesc samplerDesc; + bool isOutput = false; + int hlslBinding = -1; + Slang::List<int> glslBinding; +}; + +struct TextureData +{ + Slang::List<Slang::List<unsigned int>> 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<unsigned int> bufferData; - InputTextureDesc textureDesc; - InputBufferDesc bufferDesc; - InputSamplerDesc samplerDesc; - bool isOutput = false; - int hlslBinding = -1; - Slang::List<int> glslBinding; - - }; +public: + Slang::List<ShaderInputLayoutEntry> entries; + Slang::List<Slang::String> globalTypeArguments; + int numRenderTargets = 1; + void Parse(const char * source); +}; - struct TextureData - { - Slang::List<Slang::List<unsigned int>> 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<ShaderInputLayoutEntry> entries; - Slang::List<Slang::String> globalTypeArguments; - int numRenderTargets = 1; - void Parse(const char * source); - }; -} +} // namespace render_test #endif
\ No newline at end of file diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp index 0f469e8d9..e67db42e4 100644 --- a/tools/slang-test/main.cpp +++ b/tools/slang-test/main.cpp @@ -4,10 +4,12 @@ #include "../../source/core/token-reader.h" #include "../../source/core/slang-result.h" +#include "../../source/core/slang-string-util.h" using namespace Slang; #include "os.h" +#include "render-api-util.h" #define STB_IMAGE_IMPLEMENTATION #include "external/stb/stb_image.h" @@ -70,6 +72,9 @@ struct Options // Exclude test that match one these categories Dictionary<TestCategory*, TestCategory*> excludeCategories; + + // By default we can test against all apis + int enabledApis = int(RenderApiFlag::AllOf); }; Options options; @@ -188,6 +193,22 @@ Result parseOptions(int* argc, char** argv) options.excludeCategories.Add(category, category); } } + else if (strcmp(arg, "-api") == 0) + { + if (argCursor == argEnd) + { + fprintf(stderr, "error: expected comma separated list of apis '%s'\n", arg); + return SLANG_FAIL; + } + const char* apiList = *argCursor++; + + SlangResult res = RenderApiUtil::parseApiFlags(UnownedStringSlice(apiList), &options.enabledApis); + if (SLANG_FAILED(res)) + { + fprintf(stderr, "error: unable to parse api list '%s'\n", apiList); + return res; + } + } else { fprintf(stderr, "unknown option '%s'\n", arg); @@ -195,6 +216,13 @@ Result parseOptions(int* argc, char** argv) } } + { + // Find out what apis are available + const int availableApis = RenderApiUtil::getAvailableApis(); + // Only allow apis we know are available + options.enabledApis &= availableApis; + } + // any arguments left over were positional arguments argCount = (int)((char**)writeCursor - argv); argCursor = argv; @@ -636,6 +664,44 @@ void maybeDumpOutput( fflush(stderr); } +// Finds the specialized or default path for expected data for a test. +// If neither are found, will return an empty string +String findExpectedPath(const TestInput& input, const char* postFix) +{ + StringBuilder specializedBuf; + + // Try the specialized name first + specializedBuf << input.outputStem; + if (postFix) + { + specializedBuf << postFix; + } + if (File::Exists(specializedBuf)) + { + return specializedBuf; + } + + + // Try the default name + StringBuilder defaultBuf; + defaultBuf.Clear(); + defaultBuf << input.filePath; + if (postFix) + { + defaultBuf << postFix; + } + + if (File::Exists(defaultBuf)) + { + return defaultBuf; + } + + // Couldn't find either + printf("referenceOutput '%s' or '%s' not found.\n", defaultBuf.Buffer(), specializedBuf.Buffer()); + + return ""; +} + TestResult runSimpleTest(TestInput& input) { // need to execute the stand-alone Slang compiler on the file, and compare its output to what we expect @@ -1124,12 +1190,19 @@ TestResult runGLSLComparisonTest(TestInput& input) return kTestResult_Pass; } -TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, String referenceOutput) + +TestResult runComputeComparisonImpl(TestInput& input, const char * langOption) { // TODO: delete any existing files at the output path(s) to avoid stale outputs leading to a false pass auto filePath999 = input.filePath; auto outputStem = input.outputStem; + const String referenceOutput = findExpectedPath(input, ".expected.txt"); + if (referenceOutput.Length() <= 0) + { + return kTestResult_Fail; + } + OSProcessSpawner spawner; spawner.pushExecutablePath(String(options.binDir) + "render-test" + osGetExecutableSuffix()); @@ -1211,22 +1284,22 @@ TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, S TestResult runSlangComputeComparisonTest(TestInput& input) { - return runComputeComparisonImpl(input, "-slang -compute", input.outputStem + ".expected.txt"); + return runComputeComparisonImpl(input, "-slang -compute"); } TestResult runSlangComputeComparisonTestEx(TestInput& input) { - return runComputeComparisonImpl(input, "", input.outputStem + ".expected.txt"); + return runComputeComparisonImpl(input, ""); } TestResult runHLSLComputeTest(TestInput& input) { - return runComputeComparisonImpl(input, "-hlsl-rewrite -compute", input.outputStem + ".expected.txt"); + return runComputeComparisonImpl(input, "-hlsl-rewrite -compute"); } TestResult runSlangRenderComputeComparisonTest(TestInput& input) { - return runComputeComparisonImpl(input, "-slang -gcompute", input.outputStem + ".expected.txt"); + return runComputeComparisonImpl(input, "-slang -gcompute"); } TestResult doRenderComparisonTestRun(TestInput& input, char const* langOption, char const* outputKind, String* outOutput) @@ -1411,12 +1484,48 @@ TestResult skipTest(TestInput& /*input*/) return kTestResult_Ignored; } +static bool hasD3D12Option(const TestOptions& testOptions) +{ + return (testOptions.args.IndexOf("-dx12") != UInt(-1) || + testOptions.args.IndexOf("-d3d12") != UInt(-1)); +} + +bool hasD3D12Option(const FileTestList& testList) +{ + const int numTests = int(testList.tests.Count()); + for (int i = 0; i < numTests; i++) + { + if (hasD3D12Option(testList.tests[i])) + { + return true; + } + } + return false; +} + +bool isRenderTest(const String& command) +{ + return command == "COMPARE_COMPUTE" || + command == "COMPARE_COMPUTE_EX" || + command == "HLSL_COMPUTE" || + command == "COMPARE_RENDER_COMPUTE" || + command == "COMPARE_HLSL_RENDER" || + command == "COMPARE_HLSL_CROSS_COMPILE_RENDER" || + command == "COMPARE_HLSL_GLSL_RENDER"; +} + TestResult runTest( String const& filePath, String const& outputStem, TestOptions const& testOptions, FileTestList const& testList) { + // If this is d3d12 test + if (hasD3D12Option(testOptions) && (options.enabledApis & RenderApiFlag::D3D12) == 0) + { + return kTestResult_Ignored; + } + // based on command name, dispatch to an appropriate callback struct TestCommands { @@ -1426,11 +1535,11 @@ TestResult runTest( static const TestCommands kTestCommands[] = { - { "SIMPLE", &runSimpleTest }, - { "REFLECTION", &runReflectionTest }, + { "SIMPLE", &runSimpleTest}, + { "REFLECTION", &runReflectionTest}, #if SLANG_TEST_SUPPORT_HLSL - { "COMPARE_HLSL", &runHLSLComparisonTest }, - { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest }, + { "COMPARE_HLSL", &runHLSLComparisonTest}, + { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest}, { "COMPARE_HLSL_CROSS_COMPILE_RENDER", &runHLSLCrossCompileRenderComparisonTest}, { "COMPARE_HLSL_GLSL_RENDER", &runHLSLAndGLSLRenderComparisonTest }, { "COMPARE_COMPUTE", runSlangComputeComparisonTest}, @@ -1623,6 +1732,9 @@ bool testPassesCategoryMask( return false; } + + + void runTestsOnFile( TestContext* context, String filePath) @@ -1643,6 +1755,29 @@ void runTestsOnFile( return; } + // If dx12 is available synthesize Dx12 test + if ((options.enabledApis & RenderApiFlag::D3D12) != 0) + { + // If doesn't have option generate dx12 options from dx11 + if (!hasD3D12Option(testList)) + { + const int numTests = int(testList.tests.Count()); + for (int i = 0; i < numTests; i++) + { + const TestOptions& testOptions = testList.tests[i]; + // If it's a render test, and there is on d3d option, add one + if (isRenderTest(testOptions.command) && !hasD3D12Option(testOptions)) + { + // Add with -dx12 option + TestOptions testOptionsCopy(testOptions); + testOptionsCopy.args.Add("-dx12"); + + testList.tests.Add(testOptionsCopy); + } + } + } + } + // We have found a test to run! int subTestCount = 0; for( auto& tt : testList.tests ) diff --git a/tools/slang-test/render-api-util.cpp b/tools/slang-test/render-api-util.cpp new file mode 100644 index 000000000..b8697c54b --- /dev/null +++ b/tools/slang-test/render-api-util.cpp @@ -0,0 +1,210 @@ + +#include "render-api-util.h" + +#include "../../source/core/slang-defines.h" + +#include "../../source/core/list.h" +#include "../../source/core/slang-string-util.h" + +/* static */const RenderApiUtil::Info RenderApiUtil::s_infos[] = +{ + { RenderApiType::OpenGl, "gl,ogl,opengl"}, + { RenderApiType::Vulkan, "vk,vulkan"}, + { RenderApiType::D3D12, "dx12,d3d12"}, + { RenderApiType::D3D11, "dx11,d3d11"}, +}; + +static int _calcAvailableApis() +{ + int flags = 0; + for (int i = 0; i < int(RenderApiType::CountOf); i++) + { + if (RenderApiUtil::calcHasApi(RenderApiType(i))) + { + flags |= (1 << i); + } + } + + return flags; +} + +/* static */int RenderApiUtil::getAvailableApis() +{ + static int s_availableApis = _calcAvailableApis(); + return s_availableApis; +} + +/* static */RenderApiType RenderApiUtil::findApiTypeByName(const Slang::UnownedStringSlice& name) +{ + using namespace Slang; + List<UnownedStringSlice> namesList; + for (int j = 0; j < SLANG_COUNT_OF(RenderApiUtil::s_infos); j++) + { + const auto& apiInfo = RenderApiUtil::s_infos[j]; + const UnownedStringSlice names(apiInfo.names); + + if (names.indexOf(',') >= 0) + { + StringUtil::split(names, ',', namesList); + if (namesList.IndexOf(name) != UInt(-1)) + { + return apiInfo.type; + } + } + else if (names == name) + { + return apiInfo.type; + } + } + return RenderApiType::Unknown; +} + +/* static */int RenderApiUtil::findApiFlagsByName(const Slang::UnownedStringSlice& name) +{ + // Special case 'all' + if (name == "all") + { + return int(RenderApiFlag::AllOf); + } + RenderApiType type = findApiTypeByName(name); + return (type == RenderApiType::Unknown) ? 0 : (1 << int(type)); +} + +/* static */Slang::Result RenderApiUtil::parseApiFlags(const Slang::UnownedStringSlice& text, int* apiBitsOut) +{ + using namespace Slang; + + int apiBits = 0; + + List<UnownedStringSlice> slices; + StringUtil::split(text, ',', slices); + + for (int i = 0; i < int(slices.Count()); ++i) + { + UnownedStringSlice slice = slices[i]; + bool add = true; + if (slice.size() <= 0) + { + return SLANG_FAIL; + } + if (slice[0] == '+') + { + // Drop the + + slice = UnownedStringSlice(slice.begin() + 1, slice.end()); + } + else if (slice[0] == '-') + { + add = false; + // Drop the + + slice = UnownedStringSlice(slice.begin() + 1, slice.end()); + } + + // We need to find the bits... + int bits = findApiFlagsByName(slice); + // 0 means an error + if (bits == 0) + { + return SLANG_FAIL; + } + + if (add) + { + apiBits |= bits; + } + else + { + apiBits &= ~bits; + } + } + + *apiBitsOut = apiBits; + return SLANG_OK; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!! Platform specific stuff !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + + +#if SLANG_WINDOWS_FAMILY + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include <Windows.h> +#undef WIN32_LEAN_AND_MEAN +#undef NOMINMAX + +namespace { // anonymous + +class WinModule +{ +public: + + /// Initialize. Returns the module on success + HMODULE init(const char* name) + { + if (m_module) + { + ::FreeModule(m_module); + m_module = nullptr; + } + return m_module = ::LoadLibraryA(name); + } + + /// convert to HMODULE + SLANG_FORCE_INLINE operator HMODULE() const { return m_module; } + + /// True if loaded + bool isLoaded() const { return m_module != nullptr; } + + explicit WinModule(const char* name) : + m_module(nullptr) + { + init(name); + } + + /// Ctor + WinModule() :m_module(nullptr) {} + /// Dtor + ~WinModule() + { + if (m_module) + { + ::FreeLibrary(m_module); + } + } + +protected: + HMODULE m_module; +}; + +} // anonymous + +#else +#endif + +/* static */bool RenderApiUtil::calcHasApi(RenderApiType type) +{ +#if SLANG_WINDOWS_FAMILY + switch (type) + { + case RenderApiType::OpenGl: return WinModule("opengl32.dll").isLoaded(); + case RenderApiType::Vulkan: return WinModule("vulkan-1.dll").isLoaded(); + case RenderApiType::D3D11: return WinModule("d3d11.dll").isLoaded(); + case RenderApiType::D3D12: return WinModule("d3d12.dll").isLoaded(); + + default: return false; + } + +#else + + switch (type) + { + case RenderApiType::OpenGl: + case RenderApiType::Vulkan: + { + return true; + } + default: return false; + } +#endif + +} diff --git a/tools/slang-test/render-api-util.h b/tools/slang-test/render-api-util.h new file mode 100644 index 000000000..0f941f05d --- /dev/null +++ b/tools/slang-test/render-api-util.h @@ -0,0 +1,61 @@ +#ifndef SLANG_RENDER_API_UTIL_H +#define SLANG_RENDER_API_UTIL_H + +#include "../../source/core/slang-string.h" +#include "../../source/core/slang-result.h" + + +enum class RenderApiType +{ + Unknown = -1, + OpenGl = 0, + Vulkan, + D3D12, + D3D11, + CountOf, +}; + +// Use a struct wrapped Enum instead of enum class, cos we want to be able to manipulate as integrals +struct RenderApiFlag +{ + enum Enum + { + OpenGl = 1 << int(RenderApiType::OpenGl), + Vulkan = 1 << int(RenderApiType::Vulkan), + D3D12 = 1 << int(RenderApiType::D3D12), + D3D11 = 1 << int(RenderApiType::D3D11), + AllOf = (1 << int(RenderApiType::CountOf)) - 1 ///< All bits set + }; +}; + +struct RenderApiUtil +{ + struct Info + { + RenderApiType type; ///< The type + const char* names; ///< Comma separated list of names associated with the type + }; + + /// Returns true if the API is available. + static bool calcHasApi(RenderApiType type); + + /// Returns a combination of RenderApiFlag bits which if set indicates that the API is available. + static int getAvailableApis(); + + /// Returns -1 if unknown + static RenderApiType findApiTypeByName(const Slang::UnownedStringSlice& name); + /// Returns 0 if none found. + static int findApiFlagsByName(const Slang::UnownedStringSlice& name); + + /// Parse api flags string (comma delimited list of api names, or 'all' for all) + /// For example "all,-dx12" would be all apis, except dx12 + static Slang::Result parseApiFlags(const Slang::UnownedStringSlice& text, int* apiBitsOut); + + /// Get information about a render API + static const Info& getInfo(RenderApiType type) { return s_infos[int(type)]; } + + /// Static information about each render api + static const Info s_infos[int(RenderApiType::CountOf)]; +}; + +#endif // SLANG_RENDER_API_UTIL_H
\ No newline at end of file diff --git a/tools/slang-test/slang-test.vcxproj b/tools/slang-test/slang-test.vcxproj index fc4e88493..34d9bed40 100644 --- a/tools/slang-test/slang-test.vcxproj +++ b/tools/slang-test/slang-test.vcxproj @@ -160,9 +160,11 @@ <ItemGroup> <ClCompile Include="main.cpp" /> <ClCompile Include="os.cpp" /> + <ClCompile Include="render-api-util.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="os.h" /> + <ClInclude Include="render-api-util.h" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\source\core\core.vcxproj"> diff --git a/tools/slang-test/slang-test.vcxproj.filters b/tools/slang-test/slang-test.vcxproj.filters index 3549e6046..e9342cfd6 100644 --- a/tools/slang-test/slang-test.vcxproj.filters +++ b/tools/slang-test/slang-test.vcxproj.filters @@ -21,10 +21,16 @@ <ClCompile Include="os.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="render-api-util.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="os.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="render-api-util.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project>
\ No newline at end of file |
