diff options
Diffstat (limited to 'tools')
| -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 |
12 files changed, 850 insertions, 313 deletions
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 |
