diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2024-10-29 14:49:26 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-29 14:49:26 +0800 |
| commit | f65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch) | |
| tree | ea1d61342cd29368e19135000ec2948813096205 /tools/gfx-unit-test | |
| parent | a729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff) | |
format
* format
* Minor test fixes
* enable checking cpp format in ci
Diffstat (limited to 'tools/gfx-unit-test')
38 files changed, 9415 insertions, 8673 deletions
diff --git a/tools/gfx-unit-test/buffer-barrier-test.cpp b/tools/gfx-unit-test/buffer-barrier-test.cpp index 007a0d180..80723d2e4 100644 --- a/tools/gfx-unit-test/buffer-barrier-test.cpp +++ b/tools/gfx-unit-test/buffer-barrier-test.cpp @@ -1,159 +1,179 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - struct Shader - { - ComPtr<IShaderProgram> program; - slang::ProgramLayout* reflection = nullptr; - ComputePipelineStateDesc pipelineDesc = {}; - ComPtr<gfx::IPipelineState> pipelineState; - }; +struct Shader +{ + ComPtr<IShaderProgram> program; + slang::ProgramLayout* reflection = nullptr; + ComputePipelineStateDesc pipelineDesc = {}; + ComPtr<gfx::IPipelineState> pipelineState; +}; - struct Buffer - { - IBufferResource::Desc desc; - ComPtr<IBufferResource> buffer; - ComPtr<IResourceView> view; - }; +struct Buffer +{ + IBufferResource::Desc desc; + ComPtr<IBufferResource> buffer; + ComPtr<IResourceView> view; +}; + +void createFloatBuffer( + IDevice* device, + Buffer& outBuffer, + bool unorderedAccess, + float* initialData, + size_t elementCount) +{ + outBuffer = {}; + IBufferResource::Desc& bufferDesc = outBuffer.desc; + bufferDesc.sizeInBytes = elementCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.defaultState = + unorderedAccess ? ResourceState::UnorderedAccess : ResourceState::ShaderResource; + bufferDesc.memoryType = MemoryType::DeviceLocal; + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::CopyDestination, + ResourceState::CopySource); + if (unorderedAccess) + bufferDesc.allowedStates.add(ResourceState::UnorderedAccess); + + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, outBuffer.buffer.writeRef())); + + IResourceView::Desc viewDesc = {}; + viewDesc.type = unorderedAccess ? IResourceView::Type::UnorderedAccess + : IResourceView::Type::ShaderResource; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(outBuffer.buffer, nullptr, viewDesc, outBuffer.view.writeRef())); +} - void createFloatBuffer(IDevice* device, Buffer& outBuffer, bool unorderedAccess, float* initialData, size_t elementCount) +void barrierTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + Shader programA; + Shader programB; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + programA.program, + "buffer-barrier-test", + "computeA", + programA.reflection)); + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + programB.program, + "buffer-barrier-test", + "computeB", + programB.reflection)); + programA.pipelineDesc.program = programA.program.get(); + programB.pipelineDesc.program = programB.program.get(); + GFX_CHECK_CALL_ABORT(device->createComputePipelineState( + programA.pipelineDesc, + programA.pipelineState.writeRef())); + GFX_CHECK_CALL_ABORT(device->createComputePipelineState( + programB.pipelineDesc, + programB.pipelineState.writeRef())); + + float initialData[] = {1.0f, 2.0f, 3.0f, 4.0f}; + Buffer inputBuffer; + createFloatBuffer(device, inputBuffer, false, initialData, 4); + + Buffer intermediateBuffer; + createFloatBuffer(device, intermediateBuffer, true, nullptr, 4); + + Buffer outputBuffer; + createFloatBuffer(device, outputBuffer, true, nullptr, 4); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - outBuffer = {}; - IBufferResource::Desc& bufferDesc = outBuffer.desc; - bufferDesc.sizeInBytes = elementCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.defaultState = unorderedAccess ? ResourceState::UnorderedAccess : ResourceState::ShaderResource; - bufferDesc.memoryType = MemoryType::DeviceLocal; - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::CopyDestination, - ResourceState::CopySource); - if (unorderedAccess) bufferDesc.allowedStates.add(ResourceState::UnorderedAccess); - - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - outBuffer.buffer.writeRef())); - - IResourceView::Desc viewDesc = {}; - viewDesc.type = unorderedAccess ? IResourceView::Type::UnorderedAccess : IResourceView::Type::ShaderResource; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT(device->createBufferView( - outBuffer.buffer, nullptr, viewDesc, outBuffer.view.writeRef())); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + auto resourceEncoder = commandBuffer->encodeResourceCommands(); + + // Write inputBuffer data to intermediateBuffer + auto rootObjectA = encoder->bindPipeline(programA.pipelineState); + ShaderCursor entryPointCursorA(rootObjectA->getEntryPoint(0)); + entryPointCursorA.getPath("inBuffer").setResource(inputBuffer.view); + entryPointCursorA.getPath("outBuffer").setResource(intermediateBuffer.view); + + encoder->dispatchCompute(1, 1, 1); + + // Insert barrier to ensure writes to intermediateBuffer are complete before the next shader + // starts executing + auto bufferPtr = intermediateBuffer.buffer.get(); + resourceEncoder->bufferBarrier( + 1, + &bufferPtr, + ResourceState::UnorderedAccess, + ResourceState::ShaderResource); + resourceEncoder->endEncoding(); + + // Write intermediateBuffer to outputBuffer + auto rootObjectB = encoder->bindPipeline(programB.pipelineState); + ShaderCursor entryPointCursorB(rootObjectB->getEntryPoint(0)); + entryPointCursorB.getPath("inBuffer").setResource(intermediateBuffer.view); + entryPointCursorB.getPath("outBuffer").setResource(outputBuffer.view); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - void barrierTestImpl(IDevice* device, UnitTestContext* context) + compareComputeResult( + device, + outputBuffer.buffer, + Slang::makeArray<float>(11.0f, 12.0f, 13.0f, 14.0f)); +} + +void barrierTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +{ + if ((api & context->enabledApis) == 0) { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT(device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - Shader programA; - Shader programB; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, programA.program, "buffer-barrier-test", "computeA", programA.reflection)); - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, programB.program, "buffer-barrier-test", "computeB", programB.reflection)); - programA.pipelineDesc.program = programA.program.get(); - programB.pipelineDesc.program = programB.program.get(); - GFX_CHECK_CALL_ABORT(device->createComputePipelineState(programA.pipelineDesc, programA.pipelineState.writeRef())); - GFX_CHECK_CALL_ABORT(device->createComputePipelineState(programB.pipelineDesc, programB.pipelineState.writeRef())); - - float initialData[] = { 1.0f, 2.0f, 3.0f, 4.0f }; - Buffer inputBuffer; - createFloatBuffer(device, inputBuffer, false, initialData, 4); - - Buffer intermediateBuffer; - createFloatBuffer(device, intermediateBuffer, true, nullptr, 4); - - Buffer outputBuffer; - createFloatBuffer(device, outputBuffer, true, nullptr, 4); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - auto resourceEncoder = commandBuffer->encodeResourceCommands(); - - // Write inputBuffer data to intermediateBuffer - auto rootObjectA = encoder->bindPipeline(programA.pipelineState); - ShaderCursor entryPointCursorA(rootObjectA->getEntryPoint(0)); - entryPointCursorA.getPath("inBuffer").setResource(inputBuffer.view); - entryPointCursorA.getPath("outBuffer").setResource(intermediateBuffer.view); - - encoder->dispatchCompute(1, 1, 1); - - // Insert barrier to ensure writes to intermediateBuffer are complete before the next shader starts executing - auto bufferPtr = intermediateBuffer.buffer.get(); - resourceEncoder->bufferBarrier(1, &bufferPtr, ResourceState::UnorderedAccess, ResourceState::ShaderResource); - resourceEncoder->endEncoding(); - - // Write intermediateBuffer to outputBuffer - auto rootObjectB = encoder->bindPipeline(programB.pipelineState); - ShaderCursor entryPointCursorB(rootObjectB->getEntryPoint(0)); - entryPointCursorB.getPath("inBuffer").setResource(intermediateBuffer.view); - entryPointCursorB.getPath("outBuffer").setResource(outputBuffer.view); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - outputBuffer.buffer, - Slang::makeArray<float>(11.0f, 12.0f, 13.0f, 14.0f)); + SLANG_IGNORE_TEST } - - void barrierTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) + Slang::ComPtr<IDevice> device; + IDevice::Desc deviceDesc = {}; + switch (api) { - if ((api & context->enabledApis) == 0) - { - SLANG_IGNORE_TEST - } - Slang::ComPtr<IDevice> device; - IDevice::Desc deviceDesc = {}; - switch (api) - { - case Slang::RenderApiFlag::D3D12: - deviceDesc.deviceType = gfx::DeviceType::DirectX12; - break; - case Slang::RenderApiFlag::Vulkan: - deviceDesc.deviceType = gfx::DeviceType::Vulkan; - break; - default: - SLANG_IGNORE_TEST - } - deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; - const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" }; - deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); - deviceDesc.slang.searchPaths = searchPaths; - auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); - if (SLANG_FAILED(createDeviceResult)) - { - SLANG_IGNORE_TEST - } - - barrierTestImpl(device, context); + case Slang::RenderApiFlag::D3D12: deviceDesc.deviceType = gfx::DeviceType::DirectX12; break; + case Slang::RenderApiFlag::Vulkan: deviceDesc.deviceType = gfx::DeviceType::Vulkan; break; + default: SLANG_IGNORE_TEST } - - SLANG_UNIT_TEST(bufferBarrierVulkan) + deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; + const char* searchPaths[] = {"", "../../tools/gfx-unit-test", "tools/gfx-unit-test"}; + deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); + deviceDesc.slang.searchPaths = searchPaths; + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); + if (SLANG_FAILED(createDeviceResult)) { - barrierTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); + SLANG_IGNORE_TEST } + barrierTestImpl(device, context); } + +SLANG_UNIT_TEST(bufferBarrierVulkan) +{ + barrierTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/clear-texture-test.cpp b/tools/gfx-unit-test/clear-texture-test.cpp index 4ad82f313..ed9d12f0d 100644 --- a/tools/gfx-unit-test/clear-texture-test.cpp +++ b/tools/gfx-unit-test/clear-texture-test.cpp @@ -1,89 +1,92 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace Slang; using namespace gfx; namespace gfx_test { - void clearTextureTestImpl(IDevice* device, UnitTestContext* context) - { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); +void clearTextureTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - ITextureResource::Desc srcTexDesc = {}; - srcTexDesc.type = IResource::Type::Texture2D; - srcTexDesc.numMipLevels = 1; - srcTexDesc.arraySize = 1; - srcTexDesc.size.width = 4; - srcTexDesc.size.height = 4; - srcTexDesc.size.depth = 1; - srcTexDesc.defaultState = ResourceState::RenderTarget; - srcTexDesc.allowedStates = ResourceStateSet( - ResourceState::RenderTarget, - ResourceState::CopySource, - ResourceState::CopyDestination); - srcTexDesc.format = Format::R32G32B32A32_FLOAT; + ITextureResource::Desc srcTexDesc = {}; + srcTexDesc.type = IResource::Type::Texture2D; + srcTexDesc.numMipLevels = 1; + srcTexDesc.arraySize = 1; + srcTexDesc.size.width = 4; + srcTexDesc.size.height = 4; + srcTexDesc.size.depth = 1; + srcTexDesc.defaultState = ResourceState::RenderTarget; + srcTexDesc.allowedStates = ResourceStateSet( + ResourceState::RenderTarget, + ResourceState::CopySource, + ResourceState::CopyDestination); + srcTexDesc.format = Format::R32G32B32A32_FLOAT; - Slang::ComPtr<ITextureResource> srcTexture; - GFX_CHECK_CALL_ABORT(device->createTextureResource( - srcTexDesc, nullptr, srcTexture.writeRef())); + Slang::ComPtr<ITextureResource> srcTexture; + GFX_CHECK_CALL_ABORT(device->createTextureResource(srcTexDesc, nullptr, srcTexture.writeRef())); - Slang::ComPtr<IResourceView> rtv; - IResourceView::Desc rtvDesc = {}; - rtvDesc.type = IResourceView::Type::RenderTarget; - rtvDesc.format = Format::R32G32B32A32_FLOAT; - rtvDesc.renderTarget.shape = IResource::Type::Texture2D; - rtvDesc.subresourceRange.layerCount = 1; - rtvDesc.subresourceRange.mipLevelCount = 1; - rtv = device->createTextureView(srcTexture, rtvDesc); + Slang::ComPtr<IResourceView> rtv; + IResourceView::Desc rtvDesc = {}; + rtvDesc.type = IResourceView::Type::RenderTarget; + rtvDesc.format = Format::R32G32B32A32_FLOAT; + rtvDesc.renderTarget.shape = IResource::Type::Texture2D; + rtvDesc.subresourceRange.layerCount = 1; + rtvDesc.subresourceRange.mipLevelCount = 1; + rtv = device->createTextureView(srcTexture, rtvDesc); - { - ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; - auto queue = device->createCommandQueue(queueDesc); + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - auto resourceEncoder = commandBuffer->encodeResourceCommands(); - ClearValue clearValue = {}; - clearValue.color.floatValues[0] = 0.5f; - clearValue.color.floatValues[1] = 1.0f; - clearValue.color.floatValues[2] = 0.2f; - clearValue.color.floatValues[3] = 0.1f; - resourceEncoder->clearResourceView(rtv, &clearValue, ClearResourceViewFlags::FloatClearValues); - resourceEncoder->textureBarrier( - srcTexture, ResourceState::RenderTarget, ResourceState::CopySource); - resourceEncoder->endEncoding(); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto resourceEncoder = commandBuffer->encodeResourceCommands(); + ClearValue clearValue = {}; + clearValue.color.floatValues[0] = 0.5f; + clearValue.color.floatValues[1] = 1.0f; + clearValue.color.floatValues[2] = 0.2f; + clearValue.color.floatValues[3] = 0.1f; + resourceEncoder->clearResourceView( + rtv, + &clearValue, + ClearResourceViewFlags::FloatClearValues); + resourceEncoder->textureBarrier( + srcTexture, + ResourceState::RenderTarget, + ResourceState::CopySource); + resourceEncoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); + queue->waitOnHost(); - Slang::ComPtr<ISlangBlob> blob; - size_t rowPitch, pixelSize; - device->readTextureResource( - srcTexture, - ResourceState::CopySource, - blob.writeRef(), - &rowPitch, - &pixelSize); - float* data = (float*)blob->getBufferPointer(); - for (int i = 0; i < 4; i++) - { - SLANG_CHECK(data[i] == clearValue.color.floatValues[i]); - } + Slang::ComPtr<ISlangBlob> blob; + size_t rowPitch, pixelSize; + device->readTextureResource( + srcTexture, + ResourceState::CopySource, + blob.writeRef(), + &rowPitch, + &pixelSize); + float* data = (float*)blob->getBufferPointer(); + for (int i = 0; i < 4; i++) + { + SLANG_CHECK(data[i] == clearValue.color.floatValues[i]); } } +} - SLANG_UNIT_TEST(clearTextureTestVulkan) - { - runTestImpl(clearTextureTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(clearTextureTestVulkan) +{ + runTestImpl(clearTextureTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/compute-smoke.cpp b/tools/gfx-unit-test/compute-smoke.cpp index 5e14a2e00..da8357591 100644 --- a/tools/gfx-unit-test/compute-smoke.cpp +++ b/tools/gfx-unit-test/compute-smoke.cpp @@ -1,115 +1,115 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void computeSmokeTestImpl(IDevice* device, UnitTestContext* context) +void computeSmokeTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT( + loadComputeProgram(device, shaderProgram, "compute-smoke", "computeMain", slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "compute-smoke", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - slang::TypeReflection* addTransformerType = - slangReflection->findTypeByName("AddTransformer"); - - // Now we can use this type to create a shader object that can be bound to the root object. - ComPtr<IShaderObject> transformer; - GFX_CHECK_CALL_ABORT(device->createShaderObject( - addTransformerType, ShaderObjectContainerType::None, transformer.writeRef())); - // Set the `c` field of the `AddTransformer`. - float c = 1.0f; - ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); - - // Bind the previously created transformer object to root object. - entryPointCursor.getPath("transformer").setObject(transformer); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(11.0f, 12.0f, 13.0f, 14.0f)); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + slang::TypeReflection* addTransformerType = + slangReflection->findTypeByName("AddTransformer"); + + // Now we can use this type to create a shader object that can be bound to the root object. + ComPtr<IShaderObject> transformer; + GFX_CHECK_CALL_ABORT(device->createShaderObject( + addTransformerType, + ShaderObjectContainerType::None, + transformer.writeRef())); + // Set the `c` field of the `AddTransformer`. + float c = 1.0f; + ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + // Bind the previously created transformer object to root object. + entryPointCursor.getPath("transformer").setObject(transformer); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(computeSmokeD3D12) - { - runTestImpl(computeSmokeTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + compareComputeResult( + device, + numbersBuffer, + Slang::makeArray<float>(11.0f, 12.0f, 13.0f, 14.0f)); +} - SLANG_UNIT_TEST(computeSmokeD3D11) - { - runTestImpl(computeSmokeTestImpl, unitTestContext, Slang::RenderApiFlag::D3D11); - } +SLANG_UNIT_TEST(computeSmokeD3D12) +{ + runTestImpl(computeSmokeTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} - SLANG_UNIT_TEST(computeSmokeVulkan) - { - runTestImpl(computeSmokeTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(computeSmokeD3D11) +{ + runTestImpl(computeSmokeTestImpl, unitTestContext, Slang::RenderApiFlag::D3D11); +} +SLANG_UNIT_TEST(computeSmokeVulkan) +{ + runTestImpl(computeSmokeTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/compute-trivial.cpp b/tools/gfx-unit-test/compute-trivial.cpp index 5674dd1a7..341593d04 100644 --- a/tools/gfx-unit-test/compute-trivial.cpp +++ b/tools/gfx-unit-test/compute-trivial.cpp @@ -1,99 +1,98 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void computeTrivialTestImpl(IDevice* device, UnitTestContext* context) +void computeTrivialTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "compute-trivial", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "compute-trivial", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - // Bind buffer view to the entry point. - ShaderCursor(rootObject).getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); - } + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - SLANG_UNIT_TEST(computeTrivialD3D12) - { - runTestImpl(computeTrivialTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - SLANG_UNIT_TEST(computeTrivialD3D11) - { - runTestImpl(computeTrivialTestImpl, unitTestContext, Slang::RenderApiFlag::D3D11); - } + auto rootObject = encoder->bindPipeline(pipelineState); - SLANG_UNIT_TEST(computeTrivialVulkan) - { - runTestImpl(computeTrivialTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + // Bind buffer view to the entry point. + ShaderCursor(rootObject).getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); +} + +SLANG_UNIT_TEST(computeTrivialD3D12) +{ + runTestImpl(computeTrivialTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(computeTrivialD3D11) +{ + runTestImpl(computeTrivialTestImpl, unitTestContext, Slang::RenderApiFlag::D3D11); +} + +SLANG_UNIT_TEST(computeTrivialVulkan) +{ + runTestImpl(computeTrivialTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/copy-texture-tests.cpp b/tools/gfx-unit-test/copy-texture-tests.cpp index 68ca193ae..babe0bcf1 100644 --- a/tools/gfx-unit-test/copy-texture-tests.cpp +++ b/tools/gfx-unit-test/copy-texture-tests.cpp @@ -1,10 +1,9 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" -#include "gfx-test-util.h" #include "gfx-test-texture-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "gfx-test-util.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" #if SLANG_WINDOWS_FAMILY #include <d3d12.h> @@ -15,810 +14,943 @@ using namespace gfx; namespace gfx_test { - struct TextureToTextureCopyInfo - { - SubresourceRange srcSubresource; - SubresourceRange dstSubresource; - ITextureResource::Extents extent; - ITextureResource::Offset3D srcOffset; - ITextureResource::Offset3D dstOffset; - }; - - struct TextureToBufferCopyInfo - { - SubresourceRange srcSubresource; - ITextureResource::Extents extent; - ITextureResource::Offset3D textureOffset; - Offset bufferOffset; - Offset bufferSize; - }; - - struct BaseCopyTextureTest +struct TextureToTextureCopyInfo +{ + SubresourceRange srcSubresource; + SubresourceRange dstSubresource; + ITextureResource::Extents extent; + ITextureResource::Offset3D srcOffset; + ITextureResource::Offset3D dstOffset; +}; + +struct TextureToBufferCopyInfo +{ + SubresourceRange srcSubresource; + ITextureResource::Extents extent; + ITextureResource::Offset3D textureOffset; + Offset bufferOffset; + Offset bufferSize; +}; + +struct BaseCopyTextureTest +{ + IDevice* device; + UnitTestContext* context; + + Size alignedRowStride; + + RefPtr<TextureInfo> srcTextureInfo; + RefPtr<TextureInfo> dstTextureInfo; + TextureToTextureCopyInfo texCopyInfo; + TextureToBufferCopyInfo bufferCopyInfo; + + ComPtr<ITextureResource> srcTexture; + ComPtr<ITextureResource> dstTexture; + ComPtr<IBufferResource> resultsBuffer; + + RefPtr<ValidationTextureFormatBase> validationFormat; + + void init( + IDevice* device, + UnitTestContext* context, + Format format, + RefPtr<ValidationTextureFormatBase> validationFormat, + ITextureResource::Type type) { - IDevice* device; - UnitTestContext* context; - - Size alignedRowStride; - - RefPtr<TextureInfo> srcTextureInfo; - RefPtr<TextureInfo> dstTextureInfo; - TextureToTextureCopyInfo texCopyInfo; - TextureToBufferCopyInfo bufferCopyInfo; - - ComPtr<ITextureResource> srcTexture; - ComPtr<ITextureResource> dstTexture; - ComPtr<IBufferResource> resultsBuffer; - - RefPtr<ValidationTextureFormatBase> validationFormat; - - void init( - IDevice* device, - UnitTestContext* context, - Format format, - RefPtr<ValidationTextureFormatBase> validationFormat, - ITextureResource::Type type) - { - this->device = device; - this->context = context; - this->validationFormat = validationFormat; + this->device = device; + this->context = context; + this->validationFormat = validationFormat; - this->srcTextureInfo = new TextureInfo(); - this->srcTextureInfo->format = format; - this->srcTextureInfo->textureType = type; + this->srcTextureInfo = new TextureInfo(); + this->srcTextureInfo->format = format; + this->srcTextureInfo->textureType = type; - this->dstTextureInfo = new TextureInfo(); - this->dstTextureInfo->format = format; - this->dstTextureInfo->textureType = type; - } + this->dstTextureInfo = new TextureInfo(); + this->dstTextureInfo->format = format; + this->dstTextureInfo->textureType = type; + } - void createRequiredResources() + void createRequiredResources() + { + ITextureResource::Desc srcTexDesc = {}; + srcTexDesc.type = srcTextureInfo->textureType; + srcTexDesc.numMipLevels = srcTextureInfo->mipLevelCount; + srcTexDesc.arraySize = srcTextureInfo->arrayLayerCount; + srcTexDesc.size = srcTextureInfo->extents; + srcTexDesc.defaultState = ResourceState::ShaderResource; + srcTexDesc.allowedStates = + ResourceStateSet(ResourceState::ShaderResource, ResourceState::CopySource); + if (srcTextureInfo->format == Format::D32_FLOAT || + srcTextureInfo->format == Format::D16_UNORM) { - ITextureResource::Desc srcTexDesc = {}; - srcTexDesc.type = srcTextureInfo->textureType; - srcTexDesc.numMipLevels = srcTextureInfo->mipLevelCount; - srcTexDesc.arraySize = srcTextureInfo->arrayLayerCount; - srcTexDesc.size = srcTextureInfo->extents; - srcTexDesc.defaultState = ResourceState::ShaderResource; - srcTexDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::CopySource); - if (srcTextureInfo->format == Format::D32_FLOAT || srcTextureInfo->format == Format::D16_UNORM) - { - srcTexDesc.allowedStates.add(ResourceState::DepthWrite); - srcTexDesc.allowedStates.add(ResourceState::DepthRead); - } - srcTexDesc.format = srcTextureInfo->format; - - GFX_CHECK_CALL_ABORT(device->createTextureResource( - srcTexDesc, - srcTextureInfo->subresourceDatas.getBuffer(), - srcTexture.writeRef())); - - ITextureResource::Desc dstTexDesc = {}; - dstTexDesc.type = dstTextureInfo->textureType; - dstTexDesc.numMipLevels = dstTextureInfo->mipLevelCount; - dstTexDesc.arraySize = dstTextureInfo->arrayLayerCount; - dstTexDesc.size = dstTextureInfo->extents; - dstTexDesc.defaultState = ResourceState::CopyDestination; - dstTexDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::CopyDestination, - ResourceState::CopySource); - if (dstTextureInfo->format == Format::D32_FLOAT || dstTextureInfo->format == Format::D16_UNORM) - { - dstTexDesc.allowedStates.add(ResourceState::DepthWrite); - dstTexDesc.allowedStates.add(ResourceState::DepthRead); - } - dstTexDesc.format = dstTextureInfo->format; - - GFX_CHECK_CALL_ABORT(device->createTextureResource( - dstTexDesc, - dstTextureInfo->subresourceDatas.getBuffer(), - dstTexture.writeRef())); - - auto bufferCopyExtents = bufferCopyInfo.extent; - auto texelSize = getTexelSize(dstTextureInfo->format); - size_t alignment; - device->getTextureRowAlignment(&alignment); - alignedRowStride = (bufferCopyExtents.width * texelSize + alignment - 1) & ~(alignment - 1); - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = bufferCopyExtents.height * bufferCopyExtents.depth * alignedRowStride; - bufferDesc.format = Format::Unknown; - bufferDesc.elementSize = 0; - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::CopyDestination; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - nullptr, - resultsBuffer.writeRef())); - - bufferCopyInfo.bufferSize = bufferDesc.sizeInBytes; + srcTexDesc.allowedStates.add(ResourceState::DepthWrite); + srcTexDesc.allowedStates.add(ResourceState::DepthRead); } - - void submitGPUWork() + srcTexDesc.format = srcTextureInfo->format; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + srcTexDesc, + srcTextureInfo->subresourceDatas.getBuffer(), + srcTexture.writeRef())); + + ITextureResource::Desc dstTexDesc = {}; + dstTexDesc.type = dstTextureInfo->textureType; + dstTexDesc.numMipLevels = dstTextureInfo->mipLevelCount; + dstTexDesc.arraySize = dstTextureInfo->arrayLayerCount; + dstTexDesc.size = dstTextureInfo->extents; + dstTexDesc.defaultState = ResourceState::CopyDestination; + dstTexDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::CopyDestination, + ResourceState::CopySource); + if (dstTextureInfo->format == Format::D32_FLOAT || + dstTextureInfo->format == Format::D16_UNORM) { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeResourceCommands(); - - encoder->textureSubresourceBarrier(srcTexture, texCopyInfo.srcSubresource, ResourceState::ShaderResource, ResourceState::CopySource); - encoder->copyTexture( - dstTexture, - ResourceState::CopyDestination, - texCopyInfo.dstSubresource, - texCopyInfo.dstOffset, - srcTexture, - ResourceState::CopySource, - texCopyInfo.srcSubresource, - texCopyInfo.srcOffset, - texCopyInfo.extent); - - encoder->textureSubresourceBarrier(dstTexture, bufferCopyInfo.srcSubresource, ResourceState::CopyDestination, ResourceState::CopySource); - encoder->copyTextureToBuffer( - resultsBuffer, - bufferCopyInfo.bufferOffset, - bufferCopyInfo.bufferSize, - alignedRowStride, - dstTexture, - ResourceState::CopySource, - bufferCopyInfo.srcSubresource, - bufferCopyInfo.textureOffset, - bufferCopyInfo.extent); - - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); + dstTexDesc.allowedStates.add(ResourceState::DepthWrite); + dstTexDesc.allowedStates.add(ResourceState::DepthRead); } + dstTexDesc.format = dstTextureInfo->format; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + dstTexDesc, + dstTextureInfo->subresourceDatas.getBuffer(), + dstTexture.writeRef())); + + auto bufferCopyExtents = bufferCopyInfo.extent; + auto texelSize = getTexelSize(dstTextureInfo->format); + size_t alignment; + device->getTextureRowAlignment(&alignment); + alignedRowStride = (bufferCopyExtents.width * texelSize + alignment - 1) & ~(alignment - 1); + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = + bufferCopyExtents.height * bufferCopyExtents.depth * alignedRowStride; + bufferDesc.format = Format::Unknown; + bufferDesc.elementSize = 0; + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::CopyDestination; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, nullptr, resultsBuffer.writeRef())); + + bufferCopyInfo.bufferSize = bufferDesc.sizeInBytes; + } - bool isWithinCopyBounds(GfxIndex x, GfxIndex y, GfxIndex z) - { - auto copyExtents = texCopyInfo.extent; - auto copyOffset = texCopyInfo.dstOffset; - - auto xLowerBound = copyOffset.x; - auto xUpperBound = copyOffset.x + copyExtents.width; - auto yLowerBound = copyOffset.y; - auto yUpperBound = copyOffset.y + copyExtents.height; - auto zLowerBound = copyOffset.z; - auto zUpperBound = copyOffset.z + copyExtents.depth; - - if (x < xLowerBound || x >= xUpperBound || y < yLowerBound || y >= yUpperBound || z < zLowerBound || z >= zUpperBound) - return false; - else - return true; - } + void submitGPUWork() + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeResourceCommands(); + + encoder->textureSubresourceBarrier( + srcTexture, + texCopyInfo.srcSubresource, + ResourceState::ShaderResource, + ResourceState::CopySource); + encoder->copyTexture( + dstTexture, + ResourceState::CopyDestination, + texCopyInfo.dstSubresource, + texCopyInfo.dstOffset, + srcTexture, + ResourceState::CopySource, + texCopyInfo.srcSubresource, + texCopyInfo.srcOffset, + texCopyInfo.extent); + + encoder->textureSubresourceBarrier( + dstTexture, + bufferCopyInfo.srcSubresource, + ResourceState::CopyDestination, + ResourceState::CopySource); + encoder->copyTextureToBuffer( + resultsBuffer, + bufferCopyInfo.bufferOffset, + bufferCopyInfo.bufferSize, + alignedRowStride, + dstTexture, + ResourceState::CopySource, + bufferCopyInfo.srcSubresource, + bufferCopyInfo.textureOffset, + bufferCopyInfo.extent); + + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - void validateTestResults( - ValidationTextureData actual, - ValidationTextureData expectedCopied, - ValidationTextureData expectedOriginal) - { - auto actualExtents = actual.extents; - auto copyExtent = texCopyInfo.extent; - auto srcTexOffset = texCopyInfo.srcOffset; - auto dstTexOffset = texCopyInfo.dstOffset; + bool isWithinCopyBounds(GfxIndex x, GfxIndex y, GfxIndex z) + { + auto copyExtents = texCopyInfo.extent; + auto copyOffset = texCopyInfo.dstOffset; + + auto xLowerBound = copyOffset.x; + auto xUpperBound = copyOffset.x + copyExtents.width; + auto yLowerBound = copyOffset.y; + auto yUpperBound = copyOffset.y + copyExtents.height; + auto zLowerBound = copyOffset.z; + auto zUpperBound = copyOffset.z + copyExtents.depth; + + if (x < xLowerBound || x >= xUpperBound || y < yLowerBound || y >= yUpperBound || + z < zLowerBound || z >= zUpperBound) + return false; + else + return true; + } + + void validateTestResults( + ValidationTextureData actual, + ValidationTextureData expectedCopied, + ValidationTextureData expectedOriginal) + { + auto actualExtents = actual.extents; + auto copyExtent = texCopyInfo.extent; + auto srcTexOffset = texCopyInfo.srcOffset; + auto dstTexOffset = texCopyInfo.dstOffset; - for (GfxIndex x = 0; x < actualExtents.width; ++x) + for (GfxIndex x = 0; x < actualExtents.width; ++x) + { + for (GfxIndex y = 0; y < actualExtents.height; ++y) { - for (GfxIndex y = 0; y < actualExtents.height; ++y) + for (GfxIndex z = 0; z < actualExtents.depth; ++z) { - for (GfxIndex z = 0; z < actualExtents.depth; ++z) + auto actualBlock = actual.getBlockAt(x, y, z); + if (isWithinCopyBounds(x, y, z)) + { + // Block is located within the bounds of the source texture + auto xSource = x + srcTexOffset.x - dstTexOffset.x; + auto ySource = y + srcTexOffset.y - dstTexOffset.y; + auto zSource = z + srcTexOffset.z - dstTexOffset.z; + auto expectedBlock = expectedCopied.getBlockAt(xSource, ySource, zSource); + validationFormat->validateBlocksEqual(actualBlock, expectedBlock); + } + else { - auto actualBlock = actual.getBlockAt(x, y, z); - if (isWithinCopyBounds(x, y, z)) - { - // Block is located within the bounds of the source texture - auto xSource = x + srcTexOffset.x - dstTexOffset.x; - auto ySource = y + srcTexOffset.y - dstTexOffset.y; - auto zSource = z + srcTexOffset.z - dstTexOffset.z; - auto expectedBlock = expectedCopied.getBlockAt(xSource, ySource, zSource); - validationFormat->validateBlocksEqual(actualBlock, expectedBlock); - } - else - { - // Block is located outside the bounds of the source texture and should be compared - // against known expected values for the destination texture. - auto expectedBlock = expectedOriginal.getBlockAt(x, y, z); - validationFormat->validateBlocksEqual(actualBlock, expectedBlock); - } + // Block is located outside the bounds of the source texture and should be + // compared against known expected values for the destination texture. + auto expectedBlock = expectedOriginal.getBlockAt(x, y, z); + validationFormat->validateBlocksEqual(actualBlock, expectedBlock); } } } } + } - void checkTestResults(ITextureResource::Extents srcMipExtent, const void* expectedCopiedData, const void* expectedOriginalData) + void checkTestResults( + ITextureResource::Extents srcMipExtent, + const void* expectedCopiedData, + const void* expectedOriginalData) + { + ComPtr<ISlangBlob> resultBlob; + GFX_CHECK_CALL_ABORT(device->readBufferResource( + resultsBuffer, + 0, + bufferCopyInfo.bufferSize, + resultBlob.writeRef())); + auto results = resultBlob->getBufferPointer(); + + ValidationTextureData actual; + actual.extents = bufferCopyInfo.extent; + actual.textureData = results; + actual.strides.x = getTexelSize(dstTextureInfo->format); + actual.strides.y = alignedRowStride; + actual.strides.z = actual.extents.height * actual.strides.y; + + ValidationTextureData expectedCopied; + expectedCopied.extents = srcMipExtent; + expectedCopied.textureData = expectedCopiedData; + expectedCopied.strides.x = getTexelSize(srcTextureInfo->format); + expectedCopied.strides.y = expectedCopied.extents.width * expectedCopied.strides.x; + expectedCopied.strides.z = expectedCopied.extents.height * expectedCopied.strides.y; + + ValidationTextureData expectedOriginal; + if (expectedOriginalData) { - ComPtr<ISlangBlob> resultBlob; - GFX_CHECK_CALL_ABORT(device->readBufferResource(resultsBuffer, 0, bufferCopyInfo.bufferSize, resultBlob.writeRef())); - auto results = resultBlob->getBufferPointer(); - - ValidationTextureData actual; - actual.extents = bufferCopyInfo.extent; - actual.textureData = results; - actual.strides.x = getTexelSize(dstTextureInfo->format); - actual.strides.y = alignedRowStride; - actual.strides.z = actual.extents.height * actual.strides.y; - - ValidationTextureData expectedCopied; - expectedCopied.extents = srcMipExtent; - expectedCopied.textureData = expectedCopiedData; - expectedCopied.strides.x = getTexelSize(srcTextureInfo->format); - expectedCopied.strides.y = expectedCopied.extents.width * expectedCopied.strides.x; - expectedCopied.strides.z = expectedCopied.extents.height * expectedCopied.strides.y; - - ValidationTextureData expectedOriginal; - if (expectedOriginalData) - { - expectedOriginal.extents = bufferCopyInfo.extent; - expectedOriginal.textureData = expectedOriginalData; - expectedOriginal.strides.x = getTexelSize(dstTextureInfo->format); - expectedOriginal.strides.y = expectedOriginal.extents.width * expectedOriginal.strides.x; - expectedOriginal.strides.z = expectedOriginal.extents.height * expectedOriginal.strides.y; - } - - validateTestResults(actual, expectedCopied, expectedOriginal); + expectedOriginal.extents = bufferCopyInfo.extent; + expectedOriginal.textureData = expectedOriginalData; + expectedOriginal.strides.x = getTexelSize(dstTextureInfo->format); + expectedOriginal.strides.y = + expectedOriginal.extents.width * expectedOriginal.strides.x; + expectedOriginal.strides.z = + expectedOriginal.extents.height * expectedOriginal.strides.y; } - }; - struct SimpleCopyTexture : BaseCopyTextureTest + validateTestResults(actual, expectedCopied, expectedOriginal); + } +}; + +struct SimpleCopyTexture : BaseCopyTextureTest +{ + void run() { - void run() - { - auto textureType = srcTextureInfo->textureType; - auto format = srcTextureInfo->format; - - srcTextureInfo->extents.width = 4; - srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; - srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - srcTextureInfo->mipLevelCount = 1; - srcTextureInfo->arrayLayerCount = 1; - - dstTextureInfo = srcTextureInfo; - - generateTextureData(srcTextureInfo, validationFormat); - - SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = getTextureAspect(format); - srcSubresource.mipLevel = 0; - srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = 0; - srcSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = getTextureAspect(format); - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - texCopyInfo.srcSubresource = srcSubresource; - texCopyInfo.dstSubresource = dstSubresource; - texCopyInfo.extent = srcTextureInfo->extents; - texCopyInfo.srcOffset = { 0, 0, 0 }; - texCopyInfo.dstOffset = { 0, 0, 0 }; - - bufferCopyInfo.srcSubresource = dstSubresource; - bufferCopyInfo.extent = dstTextureInfo->extents; - bufferCopyInfo.textureOffset = { 0, 0, 0 }; - bufferCopyInfo.bufferOffset = 0; - - createRequiredResources(); - submitGPUWork(); - - auto subresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcTextureInfo->mipLevelCount, srcSubresource.baseArrayLayer); - auto expectedData = srcTextureInfo->subresourceDatas[subresourceIndex]; - checkTestResults(srcTextureInfo->extents, expectedData.data, nullptr); - } - }; + auto textureType = srcTextureInfo->textureType; + auto format = srcTextureInfo->format; + + srcTextureInfo->extents.width = 4; + srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + srcTextureInfo->mipLevelCount = 1; + srcTextureInfo->arrayLayerCount = 1; + + dstTextureInfo = srcTextureInfo; + + generateTextureData(srcTextureInfo, validationFormat); + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(format); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(format); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = srcTextureInfo->extents; + texCopyInfo.srcOffset = {0, 0, 0}; + texCopyInfo.dstOffset = {0, 0, 0}; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstTextureInfo->extents; + bufferCopyInfo.textureOffset = {0, 0, 0}; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto subresourceIndex = getSubresourceIndex( + srcSubresource.mipLevel, + srcTextureInfo->mipLevelCount, + srcSubresource.baseArrayLayer); + auto expectedData = srcTextureInfo->subresourceDatas[subresourceIndex]; + checkTestResults(srcTextureInfo->extents, expectedData.data, nullptr); + } +}; - struct CopyTextureSection : BaseCopyTextureTest +struct CopyTextureSection : BaseCopyTextureTest +{ + void run() { - void run() - { - auto textureType = srcTextureInfo->textureType; - auto format = srcTextureInfo->format; - - srcTextureInfo->extents.width = 4; - srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; - srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - srcTextureInfo->mipLevelCount = 2; - srcTextureInfo->arrayLayerCount = (textureType == ITextureResource::Type::Texture3D) ? 1 : 2; - - dstTextureInfo = srcTextureInfo; - - generateTextureData(srcTextureInfo, validationFormat); - - SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = getTextureAspect(format); - srcSubresource.mipLevel = 0; - srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = (textureType == ITextureResource::Type::Texture3D) ? 0 : 1; - srcSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = getTextureAspect(format); - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - texCopyInfo.srcSubresource = srcSubresource; - texCopyInfo.dstSubresource = dstSubresource; - texCopyInfo.extent = srcTextureInfo->extents; - texCopyInfo.srcOffset = { 0, 0, 0 }; - texCopyInfo.dstOffset = { 0, 0, 0 }; - - bufferCopyInfo.srcSubresource = dstSubresource; - bufferCopyInfo.extent = dstTextureInfo->extents; - bufferCopyInfo.textureOffset = { 0, 0, 0 }; - bufferCopyInfo.bufferOffset = 0; - - createRequiredResources(); - submitGPUWork(); - - auto subresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcTextureInfo->mipLevelCount, srcSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedData = srcTextureInfo->subresourceDatas[subresourceIndex]; - checkTestResults(srcTextureInfo->extents, expectedData.data, nullptr); - } - }; + auto textureType = srcTextureInfo->textureType; + auto format = srcTextureInfo->format; + + srcTextureInfo->extents.width = 4; + srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + srcTextureInfo->mipLevelCount = 2; + srcTextureInfo->arrayLayerCount = + (textureType == ITextureResource::Type::Texture3D) ? 1 : 2; + + dstTextureInfo = srcTextureInfo; + + generateTextureData(srcTextureInfo, validationFormat); + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(format); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = (textureType == ITextureResource::Type::Texture3D) ? 0 : 1; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(format); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = srcTextureInfo->extents; + texCopyInfo.srcOffset = {0, 0, 0}; + texCopyInfo.dstOffset = {0, 0, 0}; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstTextureInfo->extents; + bufferCopyInfo.textureOffset = {0, 0, 0}; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto subresourceIndex = getSubresourceIndex( + srcSubresource.mipLevel, + srcTextureInfo->mipLevelCount, + srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedData = + srcTextureInfo->subresourceDatas[subresourceIndex]; + checkTestResults(srcTextureInfo->extents, expectedData.data, nullptr); + } +}; - struct LargeSrcToSmallDst : BaseCopyTextureTest +struct LargeSrcToSmallDst : BaseCopyTextureTest +{ + void run() { - void run() - { - auto textureType = srcTextureInfo->textureType; - auto format = srcTextureInfo->format; - - srcTextureInfo->extents.width = 8; - srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; - srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - srcTextureInfo->mipLevelCount = 1; - srcTextureInfo->arrayLayerCount = 1; - - generateTextureData(srcTextureInfo, validationFormat); - - dstTextureInfo->extents.width = 4; - dstTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; - dstTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - dstTextureInfo->mipLevelCount = 1; - dstTextureInfo->arrayLayerCount = 1; - - SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = getTextureAspect(format); - srcSubresource.mipLevel = 0; - srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = 0; - srcSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = getTextureAspect(format); - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - texCopyInfo.srcSubresource = srcSubresource; - texCopyInfo.dstSubresource = dstSubresource; - texCopyInfo.extent = dstTextureInfo->extents; - texCopyInfo.srcOffset = { 0, 0, 0 }; - texCopyInfo.dstOffset = { 0, 0, 0 }; - - bufferCopyInfo.srcSubresource = dstSubresource; - bufferCopyInfo.extent = dstTextureInfo->extents; - bufferCopyInfo.textureOffset = { 0, 0, 0 }; - bufferCopyInfo.bufferOffset = 0; - - createRequiredResources(); - submitGPUWork(); - - auto subresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcTextureInfo->mipLevelCount, srcSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedData = srcTextureInfo->subresourceDatas[subresourceIndex]; - checkTestResults(srcTextureInfo->extents, expectedData.data, nullptr); - } - }; + auto textureType = srcTextureInfo->textureType; + auto format = srcTextureInfo->format; + + srcTextureInfo->extents.width = 8; + srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; + srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + srcTextureInfo->mipLevelCount = 1; + srcTextureInfo->arrayLayerCount = 1; + + generateTextureData(srcTextureInfo, validationFormat); + + dstTextureInfo->extents.width = 4; + dstTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + dstTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + dstTextureInfo->mipLevelCount = 1; + dstTextureInfo->arrayLayerCount = 1; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(format); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(format); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = dstTextureInfo->extents; + texCopyInfo.srcOffset = {0, 0, 0}; + texCopyInfo.dstOffset = {0, 0, 0}; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstTextureInfo->extents; + bufferCopyInfo.textureOffset = {0, 0, 0}; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto subresourceIndex = getSubresourceIndex( + srcSubresource.mipLevel, + srcTextureInfo->mipLevelCount, + srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedData = + srcTextureInfo->subresourceDatas[subresourceIndex]; + checkTestResults(srcTextureInfo->extents, expectedData.data, nullptr); + } +}; - struct SmallSrcToLargeDst : BaseCopyTextureTest +struct SmallSrcToLargeDst : BaseCopyTextureTest +{ + void run() { - void run() - { - auto textureType = srcTextureInfo->textureType; - auto format = srcTextureInfo->format; - - srcTextureInfo->extents.width = 4; - srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; - srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - srcTextureInfo->mipLevelCount = 1; - srcTextureInfo->arrayLayerCount = 1; - - generateTextureData(srcTextureInfo, validationFormat); - - dstTextureInfo->extents.width = 8; - dstTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; - dstTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - dstTextureInfo->mipLevelCount = 1; - dstTextureInfo->arrayLayerCount = 1; - - generateTextureData(dstTextureInfo, validationFormat); - - SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = getTextureAspect(format); - srcSubresource.mipLevel = 0; - srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = 0; - srcSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = getTextureAspect(format); - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - texCopyInfo.srcSubresource = srcSubresource; - texCopyInfo.dstSubresource = dstSubresource; - texCopyInfo.extent = srcTextureInfo->extents; - texCopyInfo.srcOffset = { 0, 0, 0 }; - texCopyInfo.dstOffset = { 0, 0, 0 }; - - bufferCopyInfo.srcSubresource = dstSubresource; - bufferCopyInfo.extent = dstTextureInfo->extents; - bufferCopyInfo.textureOffset = { 0, 0, 0 }; - bufferCopyInfo.bufferOffset = 0; - - createRequiredResources(); - submitGPUWork(); - - auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcTextureInfo->mipLevelCount, srcSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedCopiedData = srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; - auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, dstTextureInfo->mipLevelCount, dstSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedOriginalData = dstTextureInfo->subresourceDatas[originalSubresourceIndex]; - checkTestResults(srcTextureInfo->extents, expectedCopiedData.data, expectedOriginalData.data); - } - }; + auto textureType = srcTextureInfo->textureType; + auto format = srcTextureInfo->format; + + srcTextureInfo->extents.width = 4; + srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + srcTextureInfo->mipLevelCount = 1; + srcTextureInfo->arrayLayerCount = 1; + + generateTextureData(srcTextureInfo, validationFormat); + + dstTextureInfo->extents.width = 8; + dstTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; + dstTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + dstTextureInfo->mipLevelCount = 1; + dstTextureInfo->arrayLayerCount = 1; + + generateTextureData(dstTextureInfo, validationFormat); + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(format); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(format); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = srcTextureInfo->extents; + texCopyInfo.srcOffset = {0, 0, 0}; + texCopyInfo.dstOffset = {0, 0, 0}; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstTextureInfo->extents; + bufferCopyInfo.textureOffset = {0, 0, 0}; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto copiedSubresourceIndex = getSubresourceIndex( + srcSubresource.mipLevel, + srcTextureInfo->mipLevelCount, + srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedCopiedData = + srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; + auto originalSubresourceIndex = getSubresourceIndex( + dstSubresource.mipLevel, + dstTextureInfo->mipLevelCount, + dstSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedOriginalData = + dstTextureInfo->subresourceDatas[originalSubresourceIndex]; + checkTestResults( + srcTextureInfo->extents, + expectedCopiedData.data, + expectedOriginalData.data); + } +}; - struct CopyBetweenMips : BaseCopyTextureTest +struct CopyBetweenMips : BaseCopyTextureTest +{ + void run() { - void run() - { - auto textureType = srcTextureInfo->textureType; - auto format = srcTextureInfo->format; - - srcTextureInfo->extents.width = 16; - srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; - srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - srcTextureInfo->mipLevelCount = 4; - srcTextureInfo->arrayLayerCount = 1; - - generateTextureData(srcTextureInfo, validationFormat); - - dstTextureInfo->extents.width = 16; - dstTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; - dstTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - dstTextureInfo->mipLevelCount = 4; - dstTextureInfo->arrayLayerCount = 1; - - generateTextureData(dstTextureInfo, validationFormat); - - SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = getTextureAspect(format); - srcSubresource.mipLevel = 2; - srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = 0; - srcSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = getTextureAspect(format); - dstSubresource.mipLevel = 1; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcTextureInfo->mipLevelCount, srcSubresource.baseArrayLayer); - auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, dstTextureInfo->mipLevelCount, dstSubresource.baseArrayLayer); - - texCopyInfo.srcSubresource = srcSubresource; - texCopyInfo.dstSubresource = dstSubresource; - texCopyInfo.extent = srcTextureInfo->subresourceObjects[copiedSubresourceIndex]->extents; - texCopyInfo.srcOffset = { 0, 0, 0 }; - texCopyInfo.dstOffset = { 0, 0, 0 }; - - bufferCopyInfo.srcSubresource = dstSubresource; - bufferCopyInfo.extent = dstTextureInfo->subresourceObjects[originalSubresourceIndex]->extents; - bufferCopyInfo.textureOffset = { 0, 0, 0 }; - bufferCopyInfo.bufferOffset = 0; - - createRequiredResources(); - submitGPUWork(); - - ITextureResource::SubresourceData expectedCopiedData = srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; - ITextureResource::SubresourceData expectedOriginalData = dstTextureInfo->subresourceDatas[originalSubresourceIndex]; - auto srcMipExtent = srcTextureInfo->subresourceObjects[2]->extents; - checkTestResults(srcMipExtent, expectedCopiedData.data, expectedOriginalData.data); - } - }; + auto textureType = srcTextureInfo->textureType; + auto format = srcTextureInfo->format; + + srcTextureInfo->extents.width = 16; + srcTextureInfo->extents.height = + (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; + srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + srcTextureInfo->mipLevelCount = 4; + srcTextureInfo->arrayLayerCount = 1; + + generateTextureData(srcTextureInfo, validationFormat); + + dstTextureInfo->extents.width = 16; + dstTextureInfo->extents.height = + (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; + dstTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + dstTextureInfo->mipLevelCount = 4; + dstTextureInfo->arrayLayerCount = 1; + + generateTextureData(dstTextureInfo, validationFormat); + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(format); + srcSubresource.mipLevel = 2; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(format); + dstSubresource.mipLevel = 1; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + auto copiedSubresourceIndex = getSubresourceIndex( + srcSubresource.mipLevel, + srcTextureInfo->mipLevelCount, + srcSubresource.baseArrayLayer); + auto originalSubresourceIndex = getSubresourceIndex( + dstSubresource.mipLevel, + dstTextureInfo->mipLevelCount, + dstSubresource.baseArrayLayer); + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = srcTextureInfo->subresourceObjects[copiedSubresourceIndex]->extents; + texCopyInfo.srcOffset = {0, 0, 0}; + texCopyInfo.dstOffset = {0, 0, 0}; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = + dstTextureInfo->subresourceObjects[originalSubresourceIndex]->extents; + bufferCopyInfo.textureOffset = {0, 0, 0}; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + ITextureResource::SubresourceData expectedCopiedData = + srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; + ITextureResource::SubresourceData expectedOriginalData = + dstTextureInfo->subresourceDatas[originalSubresourceIndex]; + auto srcMipExtent = srcTextureInfo->subresourceObjects[2]->extents; + checkTestResults(srcMipExtent, expectedCopiedData.data, expectedOriginalData.data); + } +}; - struct CopyBetweenLayers : BaseCopyTextureTest +struct CopyBetweenLayers : BaseCopyTextureTest +{ + void run() { - void run() - { - auto textureType = srcTextureInfo->textureType; - auto format = srcTextureInfo->format; - - srcTextureInfo->extents.width = 4; - srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; - srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - srcTextureInfo->mipLevelCount = 1; - srcTextureInfo->arrayLayerCount = (textureType == ITextureResource::Type::Texture3D) ? 1 : 2; - - generateTextureData(srcTextureInfo, validationFormat); - dstTextureInfo = srcTextureInfo; - - SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = getTextureAspect(format); - srcSubresource.mipLevel = 0; - srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = 0; - srcSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = getTextureAspect(format); - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = (textureType == ITextureResource::Type::Texture3D) ? 0 : 1; - dstSubresource.layerCount = 1; - - texCopyInfo.srcSubresource = srcSubresource; - texCopyInfo.dstSubresource = dstSubresource; - texCopyInfo.extent = srcTextureInfo->extents; - texCopyInfo.srcOffset = { 0, 0, 0 }; - texCopyInfo.dstOffset = { 0, 0, 0 }; - - bufferCopyInfo.srcSubresource = dstSubresource; - bufferCopyInfo.extent = dstTextureInfo->extents; - bufferCopyInfo.textureOffset = { 0, 0, 0 }; - bufferCopyInfo.bufferOffset = 0; - - createRequiredResources(); - submitGPUWork(); - - auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcTextureInfo->mipLevelCount, srcSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedCopiedData = srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; - auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, dstTextureInfo->mipLevelCount, dstSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedOriginalData = dstTextureInfo->subresourceDatas[originalSubresourceIndex]; - checkTestResults(srcTextureInfo->extents, expectedCopiedData.data, expectedOriginalData.data); - } - }; + auto textureType = srcTextureInfo->textureType; + auto format = srcTextureInfo->format; + + srcTextureInfo->extents.width = 4; + srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + srcTextureInfo->mipLevelCount = 1; + srcTextureInfo->arrayLayerCount = + (textureType == ITextureResource::Type::Texture3D) ? 1 : 2; + + generateTextureData(srcTextureInfo, validationFormat); + dstTextureInfo = srcTextureInfo; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(format); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(format); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = (textureType == ITextureResource::Type::Texture3D) ? 0 : 1; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = srcTextureInfo->extents; + texCopyInfo.srcOffset = {0, 0, 0}; + texCopyInfo.dstOffset = {0, 0, 0}; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstTextureInfo->extents; + bufferCopyInfo.textureOffset = {0, 0, 0}; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto copiedSubresourceIndex = getSubresourceIndex( + srcSubresource.mipLevel, + srcTextureInfo->mipLevelCount, + srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedCopiedData = + srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; + auto originalSubresourceIndex = getSubresourceIndex( + dstSubresource.mipLevel, + dstTextureInfo->mipLevelCount, + dstSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedOriginalData = + dstTextureInfo->subresourceDatas[originalSubresourceIndex]; + checkTestResults( + srcTextureInfo->extents, + expectedCopiedData.data, + expectedOriginalData.data); + } +}; - struct CopyWithOffsets : BaseCopyTextureTest +struct CopyWithOffsets : BaseCopyTextureTest +{ + void run() { - void run() + auto textureType = srcTextureInfo->textureType; + auto format = srcTextureInfo->format; + + srcTextureInfo->extents.width = 8; + srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; + srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + srcTextureInfo->mipLevelCount = 1; + srcTextureInfo->arrayLayerCount = 1; + + generateTextureData(srcTextureInfo, validationFormat); + + dstTextureInfo->extents.width = 16; + dstTextureInfo->extents.height = + (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; + dstTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 4 : 1; + dstTextureInfo->mipLevelCount = 1; + dstTextureInfo->arrayLayerCount = 1; + + generateTextureData(dstTextureInfo, validationFormat); + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(format); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(format); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent.width = 4; + texCopyInfo.extent.height = 4; + texCopyInfo.extent.depth = 1; + texCopyInfo.srcOffset = {2, 2, 0}; + texCopyInfo.dstOffset = {4, 4, 0}; + + if (textureType == ITextureResource::Type::Texture1D) { - auto textureType = srcTextureInfo->textureType; - auto format = srcTextureInfo->format; - - srcTextureInfo->extents.width = 8; - srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; - srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - srcTextureInfo->mipLevelCount = 1; - srcTextureInfo->arrayLayerCount = 1; - - generateTextureData(srcTextureInfo, validationFormat); - - dstTextureInfo->extents.width = 16; - dstTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; - dstTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 4 : 1; - dstTextureInfo->mipLevelCount = 1; - dstTextureInfo->arrayLayerCount = 1; - - generateTextureData(dstTextureInfo, validationFormat); - - SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = getTextureAspect(format); - srcSubresource.mipLevel = 0; - srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = 0; - srcSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = getTextureAspect(format); - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - texCopyInfo.srcSubresource = srcSubresource; - texCopyInfo.dstSubresource = dstSubresource; - texCopyInfo.extent.width = 4; - texCopyInfo.extent.height = 4; - texCopyInfo.extent.depth = 1; - texCopyInfo.srcOffset = { 2, 2, 0 }; - texCopyInfo.dstOffset = { 4, 4, 0 }; - - if (textureType == ITextureResource::Type::Texture1D) - { - texCopyInfo.extent.height = 1; - texCopyInfo.srcOffset.y = 0; - texCopyInfo.dstOffset.y = 0; - } - else if (textureType == ITextureResource::Type::Texture3D) - { - texCopyInfo.extent.depth = srcTextureInfo->extents.depth; - texCopyInfo.dstOffset.z = 1; - } - - bufferCopyInfo.srcSubresource = dstSubresource; - bufferCopyInfo.extent = dstTextureInfo->extents; - bufferCopyInfo.textureOffset = { 0, 0, 0 }; - bufferCopyInfo.bufferOffset = 0; - - createRequiredResources(); - submitGPUWork(); - - auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcTextureInfo->mipLevelCount, srcSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedCopiedData = srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; - auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, dstTextureInfo->mipLevelCount, dstSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedOriginalData = dstTextureInfo->subresourceDatas[originalSubresourceIndex]; - checkTestResults(srcTextureInfo->extents, expectedCopiedData.data, expectedOriginalData.data); + texCopyInfo.extent.height = 1; + texCopyInfo.srcOffset.y = 0; + texCopyInfo.dstOffset.y = 0; } - }; - - struct CopySectionWithSetExtent : BaseCopyTextureTest - { - void run() + else if (textureType == ITextureResource::Type::Texture3D) { - auto textureType = srcTextureInfo->textureType; - auto format = srcTextureInfo->format; - - srcTextureInfo->extents.width = 8; - srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; - srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; - srcTextureInfo->mipLevelCount = 1; - srcTextureInfo->arrayLayerCount = 1; - - generateTextureData(srcTextureInfo, validationFormat); - dstTextureInfo = srcTextureInfo; - - SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = getTextureAspect(format); - srcSubresource.mipLevel = 0; - srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = 0; - srcSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = getTextureAspect(format); - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - texCopyInfo.srcSubresource = srcSubresource; - texCopyInfo.dstSubresource = dstSubresource; - texCopyInfo.extent.width = 4; - texCopyInfo.extent.height = 4; - texCopyInfo.extent.depth = 1; - texCopyInfo.srcOffset = { 0, 0, 0 }; - texCopyInfo.dstOffset = { 4, 4, 0 }; - - if (textureType == ITextureResource::Type::Texture1D) - { - texCopyInfo.extent.height = 1; - texCopyInfo.dstOffset.y = 0; - } - else if (textureType == ITextureResource::Type::Texture3D) - { - texCopyInfo.extent.depth = srcTextureInfo->extents.depth; - } - - bufferCopyInfo.srcSubresource = dstSubresource; - bufferCopyInfo.extent = dstTextureInfo->extents; - bufferCopyInfo.textureOffset = { 0, 0, 0 }; - bufferCopyInfo.bufferOffset = 0; + texCopyInfo.extent.depth = srcTextureInfo->extents.depth; + texCopyInfo.dstOffset.z = 1; + } - createRequiredResources(); - submitGPUWork(); + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstTextureInfo->extents; + bufferCopyInfo.textureOffset = {0, 0, 0}; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto copiedSubresourceIndex = getSubresourceIndex( + srcSubresource.mipLevel, + srcTextureInfo->mipLevelCount, + srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedCopiedData = + srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; + auto originalSubresourceIndex = getSubresourceIndex( + dstSubresource.mipLevel, + dstTextureInfo->mipLevelCount, + dstSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedOriginalData = + dstTextureInfo->subresourceDatas[originalSubresourceIndex]; + checkTestResults( + srcTextureInfo->extents, + expectedCopiedData.data, + expectedOriginalData.data); + } +}; - auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcTextureInfo->mipLevelCount, srcSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedCopiedData = srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; - auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, dstTextureInfo->mipLevelCount, dstSubresource.baseArrayLayer); - ITextureResource::SubresourceData expectedOriginalData = dstTextureInfo->subresourceDatas[originalSubresourceIndex]; - checkTestResults(srcTextureInfo->extents, expectedCopiedData.data, expectedOriginalData.data); +struct CopySectionWithSetExtent : BaseCopyTextureTest +{ + void run() + { + auto textureType = srcTextureInfo->textureType; + auto format = srcTextureInfo->format; + + srcTextureInfo->extents.width = 8; + srcTextureInfo->extents.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; + srcTextureInfo->extents.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + srcTextureInfo->mipLevelCount = 1; + srcTextureInfo->arrayLayerCount = 1; + + generateTextureData(srcTextureInfo, validationFormat); + dstTextureInfo = srcTextureInfo; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(format); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(format); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent.width = 4; + texCopyInfo.extent.height = 4; + texCopyInfo.extent.depth = 1; + texCopyInfo.srcOffset = {0, 0, 0}; + texCopyInfo.dstOffset = {4, 4, 0}; + + if (textureType == ITextureResource::Type::Texture1D) + { + texCopyInfo.extent.height = 1; + texCopyInfo.dstOffset.y = 0; + } + else if (textureType == ITextureResource::Type::Texture3D) + { + texCopyInfo.extent.depth = srcTextureInfo->extents.depth; } - }; - template<typename T> - void copyTextureTestImpl(IDevice* device, UnitTestContext* context) - { - const bool isVkd3d = SLANG_ENABLE_VKD3D && - strcmp(device->getDeviceInfo().apiName, "Direct3D 12") == 0; + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstTextureInfo->extents; + bufferCopyInfo.textureOffset = {0, 0, 0}; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto copiedSubresourceIndex = getSubresourceIndex( + srcSubresource.mipLevel, + srcTextureInfo->mipLevelCount, + srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedCopiedData = + srcTextureInfo->subresourceDatas[copiedSubresourceIndex]; + auto originalSubresourceIndex = getSubresourceIndex( + dstSubresource.mipLevel, + dstTextureInfo->mipLevelCount, + dstSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedOriginalData = + dstTextureInfo->subresourceDatas[originalSubresourceIndex]; + checkTestResults( + srcTextureInfo->extents, + expectedCopiedData.data, + expectedOriginalData.data); + } +}; - // Skip Type::Unknown and Type::Buffer as well as Format::Unknown - // TODO: Add support for TextureCube - Format formats[] = { Format::R8G8B8A8_UNORM, Format::R16_FLOAT, Format::R16G16_FLOAT, Format::R10G10B10A2_UNORM, Format::B5G5R5A1_UNORM }; - for (uint32_t i = 2; i < (uint32_t)ITextureResource::Type::_Count - 1; ++i) +template<typename T> +void copyTextureTestImpl(IDevice* device, UnitTestContext* context) +{ + const bool isVkd3d = + SLANG_ENABLE_VKD3D && strcmp(device->getDeviceInfo().apiName, "Direct3D 12") == 0; + + // Skip Type::Unknown and Type::Buffer as well as Format::Unknown + // TODO: Add support for TextureCube + Format formats[] = { + Format::R8G8B8A8_UNORM, + Format::R16_FLOAT, + Format::R16G16_FLOAT, + Format::R10G10B10A2_UNORM, + Format::B5G5R5A1_UNORM}; + for (uint32_t i = 2; i < (uint32_t)ITextureResource::Type::_Count - 1; ++i) + { + for (auto format : formats) { - for (auto format : formats) + // Fails validation VUID-VkImageCreateInfo-imageCreateMaxMipLevels-02251 + if (isVkd3d && + (format == Format::R32G32B32_TYPELESS || format == Format::R32G32B32_FLOAT || + format == Format::R32G32B32_UINT || format == Format::R32G32B32_SINT)) { - // Fails validation VUID-VkImageCreateInfo-imageCreateMaxMipLevels-02251 - if(isVkd3d && (format == Format::R32G32B32_TYPELESS || - format == Format::R32G32B32_FLOAT || - format == Format::R32G32B32_UINT || - format == Format::R32G32B32_SINT)) - { - continue; - } - auto type = (ITextureResource::Type)i; - auto validationFormat = getValidationTextureFormat(format); - if (!validationFormat) - continue; - - T test; - test.init(device, context, format, validationFormat, type); - test.run(); + continue; } + auto type = (ITextureResource::Type)i; + auto validationFormat = getValidationTextureFormat(format); + if (!validationFormat) + continue; + + T test; + test.init(device, context, format, validationFormat, type); + test.run(); } } +} - SLANG_UNIT_TEST(copyTextureSimple) - { - runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(copyTextureSimple) +{ + runTestImpl( + copyTextureTestImpl<SimpleCopyTexture>, + unitTestContext, + Slang::RenderApiFlag::D3D12); + runTestImpl( + copyTextureTestImpl<SimpleCopyTexture>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); +} - SLANG_UNIT_TEST(copyTextureSection) - { - runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(copyTextureSection) +{ + runTestImpl( + copyTextureTestImpl<CopyTextureSection>, + unitTestContext, + Slang::RenderApiFlag::D3D12); + runTestImpl( + copyTextureTestImpl<CopyTextureSection>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); +} - SLANG_UNIT_TEST(copyLargeToSmallTexture) - { - runTestImpl(copyTextureTestImpl<LargeSrcToSmallDst>, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(copyTextureTestImpl<LargeSrcToSmallDst>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(copyLargeToSmallTexture) +{ + runTestImpl( + copyTextureTestImpl<LargeSrcToSmallDst>, + unitTestContext, + Slang::RenderApiFlag::D3D12); + runTestImpl( + copyTextureTestImpl<LargeSrcToSmallDst>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); +} - SLANG_UNIT_TEST(copySmallToLargeTexture) - { - runTestImpl(copyTextureTestImpl<SmallSrcToLargeDst>, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(copyTextureTestImpl<SmallSrcToLargeDst>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(copySmallToLargeTexture) +{ + runTestImpl( + copyTextureTestImpl<SmallSrcToLargeDst>, + unitTestContext, + Slang::RenderApiFlag::D3D12); + runTestImpl( + copyTextureTestImpl<SmallSrcToLargeDst>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); +} - SLANG_UNIT_TEST(copyBetweenMips) - { - runTestImpl(copyTextureTestImpl<CopyBetweenMips>, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(copyTextureTestImpl<CopyBetweenMips>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(copyBetweenMips) +{ + runTestImpl(copyTextureTestImpl<CopyBetweenMips>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl( + copyTextureTestImpl<CopyBetweenMips>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); +} - SLANG_UNIT_TEST(copyBetweenLayers) - { - runTestImpl(copyTextureTestImpl<CopyBetweenLayers>, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(copyTextureTestImpl<CopyBetweenLayers>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(copyBetweenLayers) +{ + runTestImpl( + copyTextureTestImpl<CopyBetweenLayers>, + unitTestContext, + Slang::RenderApiFlag::D3D12); + runTestImpl( + copyTextureTestImpl<CopyBetweenLayers>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); +} - SLANG_UNIT_TEST(copyWithOffsets) - { - runTestImpl(copyTextureTestImpl<CopyWithOffsets>, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(copyTextureTestImpl<CopyWithOffsets>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(copyWithOffsets) +{ + runTestImpl(copyTextureTestImpl<CopyWithOffsets>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl( + copyTextureTestImpl<CopyWithOffsets>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); +} - SLANG_UNIT_TEST(copySectionWithSetExtent) - { - runTestImpl(copyTextureTestImpl<CopySectionWithSetExtent>, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(copyTextureTestImpl<CopySectionWithSetExtent>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(copySectionWithSetExtent) +{ + runTestImpl( + copyTextureTestImpl<CopySectionWithSetExtent>, + unitTestContext, + Slang::RenderApiFlag::D3D12); + runTestImpl( + copyTextureTestImpl<CopySectionWithSetExtent>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/create-buffer-from-handle.cpp b/tools/gfx-unit-test/create-buffer-from-handle.cpp index 4e2261465..a4e743196 100644 --- a/tools/gfx-unit-test/create-buffer-from-handle.cpp +++ b/tools/gfx-unit-test/create-buffer-from-handle.cpp @@ -1,101 +1,103 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void createBufferFromHandleTestImpl(IDevice* device, UnitTestContext* context) +void createBufferFromHandleTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "compute-trivial", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> originalNumbersBuffer; + GFX_CHECK_CALL_ABORT(device->createBufferResource( + bufferDesc, + (void*)initialData, + originalNumbersBuffer.writeRef())); + + InteropHandle handle; + originalNumbersBuffer->getNativeResourceHandle(&handle); + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferFromNativeHandle(handle, bufferDesc, numbersBuffer.writeRef())); + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(0.0f, 1.0f, 2.0f, 3.0f)); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "compute-trivial", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> originalNumbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - originalNumbersBuffer.writeRef())); - - InteropHandle handle; - originalNumbersBuffer->getNativeResourceHandle(&handle); - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferFromNativeHandle(handle, bufferDesc, numbersBuffer.writeRef())); - compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(0.0f, 1.0f, 2.0f, 3.0f)); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor rootCursor(rootObject); - // Bind buffer view to the entry point. - rootCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); - } + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - SLANG_UNIT_TEST(createBufferFromHandleD3D12) - { - runTestImpl(createBufferFromHandleTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - SLANG_UNIT_TEST(createBufferFromHandleVulkan) - { - runTestImpl(createBufferFromHandleTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor rootCursor(rootObject); + // Bind buffer view to the entry point. + rootCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); +} + +SLANG_UNIT_TEST(createBufferFromHandleD3D12) +{ + runTestImpl(createBufferFromHandleTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); } + +SLANG_UNIT_TEST(createBufferFromHandleVulkan) +{ + runTestImpl(createBufferFromHandleTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/existing-device-handle-test.cpp b/tools/gfx-unit-test/existing-device-handle-test.cpp index d6f66af84..03f924b5c 100644 --- a/tools/gfx-unit-test/existing-device-handle-test.cpp +++ b/tools/gfx-unit-test/existing-device-handle-test.cpp @@ -1,151 +1,143 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void existingDeviceHandleTestImpl(IDevice* device, UnitTestContext* context) +void existingDeviceHandleTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "compute-trivial", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "compute-trivial", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor rootCursor(rootObject); - // Bind buffer view to the root. - rootCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor rootCursor(rootObject); + // Bind buffer view to the root. + rootCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - void existingDeviceHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); +} + +void existingDeviceHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +{ + if ((api & context->enabledApis) == 0) { - if ((api & context->enabledApis) == 0) - { - SLANG_IGNORE_TEST; - } - Slang::ComPtr<IDevice> device; - IDevice::Desc deviceDesc = {}; - switch (api) - { - case Slang::RenderApiFlag::D3D12: - deviceDesc.deviceType = gfx::DeviceType::DirectX12; - break; - case Slang::RenderApiFlag::Vulkan: - deviceDesc.deviceType = gfx::DeviceType::Vulkan; - break; - case Slang::RenderApiFlag::CUDA: - deviceDesc.deviceType = gfx::DeviceType::CUDA; - break; - default: - SLANG_IGNORE_TEST; - } - deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; - const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" }; - deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); - deviceDesc.slang.searchPaths = searchPaths; - auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); - if (SLANG_FAILED(createDeviceResult) || !device) - { - SLANG_IGNORE_TEST; - } - - IDevice::InteropHandles handles; - GFX_CHECK_CALL_ABORT(device->getNativeDeviceHandles(&handles)); - Slang::ComPtr<IDevice> testDevice; - IDevice::Desc testDeviceDesc = deviceDesc; - testDeviceDesc.existingDeviceHandles.handles[0] = handles.handles[0]; - if (api == Slang::RenderApiFlag::Vulkan) - { - testDeviceDesc.existingDeviceHandles.handles[1] = handles.handles[1]; - testDeviceDesc.existingDeviceHandles.handles[2] = handles.handles[2]; - } - auto createTestDeviceResult = gfxCreateDevice(&testDeviceDesc, testDevice.writeRef()); - if (SLANG_FAILED(createTestDeviceResult) || !device) - { - SLANG_IGNORE_TEST; - } - - existingDeviceHandleTestImpl(device, context); + SLANG_IGNORE_TEST; } - - SLANG_UNIT_TEST(existingDeviceHandleD3D12) + Slang::ComPtr<IDevice> device; + IDevice::Desc deviceDesc = {}; + switch (api) { - return existingDeviceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); + case Slang::RenderApiFlag::D3D12: deviceDesc.deviceType = gfx::DeviceType::DirectX12; break; + case Slang::RenderApiFlag::Vulkan: deviceDesc.deviceType = gfx::DeviceType::Vulkan; break; + case Slang::RenderApiFlag::CUDA: deviceDesc.deviceType = gfx::DeviceType::CUDA; break; + default: SLANG_IGNORE_TEST; + } + deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; + const char* searchPaths[] = {"", "../../tools/gfx-unit-test", "tools/gfx-unit-test"}; + deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); + deviceDesc.slang.searchPaths = searchPaths; + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); + if (SLANG_FAILED(createDeviceResult) || !device) + { + SLANG_IGNORE_TEST; } - SLANG_UNIT_TEST(existingDeviceHandleVulkan) + IDevice::InteropHandles handles; + GFX_CHECK_CALL_ABORT(device->getNativeDeviceHandles(&handles)); + Slang::ComPtr<IDevice> testDevice; + IDevice::Desc testDeviceDesc = deviceDesc; + testDeviceDesc.existingDeviceHandles.handles[0] = handles.handles[0]; + if (api == Slang::RenderApiFlag::Vulkan) { - return existingDeviceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); + testDeviceDesc.existingDeviceHandles.handles[1] = handles.handles[1]; + testDeviceDesc.existingDeviceHandles.handles[2] = handles.handles[2]; } -#if SLANG_WIN64 - SLANG_UNIT_TEST(existingDeviceHandleCUDA) + auto createTestDeviceResult = gfxCreateDevice(&testDeviceDesc, testDevice.writeRef()); + if (SLANG_FAILED(createTestDeviceResult) || !device) { - return existingDeviceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::CUDA); + SLANG_IGNORE_TEST; } -#endif + + existingDeviceHandleTestImpl(device, context); +} + +SLANG_UNIT_TEST(existingDeviceHandleD3D12) +{ + return existingDeviceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); } + +SLANG_UNIT_TEST(existingDeviceHandleVulkan) +{ + return existingDeviceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); +} +#if SLANG_WIN64 +SLANG_UNIT_TEST(existingDeviceHandleCUDA) +{ + return existingDeviceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::CUDA); +} +#endif +} // namespace gfx_test diff --git a/tools/gfx-unit-test/format-unit-tests.cpp b/tools/gfx-unit-test/format-unit-tests.cpp index 5755e03cd..6ce38a26a 100644 --- a/tools/gfx-unit-test/format-unit-tests.cpp +++ b/tools/gfx-unit-test/format-unit-tests.cpp @@ -1,1119 +1,1489 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - gfx::Format convertTypelessFormat(gfx::Format format) +gfx::Format convertTypelessFormat(gfx::Format format) +{ + switch (format) + { + case gfx::Format::R32G32B32A32_TYPELESS: return gfx::Format::R32G32B32A32_FLOAT; + case gfx::Format::R32G32B32_TYPELESS: return gfx::Format::R32G32B32_FLOAT; + case gfx::Format::R32G32_TYPELESS: return gfx::Format::R32G32_FLOAT; + case gfx::Format::R32_TYPELESS: return gfx::Format::R32_FLOAT; + case gfx::Format::R16G16B16A16_TYPELESS: return gfx::Format::R16G16B16A16_FLOAT; + case gfx::Format::R16G16_TYPELESS: return gfx::Format::R16G16_FLOAT; + case gfx::Format::R16_TYPELESS: return gfx::Format::R16_FLOAT; + case gfx::Format::R8G8B8A8_TYPELESS: return gfx::Format::R8G8B8A8_UNORM; + case gfx::Format::R8G8_TYPELESS: return gfx::Format::R8G8_UNORM; + case gfx::Format::R8_TYPELESS: return gfx::Format::R8_UNORM; + case gfx::Format::B8G8R8A8_TYPELESS: return gfx::Format::B8G8R8A8_UNORM; + case gfx::Format::R10G10B10A2_TYPELESS: return gfx::Format::R10G10B10A2_UINT; + default: return gfx::Format::Unknown; + } +} + +void setUpAndRunTest( + IDevice* device, + ComPtr<IResourceView> texView, + ComPtr<IResourceView> bufferView, + const char* entryPoint, + ComPtr<ISamplerState> sampler = nullptr) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "format-test-shaders", + entryPoint, + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + + // Bind texture view to the entry point + entryPointCursor.getPath("tex").setResource(texView); + + if (sampler) + entryPointCursor.getPath("sampler").setSampler(sampler); + + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } +} + +ComPtr<IResourceView> createTexView( + IDevice* device, + ITextureResource::Extents size, + gfx::Format format, + ITextureResource::SubresourceData* data, + int mips = 1) +{ + ITextureResource::Desc texDesc = {}; + texDesc.type = IResource::Type::Texture2D; + texDesc.numMipLevels = mips; + texDesc.arraySize = 1; + texDesc.size = size; + texDesc.defaultState = ResourceState::ShaderResource; + texDesc.format = format; + + ComPtr<ITextureResource> inTex; + GFX_CHECK_CALL_ABORT(device->createTextureResource(texDesc, data, inTex.writeRef())); + + ComPtr<IResourceView> texView; + IResourceView::Desc texViewDesc = {}; + texViewDesc.type = IResourceView::Type::ShaderResource; + texViewDesc.format = gfxIsTypelessFormat(format) ? convertTypelessFormat(format) : format; + GFX_CHECK_CALL_ABORT(device->createTextureView(inTex, texViewDesc, texView.writeRef())); + return texView; +} + +template<typename T> +ComPtr<IBufferResource> createBuffer(IDevice* device, int size, void* initialData) +{ + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = size * sizeof(T); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(T); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> outBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, initialData, outBuffer.writeRef())); + return outBuffer; +} + +ComPtr<IResourceView> createBufferView(IDevice* device, ComPtr<IBufferResource> outBuffer) +{ + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(outBuffer, nullptr, viewDesc, bufferView.writeRef())); + return bufferView; +} + +void formatTestsImpl(IDevice* device, UnitTestContext* context) +{ + ISamplerState::Desc samplerDesc; + auto sampler = device->createSamplerState(samplerDesc); + + float initFloatData[16] = {0.0f}; + auto floatResults = createBuffer<float>(device, 16, initFloatData); + auto floatBufferView = createBufferView(device, floatResults); + + uint32_t initUintData[16] = {0u}; + auto uintResults = createBuffer<uint32_t>(device, 16, initUintData); + auto uintBufferView = createBufferView(device, uintResults); + + int32_t initIntData[16] = {0}; + auto intResults = createBuffer<uint32_t>(device, 16, initIntData); + auto intBufferView = createBufferView(device, intResults); + + ITextureResource::Extents size = {}; + size.width = 2; + size.height = 2; + size.depth = 1; + + ITextureResource::Extents bcSize = {}; + bcSize.width = 4; + bcSize.height = 4; + bcSize.depth = 1; + + // Note: D32_FLOAT and D16_UNORM are not directly tested as they are only used for raster. These + // are the same as R32_FLOAT and R16_UNORM, respectively, when passed to a shader. + { + float texData[] = { + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.5f, + 0.5f, + 0.5f, + 1.0f}; + ITextureResource::SubresourceData subData = {(void*)texData, 32, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32B32A32_FLOAT, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.5f, + 0.5f, + 0.5f, + 1.0f)); + + texView = createTexView(device, size, gfx::Format::R32G32B32A32_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.5f, + 0.5f, + 0.5f, + 1.0f)); + } + + // Ignore this test since it is not supported by swiftshader and nvidia's driver. + if (false) + { + float texData[] = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f}; + ITextureResource::SubresourceData subData = {(void*)texData, 24, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32B32_FLOAT, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); + compareComputeResult( + device, + floatResults, + Slang::makeArray< + float>(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f)); + + texView = createTexView(device, size, gfx::Format::R32G32B32_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); + compareComputeResult( + device, + floatResults, + Slang::makeArray< + float>(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f)); + } + + { + float texData[] = {1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32_FLOAT, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f)); + + texView = createTexView(device, size, gfx::Format::R32G32_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f)); + } + + { + float texData[] = {1.0f, 0.0f, 0.5f, 0.25f}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32_FLOAT, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.5f, 0.25f)); + + texView = createTexView(device, size, gfx::Format::R32_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.5f, 0.25f)); + } + + { + uint16_t texData[] = { + 15360u, + 0u, + 0u, + 15360u, + 0u, + 15360u, + 0u, + 15360u, + 0u, + 0u, + 15360u, + 15360u, + 14336u, + 14336u, + 14336u, + 15360u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_FLOAT, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.5f, + 0.5f, + 0.5f, + 1.0f)); + + texView = createTexView(device, size, gfx::Format::R16G16B16A16_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.5f, + 0.5f, + 0.5f, + 1.0f)); + } + + { + uint16_t texData[] = {15360u, 0u, 0u, 15360u, 15360u, 15360u, 14336u, 14336u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16_FLOAT, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f)); + + texView = createTexView(device, size, gfx::Format::R16G16_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f)); + } + + { + uint16_t texData[] = {15360u, 0u, 14336u, 13312u}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16_FLOAT, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.5f, 0.25f)); + + texView = createTexView(device, size, gfx::Format::R16_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.5f, 0.25f)); + } + + { + uint32_t texData[] = + {255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u}; + ITextureResource::SubresourceData subData = {(void*)texData, 32, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32B32A32_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>( + 255u, + 0u, + 0u, + 255u, + 0u, + 255u, + 0u, + 255u, + 0u, + 0u, + 255u, + 255u, + 127u, + 127u, + 127u, + 255u)); + } + + // Ignore this test since validation layer reports that it is unsupported. + if (false) { - switch (format) - { - case gfx::Format::R32G32B32A32_TYPELESS: - return gfx::Format::R32G32B32A32_FLOAT; - case gfx::Format::R32G32B32_TYPELESS: - return gfx::Format::R32G32B32_FLOAT; - case gfx::Format::R32G32_TYPELESS: - return gfx::Format::R32G32_FLOAT; - case gfx::Format::R32_TYPELESS: - return gfx::Format::R32_FLOAT; - case gfx::Format::R16G16B16A16_TYPELESS: - return gfx::Format::R16G16B16A16_FLOAT; - case gfx::Format::R16G16_TYPELESS: - return gfx::Format::R16G16_FLOAT; - case gfx::Format::R16_TYPELESS: - return gfx::Format::R16_FLOAT; - case gfx::Format::R8G8B8A8_TYPELESS: - return gfx::Format::R8G8B8A8_UNORM; - case gfx::Format::R8G8_TYPELESS: - return gfx::Format::R8G8_UNORM; - case gfx::Format::R8_TYPELESS: - return gfx::Format::R8_UNORM; - case gfx::Format::B8G8R8A8_TYPELESS: - return gfx::Format::B8G8R8A8_UNORM; - case gfx::Format::R10G10B10A2_TYPELESS: - return gfx::Format::R10G10B10A2_UINT; - default: - return gfx::Format::Unknown; - } + uint32_t texData[] = {255u, 0u, 0u, 0u, 255u, 0u, 0u, 0u, 255u, 127u, 127u, 127u}; + ITextureResource::SubresourceData subData = {(void*)texData, 24, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32B32_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint3"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>(255u, 0u, 0u, 0u, 255u, 0u, 0u, 0u, 255u, 127u, 127u, 127u)); } - void setUpAndRunTest( - IDevice* device, - ComPtr<IResourceView> texView, - ComPtr<IResourceView> bufferView, - const char* entryPoint, - ComPtr<ISamplerState> sampler = nullptr) { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "format-test-shaders", entryPoint, slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - - // Bind texture view to the entry point - entryPointCursor.getPath("tex").setResource(texView); - - if (sampler) entryPointCursor.getPath("sampler").setSampler(sampler); - - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + uint32_t texData[] = {255u, 0u, 0u, 255u, 255u, 255u, 127u, 127u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint2"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, 255u, 255u, 127u, 127u)); } - ComPtr<IResourceView> createTexView( - IDevice* device, - ITextureResource::Extents size, - gfx::Format format, - ITextureResource::SubresourceData* data, - int mips = 1) { - ITextureResource::Desc texDesc = {}; - texDesc.type = IResource::Type::Texture2D; - texDesc.numMipLevels = mips; - texDesc.arraySize = 1; - texDesc.size = size; - texDesc.defaultState = ResourceState::ShaderResource; - texDesc.format = format; - - ComPtr<ITextureResource> inTex; - GFX_CHECK_CALL_ABORT(device->createTextureResource( - texDesc, - data, - inTex.writeRef())); - - ComPtr<IResourceView> texView; - IResourceView::Desc texViewDesc = {}; - texViewDesc.type = IResourceView::Type::ShaderResource; - texViewDesc.format = gfxIsTypelessFormat(format) ? convertTypelessFormat(format) : format; - GFX_CHECK_CALL_ABORT(device->createTextureView(inTex, texViewDesc, texView.writeRef())); - return texView; + uint32_t texData[] = {255u, 0u, 127u, 73u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint"); + compareComputeResult(device, uintResults, Slang::makeArray<uint32_t>(255u, 0u, 127u, 73u)); } - template <typename T> - ComPtr<IBufferResource> createBuffer(IDevice* device, int size, void* initialData) { - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = size * sizeof(T); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(T); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> outBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - initialData, - outBuffer.writeRef())); - return outBuffer; + uint16_t texData[] = + {255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>( + 255u, + 0u, + 0u, + 255u, + 0u, + 255u, + 0u, + 255u, + 0u, + 0u, + 255u, + 255u, + 127u, + 127u, + 127u, + 255u)); } - ComPtr<IResourceView> createBufferView(IDevice* device, ComPtr<IBufferResource> outBuffer) { - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(outBuffer, nullptr, viewDesc, bufferView.writeRef())); - return bufferView; + uint16_t texData[] = {255u, 0u, 0u, 255u, 255u, 255u, 127u, 127u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint2"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, 255u, 255u, 127u, 127u)); } - void formatTestsImpl(IDevice* device, UnitTestContext* context) { - ISamplerState::Desc samplerDesc; - auto sampler = device->createSamplerState(samplerDesc); + uint16_t texData[] = {255u, 0u, 127u, 73u}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; - float initFloatData[16] = { 0.0f }; - auto floatResults = createBuffer<float>(device, 16, initFloatData); - auto floatBufferView = createBufferView(device, floatResults); + auto texView = createTexView(device, size, gfx::Format::R16_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint"); + compareComputeResult(device, uintResults, Slang::makeArray<uint32_t>(255u, 0u, 127u, 73u)); + } - uint32_t initUintData[16] = { 0u }; - auto uintResults = createBuffer<uint32_t>(device, 16, initUintData); - auto uintBufferView = createBufferView(device, uintResults); + { + uint8_t texData[] = + {255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8G8B8A8_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>( + 255u, + 0u, + 0u, + 255u, + 0u, + 255u, + 0u, + 255u, + 0u, + 0u, + 255u, + 255u, + 127u, + 127u, + 127u, + 255u)); + } - int32_t initIntData[16] = { 0 }; - auto intResults = createBuffer<uint32_t>(device, 16, initIntData); - auto intBufferView = createBufferView(device, intResults); + { + uint8_t texData[] = {255u, 0u, 0u, 255u, 255u, 255u, 127u, 127u}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8G8_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint2"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, 255u, 255u, 127u, 127u)); + } + { + uint8_t texData[] = {255u, 0u, 127u, 73u}; + ITextureResource::SubresourceData subData = {(void*)texData, 2, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint"); + compareComputeResult(device, uintResults, Slang::makeArray<uint32_t>(255u, 0u, 127u, 73u)); + } + + { + int32_t texData[] = {255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 127, 127, 127, 255}; + ITextureResource::SubresourceData subData = {(void*)texData, 32, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32B32A32_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt4"); + compareComputeResult( + device, + intResults, + Slang::makeArray< + int32_t>(255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 127, 127, 127, 255)); + } + + // Ignore this test on swiftshader. Swiftshader produces unsupported format warnings for this + // test. + if (false) + { + int32_t texData[] = {255, 0, 0, 0, 255, 0, 0, 0, 255, 127, 127, 127}; + ITextureResource::SubresourceData subData = {(void*)texData, 24, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32B32_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt3"); + compareComputeResult( + device, + intResults, + Slang::makeArray<int32_t>(255, 0, 0, 0, 255, 0, 0, 0, 255, 127, 127, 127)); + } + + { + int32_t texData[] = {255, 0, 0, 255, 255, 255, 127, 127}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32G32_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt2"); + compareComputeResult( + device, + intResults, + Slang::makeArray<int32_t>(255, 0, 0, 255, 255, 255, 127, 127)); + } + + { + int32_t texData[] = {255, 0, 127, 73}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R32_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt"); + compareComputeResult(device, intResults, Slang::makeArray<int32_t>(255, 0, 127, 73)); + } + + { + int16_t texData[] = {255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 127, 127, 127, 255}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt4"); + compareComputeResult( + device, + intResults, + Slang::makeArray< + int32_t>(255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 127, 127, 127, 255)); + } + + { + int16_t texData[] = {255, 0, 0, 255, 255, 255, 127, 127}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt2"); + compareComputeResult( + device, + intResults, + Slang::makeArray<int32_t>(255, 0, 0, 255, 255, 255, 127, 127)); + } + + { + int16_t texData[] = {255, 0, 127, 73}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt"); + compareComputeResult(device, intResults, Slang::makeArray<int32_t>(255, 0, 127, 73)); + } + + { + int8_t texData[] = {127, 0, 0, 127, 0, 127, 0, 127, 0, 0, 127, 127, 0, 0, 0, 127}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8G8B8A8_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt4"); + compareComputeResult( + device, + intResults, + Slang::makeArray< + int32_t>(127, 0, 0, 127, 0, 127, 0, 127, 0, 0, 127, 127, 0, 0, 0, 127)); + } + + { + int8_t texData[] = {127, 0, 0, 127, 127, 127, 73, 73}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8G8_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt2"); + compareComputeResult( + device, + intResults, + Slang::makeArray<int32_t>(127, 0, 0, 127, 127, 127, 73, 73)); + } + + { + int8_t texData[] = {127, 0, 73, 25}; + ITextureResource::SubresourceData subData = {(void*)texData, 2, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8_SINT, &subData); + setUpAndRunTest(device, texView, intBufferView, "copyTexInt"); + compareComputeResult(device, intResults, Slang::makeArray<int32_t>(127, 0, 73, 25)); + } + + { + uint16_t texData[] = { + 65535u, + 0u, + 0u, + 65535u, + 0u, + 65535u, + 0u, + 65535u, + 0u, + 0u, + 65535u, + 65535u, + 32767u, + 32767u, + 32767u, + 32767u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.499992371f, + 0.499992371f, + 0.499992371f, + 0.499992371f)); + } + + { + uint16_t texData[] = {65535u, 0u, 0u, 65535u, 65535u, 65535u, 32767u, 32767u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray< + float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.499992371f, 0.499992371f)); + } + + { + uint16_t texData[] = {65535u, 0u, 32767u, 16383u}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.499992371f, 0.249988556f)); + } + + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = + {0u, 0u, 0u, 255u, 127u, 127u, 127u, 255u, 255u, 255u, 255u, 255u, 0u, 0u, 0u, 0u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8G8B8A8_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.498039216f, + 0.498039216f, + 0.498039216f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f)); + + texView = createTexView(device, size, gfx::Format::R8G8B8A8_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.498039216f, + 0.498039216f, + 0.498039216f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f)); + + texView = createTexView(device, size, gfx::Format::R8G8B8A8_UNORM_SRGB, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.211914062f, + 0.211914062f, + 0.211914062f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f)); + } + + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = {255u, 0u, 0u, 255u, 255u, 255u, 127u, 127u}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8G8_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray< + float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.498039216f, 0.498039216f)); + + texView = createTexView(device, size, gfx::Format::R8G8_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray< + float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.498039216f, 0.498039216f)); + } + + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = {255u, 0u, 127u, 63u}; + ITextureResource::SubresourceData subData = {(void*)texData, 2, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.498039216f, 0.247058824f)); + + texView = createTexView(device, size, gfx::Format::R8_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.498039216f, 0.247058824f)); + } + + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = + {0u, 0u, 0u, 255u, 127u, 127u, 127u, 255u, 255u, 255u, 255u, 255u, 0u, 0u, 0u, 0u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::B8G8R8A8_TYPELESS, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.498039216f, + 0.498039216f, + 0.498039216f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f)); + + texView = createTexView(device, size, gfx::Format::B8G8R8A8_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.498039216f, + 0.498039216f, + 0.498039216f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f)); + + texView = createTexView(device, size, gfx::Format::B8G8R8A8_UNORM_SRGB, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.211914062f, + 0.211914062f, + 0.211914062f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f)); + } + + { + int16_t texData[] = + {32767, 0, 0, 32767, 0, 32767, 0, 32767, 0, 0, 32767, 32767, -32768, -32768, 0, 32767}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_SNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + -1.0f, + -1.0f, + 0.0f, + 1.0f)); + } + + { + int16_t texData[] = {32767, 0, 0, 32767, 32767, 32767, -32768, -32768}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16G16_SNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f)); + } + + { + int16_t texData[] = {32767, 0, -32768, 0}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::R16_SNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, -1.0f, 0.0f)); + } + + { + int8_t texData[] = {127, 0, 0, 127, 0, 127, 0, 127, 0, 0, 127, 127, -128, -128, 0, 127}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8G8B8A8_SNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + -1.0f, + -1.0f, + 0.0f, + 1.0f)); + } + + { + int8_t texData[] = {127, 0, 0, 127, 127, 127, -128, -128}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8G8_SNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f)); + } + + { + int8_t texData[] = {127, 0, -128, 0}; + ITextureResource::SubresourceData subData = {(void*)texData, 2, 0}; + + auto texView = createTexView(device, size, gfx::Format::R8_SNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, -1.0f, 0.0f)); + } + + // Ignore this test on swiftshader. Swiftshader produces unsupported format warnings for this + // test. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = {15u, 240u, 240u, 240u, 0u, 255u, 119u, 119u}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::B4G4R4A4_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.466666669f, + 0.466666669f, + 0.466666669f, + 0.466666669f)); + } + + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint16_t texData[] = {31u, 2016u, 63488u, 31727u}; + ITextureResource::SubresourceData subData = {(void*)texData, 4, 0}; + + auto texView = createTexView(device, size, gfx::Format::B5G6R5_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 0.482352942f, + 0.490196079f, + 0.482352942f)); + + texView = createTexView(device, size, gfx::Format::B5G5R5A1_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0313725509f, + 1.0f, + 0.0f, + 0.0f, + 0.968627453f, + 0.0f, + 0.0f, + 1.0f, + 0.968627453f, + 1.0f, + 0.482352942f, + 0.0f)); + } + + { + uint32_t texData[] = {2950951416u, 2013265920u, 3086219772u, 3087007228u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R9G9B9E5_SHAREDEXP, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 63.0f, + 63.0f, + 63.0f, + 0.0f, + 0.0f, + 0.0f, + 127.0f, + 127.0f, + 127.0f, + 127.0f, + 127.5f, + 127.75f)); + } + + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint32_t texData[] = {4294967295u, 0u, 2683829759u, 1193046471u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R10G10B10A2_TYPELESS, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>( + 1023u, + 1023u, + 1023u, + 3u, + 0u, + 0u, + 0u, + 0u, + 511u, + 511u, + 511u, + 2u, + 455u, + 796u, + 113u, + 1u)); + + texView = createTexView(device, size, gfx::Format::R10G10B10A2_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 1.0f, + 1.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.499511242f, + 0.499511242f, + 0.499511242f, + 0.666666687f, + 0.444770277f, + 0.778103590f, + 0.110459432f, + 0.333333343f)); + + texView = createTexView(device, size, gfx::Format::R10G10B10A2_UINT, &subData); + setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); + compareComputeResult( + device, + uintResults, + Slang::makeArray<uint32_t>( + 1023u, + 1023u, + 1023u, + 3u, + 0u, + 0u, + 0u, + 0u, + 511u, + 511u, + 511u, + 2u, + 455u, + 796u, + 113u, + 1u)); + } + + { + uint32_t texData[] = {3085827519u, 0u, 2951478655u, 1880884096u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, size, gfx::Format::R11G11B10_FLOAT, &subData); + setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 254.0f, + 254.0f, + 252.0f, + 0.0f, + 0.0f, + 0.0f, + 127.0f, + 127.0f, + 126.0f, + 0.5f, + 0.5f, + 0.5f)); + } + + // These BC1 tests also check that mipmaps are working correctly for compressed formats. + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = {16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 16u, 0u, 0u, 0u, 0u, 0u, + 0u, 0u, 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 16u, 0u, 0u, 0u, + 0u, 0u, 0u, 0u, 255u, 255u, 255u, 255u, 0u, 0u, 0u, 0u}; + ITextureResource::SubresourceData subData[] = { + ITextureResource::SubresourceData{(void*)texData, 16, 32}, + ITextureResource::SubresourceData{(void*)(texData + 32), 8, 0}}; ITextureResource::Extents size = {}; - size.width = 2; - size.height = 2; + size.width = 8; + size.height = 8; size.depth = 1; - ITextureResource::Extents bcSize = {}; - bcSize.width = 4; - bcSize.height = 4; - bcSize.depth = 1; - - // Note: D32_FLOAT and D16_UNORM are not directly tested as they are only used for raster. These - // are the same as R32_FLOAT and R16_UNORM, respectively, when passed to a shader. - { - float texData[] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f }; - ITextureResource::SubresourceData subData = { (void*)texData, 32, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32B32A32_FLOAT, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f)); - - texView = createTexView(device, size, gfx::Format::R32G32B32A32_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f)); - } - - // Ignore this test since it is not supported by swiftshader and nvidia's driver. - if (false) - { - float texData[] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f }; - ITextureResource::SubresourceData subData = { (void*)texData, 24, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32B32_FLOAT, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f)); - - texView = createTexView(device, size, gfx::Format::R32G32B32_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f)); - } - - { - float texData[] = { 1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 0.5f, 0.5f }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32_FLOAT, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 0.5f, 0.5f)); - - texView = createTexView(device, size, gfx::Format::R32G32_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 0.5f, 0.5f)); - } - - { - float texData[] = { 1.0f, 0.0f, 0.5f, 0.25f }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32_FLOAT, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.5f, 0.25f)); - - texView = createTexView(device, size, gfx::Format::R32_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.5f, 0.25f)); - } - - { - uint16_t texData[] = { 15360u, 0u, 0u, 15360u, 0u, 15360u, 0u, 15360u, - 0u, 0u, 15360u, 15360u, 14336u, 14336u, 14336u, 15360u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_FLOAT, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f)); - - texView = createTexView(device, size, gfx::Format::R16G16B16A16_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f)); - } - - { - uint16_t texData[] = { 15360u, 0u, 0u, 15360u, - 15360u, 15360u, 14336u, 14336u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16_FLOAT, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 0.5f, 0.5f)); - - texView = createTexView(device, size, gfx::Format::R16G16_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 0.5f, 0.5f)); - } - - { - uint16_t texData[] = { 15360u, 0u, 14336u, 13312u }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16_FLOAT, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.5f, 0.25f)); - - texView = createTexView(device, size, gfx::Format::R16_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.5f, 0.25f)); - } - - { - uint32_t texData[] = { 255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, - 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u }; - ITextureResource::SubresourceData subData = { (void*)texData, 32, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32B32A32_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, - 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u)); - } - - // Ignore this test since validation layer reports that it is unsupported. - if (false) - { - uint32_t texData[] = { 255u, 0u, 0u, 0u, 255u, 0u, - 0u, 0u, 255u, 127u, 127u, 127u }; - ITextureResource::SubresourceData subData = { (void*)texData, 24, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32B32_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint3"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 0u, 0u, 255u, 0u, - 0u, 0u, 255u, 127u, 127u, 127u)); - } - - { - uint32_t texData[] = { 255u, 0u, 0u, 255u, - 255u, 255u, 127u, 127u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint2"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, - 255u, 255u, 127u, 127u)); - } - - { - uint32_t texData[] = { 255u, 0u, 127u, 73u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 127u, 73u)); - } - - { - uint16_t texData[] = { 255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, - 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, - 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u)); - } - - { - uint16_t texData[] = { 255u, 0u, 0u, 255u, - 255u, 255u, 127u, 127u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint2"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, - 255u, 255u, 127u, 127u)); - } - - { - uint16_t texData[] = { 255u, 0u, 127u, 73u }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 127u, 73u)); - } - - { - uint8_t texData[] = { 255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, - 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8G8B8A8_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, - 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u)); - } - - { - uint8_t texData[] = { 255u, 0u, 0u, 255u, - 255u, 255u, 127u, 127u }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8G8_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint2"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 0u, 255u, - 255u, 255u, 127u, 127u)); - } - - { - uint8_t texData[] = { 255u, 0u, 127u, 73u }; - ITextureResource::SubresourceData subData = { (void*)texData, 2, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(255u, 0u, 127u, 73u)); - } - - { - int32_t texData[] = { 255, 0, 0, 255, 0, 255, 0, 255, - 0, 0, 255, 255, 127, 127, 127, 255 }; - ITextureResource::SubresourceData subData = { (void*)texData, 32, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32B32A32_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt4"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(255, 0, 0, 255, 0, 255, 0, 255, - 0, 0, 255, 255, 127, 127, 127, 255)); - } - - // Ignore this test on swiftshader. Swiftshader produces unsupported format warnings for this test. - if (false) - { - int32_t texData[] = { 255, 0, 0, 0, 255, 0, - 0, 0, 255, 127, 127, 127 }; - ITextureResource::SubresourceData subData = { (void*)texData, 24, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32B32_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt3"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(255, 0, 0, 0, 255, 0, - 0, 0, 255, 127, 127, 127)); - } - - { - int32_t texData[] = { 255, 0, 0, 255, - 255, 255, 127, 127 }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32G32_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt2"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(255, 0, 0, 255, - 255, 255, 127, 127)); - } - - { - int32_t texData[] = { 255, 0, 127, 73 }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R32_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(255, 0, 127, 73)); - } - - { - int16_t texData[] = { 255, 0, 0, 255, 0, 255, 0, 255, - 0, 0, 255, 255, 127, 127, 127, 255 }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt4"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(255, 0, 0, 255, 0, 255, 0, 255, - 0, 0, 255, 255, 127, 127, 127, 255)); - } - - { - int16_t texData[] = { 255, 0, 0, 255, - 255, 255, 127, 127 }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt2"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(255, 0, 0, 255, - 255, 255, 127, 127)); - } - - { - int16_t texData[] = { 255, 0, 127, 73 }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(255, 0, 127, 73)); - } - - { - int8_t texData[] = { 127, 0, 0, 127, 0, 127, 0, 127, - 0, 0, 127, 127, 0, 0, 0, 127 }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8G8B8A8_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt4"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(127, 0, 0, 127, 0, 127, 0, 127, - 0, 0, 127, 127, 0, 0, 0, 127)); - } - - { - int8_t texData[] = { 127, 0, 0, 127, - 127, 127, 73, 73 }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8G8_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt2"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(127, 0, 0, 127, - 127, 127, 73, 73)); - } - - { - int8_t texData[] = { 127, 0, 73, 25 }; - ITextureResource::SubresourceData subData = { (void*)texData, 2, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8_SINT, &subData); - setUpAndRunTest(device, texView, intBufferView, "copyTexInt"); - compareComputeResult( - device, - intResults, - Slang::makeArray<int32_t>(127, 0, 73, 25)); - } - - { - uint16_t texData[] = { 65535u, 0u, 0u, 65535u, 0u, 65535u, 0u, 65535u, - 0u, 0u, 65535u, 65535u, 32767u, 32767u, 32767u, 32767u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.499992371f, 0.499992371f, 0.499992371f, 0.499992371f)); - } - - { - uint16_t texData[] = { 65535u, 0u, 0u, 65535u, - 65535u, 65535u, 32767u, 32767u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 0.499992371f, 0.499992371f)); - } - - { - uint16_t texData[] = { 65535u, 0u, 32767u, 16383u }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.499992371f, 0.249988556f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 0u, 0u, 0u, 255u, 127u, 127u, 127u, 255u, - 255u, 255u, 255u, 255u, 0u, 0u, 0u, 0u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0}; - - auto texView = createTexView(device, size, gfx::Format::R8G8B8A8_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.0f, 1.0f, 0.498039216f, 0.498039216f, 0.498039216f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - texView = createTexView(device, size, gfx::Format::R8G8B8A8_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.0f, 1.0f, 0.498039216f, 0.498039216f, 0.498039216f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - texView = createTexView(device, size, gfx::Format::R8G8B8A8_UNORM_SRGB, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.0f, 1.0f, 0.211914062f, 0.211914062f, 0.211914062f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 255u, 0u, 0u, 255u, 255u, 255u, 127u, 127u }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8G8_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.498039216f, 0.498039216f)); - - texView = createTexView(device, size, gfx::Format::R8G8_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.498039216f, 0.498039216f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 255u, 0u, 127u, 63u }; - ITextureResource::SubresourceData subData = { (void*)texData, 2, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.498039216f, 0.247058824f)); - - texView = createTexView(device, size, gfx::Format::R8_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.498039216f, 0.247058824f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 0u, 0u, 0u, 255u, 127u, 127u, 127u, 255u, - 255u, 255u, 255u, 255u, 0u, 0u, 0u, 0u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::B8G8R8A8_TYPELESS, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.0f, 1.0f, 0.498039216f, 0.498039216f, 0.498039216f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - texView = createTexView(device, size, gfx::Format::B8G8R8A8_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.0f, 1.0f, 0.498039216f, 0.498039216f, 0.498039216f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - texView = createTexView(device, size, gfx::Format::B8G8R8A8_UNORM_SRGB, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.0f, 1.0f, 0.211914062f, 0.211914062f, 0.211914062f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - } - - { - int16_t texData[] = { 32767, 0, 0, 32767, 0, 32767, 0, 32767, - 0, 0, 32767, 32767, -32768, -32768, 0, 32767 }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16B16A16_SNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f)); - } - - { - int16_t texData[] = { 32767, 0, 0, 32767, - 32767, 32767, -32768, -32768 }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16G16_SNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f)); - } - - { - int16_t texData[] = { 32767, 0, -32768, 0}; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R16_SNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, -1.0f, 0.0f)); - } - - { - int8_t texData[] = { 127, 0, 0, 127, 0, 127, 0, 127, - 0, 0, 127, 127, -128, -128, 0, 127 }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8G8B8A8_SNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f)); - } - - { - int8_t texData[] = { 127, 0, 0, 127, - 127, 127, -128, -128 }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8G8_SNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat2"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f)); - } - - { - int8_t texData[] = { 127, 0, -128, 0 }; - ITextureResource::SubresourceData subData = { (void*)texData, 2, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R8_SNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, -1.0f, 0.0f)); - } - - // Ignore this test on swiftshader. Swiftshader produces unsupported format warnings for this test. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 15u, 240u, 240u, 240u, 0u, 255u, 119u, 119u }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::B4G4R4A4_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, 1.0f, 0.466666669f, 0.466666669f, 0.466666669f, 0.466666669f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint16_t texData[] = { 31u, 2016u, 63488u, 31727u }; - ITextureResource::SubresourceData subData = { (void*)texData, 4, 0 }; - - auto texView = createTexView(device, size, gfx::Format::B5G6R5_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, - 1.0f, 0.0f, 0.0f, 0.482352942f, 0.490196079f, 0.482352942f)); - - texView = createTexView(device, size, gfx::Format::B5G5R5A1_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 1.0f, 0.0f, 0.0313725509f, 1.0f, 0.0f, 0.0f, - 0.968627453f, 0.0f, 0.0f, 1.0f, 0.968627453f, 1.0f, 0.482352942f, 0.0f)); - } - - { - uint32_t texData[] = { 2950951416u, 2013265920u, 3086219772u, 3087007228u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R9G9B9E5_SHAREDEXP, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(63.0f, 63.0f, 63.0f, 0.0f, 0.0f, 0.0f, - 127.0f, 127.0f, 127.0f, 127.0f, 127.5f, 127.75f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint32_t texData[] = { 4294967295u, 0u, 2683829759u, 1193046471u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R10G10B10A2_TYPELESS, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(1023u, 1023u, 1023u, 3u, 0u, 0u, 0u, 0u, - 511u, 511u, 511u, 2u, 455u, 796u, 113u, 1u)); - - texView = createTexView(device, size, gfx::Format::R10G10B10A2_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.499511242f, 0.499511242f, 0.499511242f, 0.666666687f, - 0.444770277f, 0.778103590f, 0.110459432f, 0.333333343f)); - - texView = createTexView(device, size, gfx::Format::R10G10B10A2_UINT, &subData); - setUpAndRunTest(device, texView, uintBufferView, "copyTexUint4"); - compareComputeResult( - device, - uintResults, - Slang::makeArray<uint32_t>(1023u, 1023u, 1023u, 3u, 0u, 0u, 0u, 0u, - 511u, 511u, 511u, 2u, 455u, 796u, 113u, 1u)); - } - - { - uint32_t texData[] = { 3085827519u, 0u, 2951478655u, 1880884096u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, size, gfx::Format::R11G11B10_FLOAT, &subData); - setUpAndRunTest(device, texView, floatBufferView, "copyTexFloat3"); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(254.0f, 254.0f, 252.0f, 0.0f, 0.0f, 0.0f, 127.0f, 127.0f, 126.0f, 0.5f, 0.5f, 0.5f)); - } - - // These BC1 tests also check that mipmaps are working correctly for compressed formats. - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, - 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, - 255u, 255u, 255u, 255u, 0u, 0u, 0u, 0u }; - ITextureResource::SubresourceData subData[] = { - ITextureResource::SubresourceData {(void*)texData, 16, 32}, - ITextureResource::SubresourceData {(void*)(texData + 32), 8, 0} - }; - ITextureResource::Extents size = {}; - size.width = 8; - size.height = 8; - size.depth = 1; - - auto texView = createTexView(device, size, gfx::Format::BC1_UNORM, subData, 2); - setUpAndRunTest(device, texView, floatBufferView, "sampleMips", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.517647088f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f)); - - texView = createTexView(device, size, gfx::Format::BC1_UNORM_SRGB, subData, 2); - setUpAndRunTest(device, texView, floatBufferView, "sampleMips", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.230468750f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, bcSize, gfx::Format::BC2_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.517647088f, 1.0f)); - - texView = createTexView(device, bcSize, gfx::Format::BC2_UNORM_SRGB, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.230468750f, 1.0f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 0u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, bcSize, gfx::Format::BC3_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.517647088f, 1.0f)); - - texView = createTexView(device, bcSize, gfx::Format::BC3_UNORM_SRGB, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0f, 0.230468750f, 1.0f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 127u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; - ITextureResource::SubresourceData subData = { (void*)texData, 8, 0 }; - - auto texView = createTexView(device, bcSize, gfx::Format::BC4_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.498039216f, 0.0f, 0.0f, 1.0f)); - - texView = createTexView(device, bcSize, gfx::Format::BC4_SNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 127u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 127u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, bcSize, gfx::Format::BC5_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.498039216f, 0.498039216f, 0.0f, 1.0f, 0.498039216f, 0.498039216f, 0.0f, 1.0f)); - - texView = createTexView(device, bcSize, gfx::Format::BC5_SNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f)); - } - - // BC6H_UF16 and BC6H_SF16 are tested separately due to requiring different texture data. - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 98u, 238u, 232u, 77u, 240u, 66u, 148u, 31u, - 124u, 95u, 2u, 224u, 255u, 107u, 77u, 250u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, bcSize, gfx::Format::BC6H_UF16, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.336669922f, 0.911132812f, 2.13867188f, 1.0f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 107u, 238u, 232u, 77u, 240u, 71u, 128u, 127u, - 1u, 0u, 255u, 255u, 170u, 218u, 221u, 254u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, bcSize, gfx::Format::BC6H_SF16, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.336914062f, 0.910644531f, 2.14062500f, 1.0f)); - } - - // Ignore this test on swiftshader. Swiftshader produces different results than expected. - if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - uint8_t texData[] = { 104u, 0u, 0u, 0u, 64u, 163u, 209u, 104u, - 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; - ITextureResource::SubresourceData subData = { (void*)texData, 16, 0 }; - - auto texView = createTexView(device, bcSize, gfx::Format::BC7_UNORM, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.101960786f, 0.0f, 1.0f)); - - texView = createTexView(device, bcSize, gfx::Format::BC7_UNORM_SRGB, &subData); - setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); - compareComputeResult( - device, - floatResults, - Slang::makeArray<float>(0.0f, 0.0103149414f, 0.0f, 1.0f)); - } + auto texView = createTexView(device, size, gfx::Format::BC1_UNORM, subData, 2); + setUpAndRunTest(device, texView, floatBufferView, "sampleMips", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.0f, 0.0f, 0.517647088f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f)); + + texView = createTexView(device, size, gfx::Format::BC1_UNORM_SRGB, subData, 2); + setUpAndRunTest(device, texView, floatBufferView, "sampleMips", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.0f, 0.0f, 0.230468750f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f)); } - SLANG_UNIT_TEST(FormatTestsD3D11) + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) { - runTestImpl(formatTestsImpl, unitTestContext, Slang::RenderApiFlag::D3D11); + uint8_t texData[] = + {255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, bcSize, gfx::Format::BC2_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.0f, 0.0f, 0.517647088f, 1.0f)); + + texView = createTexView(device, bcSize, gfx::Format::BC2_UNORM_SRGB, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.0f, 0.0f, 0.230468750f, 1.0f)); } -#if SLANG_WINDOWS_FAMILY - SLANG_UNIT_TEST(FormatTestsD3D12) + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) { - runTestImpl(formatTestsImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + uint8_t texData[] = + {0u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 16u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, bcSize, gfx::Format::BC3_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.0f, 0.0f, 0.517647088f, 1.0f)); + + texView = createTexView(device, bcSize, gfx::Format::BC3_UNORM_SRGB, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.0f, 0.0f, 0.230468750f, 1.0f)); } -#endif - SLANG_UNIT_TEST(FormatTestsVulkan) + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) { - runTestImpl(formatTestsImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + uint8_t texData[] = {127u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; + ITextureResource::SubresourceData subData = {(void*)texData, 8, 0}; + + auto texView = createTexView(device, bcSize, gfx::Format::BC4_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.498039216f, 0.0f, 0.0f, 1.0f)); + + texView = createTexView(device, bcSize, gfx::Format::BC4_SNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult(device, floatResults, Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f)); } + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = {127u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 127u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, bcSize, gfx::Format::BC5_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>( + 0.498039216f, + 0.498039216f, + 0.0f, + 1.0f, + 0.498039216f, + 0.498039216f, + 0.0f, + 1.0f)); + + texView = createTexView(device, bcSize, gfx::Format::BC5_SNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f)); + } + + // BC6H_UF16 and BC6H_SF16 are tested separately due to requiring different texture data. + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = { + 98u, + 238u, + 232u, + 77u, + 240u, + 66u, + 148u, + 31u, + 124u, + 95u, + 2u, + 224u, + 255u, + 107u, + 77u, + 250u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, bcSize, gfx::Format::BC6H_UF16, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.336669922f, 0.911132812f, 2.13867188f, 1.0f)); + } + + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = { + 107u, + 238u, + 232u, + 77u, + 240u, + 71u, + 128u, + 127u, + 1u, + 0u, + 255u, + 255u, + 170u, + 218u, + 221u, + 254u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, bcSize, gfx::Format::BC6H_SF16, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.336914062f, 0.910644531f, 2.14062500f, 1.0f)); + } + + // Ignore this test on swiftshader. Swiftshader produces different results than expected. + if (!Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) + { + uint8_t texData[] = + {104u, 0u, 0u, 0u, 64u, 163u, 209u, 104u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; + ITextureResource::SubresourceData subData = {(void*)texData, 16, 0}; + + auto texView = createTexView(device, bcSize, gfx::Format::BC7_UNORM, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.0f, 0.101960786f, 0.0f, 1.0f)); + + texView = createTexView(device, bcSize, gfx::Format::BC7_UNORM_SRGB, &subData); + setUpAndRunTest(device, texView, floatBufferView, "sampleTex", sampler); + compareComputeResult( + device, + floatResults, + Slang::makeArray<float>(0.0f, 0.0103149414f, 0.0f, 1.0f)); + } } + +SLANG_UNIT_TEST(FormatTestsD3D11) +{ + runTestImpl(formatTestsImpl, unitTestContext, Slang::RenderApiFlag::D3D11); +} + +#if SLANG_WINDOWS_FAMILY +SLANG_UNIT_TEST(FormatTestsD3D12) +{ + runTestImpl(formatTestsImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} +#endif + +SLANG_UNIT_TEST(FormatTestsVulkan) +{ + runTestImpl(formatTestsImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/get-buffer-resource-handle-test.cpp b/tools/gfx-unit-test/get-buffer-resource-handle-test.cpp index 36b6b3cad..a143ac135 100644 --- a/tools/gfx-unit-test/get-buffer-resource-handle-test.cpp +++ b/tools/gfx-unit-test/get-buffer-resource-handle-test.cpp @@ -1,9 +1,8 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" #if SLANG_WINDOWS_FAMILY #include <d3d12.h> @@ -13,97 +12,87 @@ using namespace gfx; namespace gfx_test { - void getBufferResourceHandleTestImpl(IDevice* device, UnitTestContext* context) - { - const int numberCount = 1; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; +void getBufferResourceHandleTestImpl(IDevice* device, UnitTestContext* context) +{ + const int numberCount = 1; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; - ComPtr<IBufferResource> buffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - nullptr, - buffer.writeRef())); + ComPtr<IBufferResource> buffer; + GFX_CHECK_CALL_ABORT(device->createBufferResource(bufferDesc, nullptr, buffer.writeRef())); - InteropHandle handle; - GFX_CHECK_CALL_ABORT(buffer->getNativeResourceHandle(&handle)); - if (device->getDeviceInfo().deviceType == gfx::DeviceType::Vulkan) - { - SLANG_CHECK(handle.handleValue != 0); - SLANG_CHECK(handle.api == InteropHandleAPI::Vulkan); - } + InteropHandle handle; + GFX_CHECK_CALL_ABORT(buffer->getNativeResourceHandle(&handle)); + if (device->getDeviceInfo().deviceType == gfx::DeviceType::Vulkan) + { + SLANG_CHECK(handle.handleValue != 0); + SLANG_CHECK(handle.api == InteropHandleAPI::Vulkan); + } #if SLANG_WINDOWS_FAMILY - else - { - SLANG_CHECK(handle.api == InteropHandleAPI::D3D12); - auto d3d12Handle = (ID3D12Resource*)handle.handleValue; - Slang::ComPtr<IUnknown> testHandle1; - GFX_CHECK_CALL_ABORT(d3d12Handle->QueryInterface<IUnknown>(testHandle1.writeRef())); - Slang::ComPtr<ID3D12Resource> testHandle2; - GFX_CHECK_CALL_ABORT(testHandle1->QueryInterface<ID3D12Resource>(testHandle2.writeRef())); - SLANG_CHECK(d3d12Handle == testHandle2.get()); - } -#endif + else + { + SLANG_CHECK(handle.api == InteropHandleAPI::D3D12); + auto d3d12Handle = (ID3D12Resource*)handle.handleValue; + Slang::ComPtr<IUnknown> testHandle1; + GFX_CHECK_CALL_ABORT(d3d12Handle->QueryInterface<IUnknown>(testHandle1.writeRef())); + Slang::ComPtr<ID3D12Resource> testHandle2; + GFX_CHECK_CALL_ABORT(testHandle1->QueryInterface<ID3D12Resource>(testHandle2.writeRef())); + SLANG_CHECK(d3d12Handle == testHandle2.get()); } +#endif +} - void getBufferResourceHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +void getBufferResourceHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +{ + if ((api & context->enabledApis) == 0) { - if ((api & context->enabledApis) == 0) - { - SLANG_IGNORE_TEST; - } - Slang::ComPtr<IDevice> device; - IDevice::Desc deviceDesc = {}; - switch (api) - { - case Slang::RenderApiFlag::D3D11: - deviceDesc.deviceType = gfx::DeviceType::DirectX11; - break; - case Slang::RenderApiFlag::D3D12: - deviceDesc.deviceType = gfx::DeviceType::DirectX12; - break; - case Slang::RenderApiFlag::Vulkan: - deviceDesc.deviceType = gfx::DeviceType::Vulkan; - break; - default: - SLANG_IGNORE_TEST; - } - deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; - const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" }; - deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); - deviceDesc.slang.searchPaths = searchPaths; - auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); - if (SLANG_FAILED(createDeviceResult)) - { - SLANG_IGNORE_TEST; - } - // Ignore this test on swiftshader. Swiftshader seems to have a bug that causes the test - // to crash. - if (Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - SLANG_IGNORE_TEST; - } - - getBufferResourceHandleTestImpl(device, context); + SLANG_IGNORE_TEST; } - - SLANG_UNIT_TEST(getBufferResourceHandleD3D12) + Slang::ComPtr<IDevice> device; + IDevice::Desc deviceDesc = {}; + switch (api) { - return getBufferResourceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); + case Slang::RenderApiFlag::D3D11: deviceDesc.deviceType = gfx::DeviceType::DirectX11; break; + case Slang::RenderApiFlag::D3D12: deviceDesc.deviceType = gfx::DeviceType::DirectX12; break; + case Slang::RenderApiFlag::Vulkan: deviceDesc.deviceType = gfx::DeviceType::Vulkan; break; + default: SLANG_IGNORE_TEST; } - - SLANG_UNIT_TEST(getBufferResourceHandleVulkan) + deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; + const char* searchPaths[] = {"", "../../tools/gfx-unit-test", "tools/gfx-unit-test"}; + deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); + deviceDesc.slang.searchPaths = searchPaths; + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); + if (SLANG_FAILED(createDeviceResult)) + { + SLANG_IGNORE_TEST; + } + // Ignore this test on swiftshader. Swiftshader seems to have a bug that causes the test + // to crash. + if (Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) { - return getBufferResourceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); + SLANG_IGNORE_TEST; } + getBufferResourceHandleTestImpl(device, context); } + +SLANG_UNIT_TEST(getBufferResourceHandleD3D12) +{ + return getBufferResourceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(getBufferResourceHandleVulkan) +{ + return getBufferResourceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/get-cmd-buffer-handle-test.cpp b/tools/gfx-unit-test/get-cmd-buffer-handle-test.cpp index 120c331ed..cd9a401f7 100644 --- a/tools/gfx-unit-test/get-cmd-buffer-handle-test.cpp +++ b/tools/gfx-unit-test/get-cmd-buffer-handle-test.cpp @@ -1,9 +1,8 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" #if SLANG_WINDOWS_FAMILY #include <d3d12.h> @@ -13,93 +12,84 @@ using namespace gfx; namespace gfx_test { - void getBufferHandleTestImpl(IDevice* device, UnitTestContext* context) - { - // We need to create a transient heap in order to create a command buffer. - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - auto commandBuffer = transientHeap->createCommandBuffer(); - struct CloseComandBufferRAII - { - ICommandBuffer* m_commandBuffer; - ~CloseComandBufferRAII() - { - m_commandBuffer->close(); - } - } closeCommandBufferRAII{ commandBuffer }; - InteropHandle handle = {}; - GFX_CHECK_CALL_ABORT(commandBuffer->getNativeHandle(&handle)); - if (device->getDeviceInfo().deviceType == gfx::DeviceType::Vulkan) - { - SLANG_CHECK(handle.handleValue != 0); - } -#if SLANG_WINDOWS_FAMILY - else - { - auto d3d12Handle = (ID3D12GraphicsCommandList*)handle.handleValue; - Slang::ComPtr<IUnknown> testHandle1; - GFX_CHECK_CALL_ABORT(d3d12Handle->QueryInterface<IUnknown>(testHandle1.writeRef())); - Slang::ComPtr<ID3D12GraphicsCommandList> testHandle2; - GFX_CHECK_CALL_ABORT(d3d12Handle->QueryInterface<ID3D12GraphicsCommandList>(testHandle2.writeRef())); - SLANG_CHECK(d3d12Handle == testHandle2.get()); - } -#endif - } +void getBufferHandleTestImpl(IDevice* device, UnitTestContext* context) +{ + // We need to create a transient heap in order to create a command buffer. + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - void getBufferHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) + auto commandBuffer = transientHeap->createCommandBuffer(); + struct CloseComandBufferRAII + { + ICommandBuffer* m_commandBuffer; + ~CloseComandBufferRAII() { m_commandBuffer->close(); } + } closeCommandBufferRAII{commandBuffer}; + InteropHandle handle = {}; + GFX_CHECK_CALL_ABORT(commandBuffer->getNativeHandle(&handle)); + if (device->getDeviceInfo().deviceType == gfx::DeviceType::Vulkan) { - if ((api & context->enabledApis) == 0) - { - SLANG_IGNORE_TEST; - } - Slang::ComPtr<IDevice> device; - IDevice::Desc deviceDesc = {}; - switch (api) - { - case Slang::RenderApiFlag::D3D11: - deviceDesc.deviceType = gfx::DeviceType::DirectX11; - break; - case Slang::RenderApiFlag::D3D12: - deviceDesc.deviceType = gfx::DeviceType::DirectX12; - break; - case Slang::RenderApiFlag::Vulkan: - deviceDesc.deviceType = gfx::DeviceType::Vulkan; - break; - default: - SLANG_IGNORE_TEST; - } - deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; - const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" }; - deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); - deviceDesc.slang.searchPaths = searchPaths; - auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); - if (SLANG_FAILED(createDeviceResult)) - { - SLANG_IGNORE_TEST; - } - // Ignore this test on swiftshader. Swiftshader seems to have a bug that causes the test - // to crash. - if (Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - SLANG_IGNORE_TEST; - } - getBufferHandleTestImpl(device, context); + SLANG_CHECK(handle.handleValue != 0); } - #if SLANG_WINDOWS_FAMILY - SLANG_UNIT_TEST(getCmdBufferHandleD3D12) + else { - return getBufferHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); + auto d3d12Handle = (ID3D12GraphicsCommandList*)handle.handleValue; + Slang::ComPtr<IUnknown> testHandle1; + GFX_CHECK_CALL_ABORT(d3d12Handle->QueryInterface<IUnknown>(testHandle1.writeRef())); + Slang::ComPtr<ID3D12GraphicsCommandList> testHandle2; + GFX_CHECK_CALL_ABORT( + d3d12Handle->QueryInterface<ID3D12GraphicsCommandList>(testHandle2.writeRef())); + SLANG_CHECK(d3d12Handle == testHandle2.get()); } #endif +} - SLANG_UNIT_TEST(getCmdBufferHandleVulkan) +void getBufferHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +{ + if ((api & context->enabledApis) == 0) + { + SLANG_IGNORE_TEST; + } + Slang::ComPtr<IDevice> device; + IDevice::Desc deviceDesc = {}; + switch (api) + { + case Slang::RenderApiFlag::D3D11: deviceDesc.deviceType = gfx::DeviceType::DirectX11; break; + case Slang::RenderApiFlag::D3D12: deviceDesc.deviceType = gfx::DeviceType::DirectX12; break; + case Slang::RenderApiFlag::Vulkan: deviceDesc.deviceType = gfx::DeviceType::Vulkan; break; + default: SLANG_IGNORE_TEST; + } + deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; + const char* searchPaths[] = {"", "../../tools/gfx-unit-test", "tools/gfx-unit-test"}; + deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); + deviceDesc.slang.searchPaths = searchPaths; + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); + if (SLANG_FAILED(createDeviceResult)) + { + SLANG_IGNORE_TEST; + } + // Ignore this test on swiftshader. Swiftshader seems to have a bug that causes the test + // to crash. + if (Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) { - return getBufferHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); + SLANG_IGNORE_TEST; } + getBufferHandleTestImpl(device, context); +} + +#if SLANG_WINDOWS_FAMILY +SLANG_UNIT_TEST(getCmdBufferHandleD3D12) +{ + return getBufferHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); +} +#endif +SLANG_UNIT_TEST(getCmdBufferHandleVulkan) +{ + return getBufferHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/get-cmd-queue-handle-test.cpp b/tools/gfx-unit-test/get-cmd-queue-handle-test.cpp index e14729718..8e589a899 100644 --- a/tools/gfx-unit-test/get-cmd-queue-handle-test.cpp +++ b/tools/gfx-unit-test/get-cmd-queue-handle-test.cpp @@ -1,9 +1,8 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" #if SLANG_WINDOWS_FAMILY #include <d3d12.h> @@ -13,77 +12,71 @@ using namespace gfx; namespace gfx_test { - void getQueueHandleTestImpl(IDevice* device, UnitTestContext* context) +void getQueueHandleTestImpl(IDevice* device, UnitTestContext* context) +{ + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + InteropHandle handle; + GFX_CHECK_CALL_ABORT(queue->getNativeHandle(&handle)); + if (device->getDeviceInfo().deviceType == gfx::DeviceType::Vulkan) { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - InteropHandle handle; - GFX_CHECK_CALL_ABORT(queue->getNativeHandle(&handle)); - if (device->getDeviceInfo().deviceType == gfx::DeviceType::Vulkan) - { - SLANG_CHECK(handle.handleValue != 0); - } + SLANG_CHECK(handle.handleValue != 0); + } #if SLANG_WINDOWS_FAMILY - else - { - auto d3d12Queue = (ID3D12CommandQueue*)handle.handleValue; - Slang::ComPtr<IUnknown> testHandle1; - GFX_CHECK_CALL_ABORT(d3d12Queue->QueryInterface<IUnknown>(testHandle1.writeRef())); - Slang::ComPtr<ID3D12CommandQueue> testHandle2; - GFX_CHECK_CALL_ABORT(testHandle1->QueryInterface<ID3D12CommandQueue>(testHandle2.writeRef())); - SLANG_CHECK(d3d12Queue == testHandle2.get()); - } -#endif + else + { + auto d3d12Queue = (ID3D12CommandQueue*)handle.handleValue; + Slang::ComPtr<IUnknown> testHandle1; + GFX_CHECK_CALL_ABORT(d3d12Queue->QueryInterface<IUnknown>(testHandle1.writeRef())); + Slang::ComPtr<ID3D12CommandQueue> testHandle2; + GFX_CHECK_CALL_ABORT( + testHandle1->QueryInterface<ID3D12CommandQueue>(testHandle2.writeRef())); + SLANG_CHECK(d3d12Queue == testHandle2.get()); } +#endif +} - void getQueueHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +void getQueueHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +{ + if ((api & context->enabledApis) == 0) { - if ((api & context->enabledApis) == 0) - { - SLANG_IGNORE_TEST; - } - Slang::ComPtr<IDevice> device; - IDevice::Desc deviceDesc = {}; - switch (api) - { - case Slang::RenderApiFlag::D3D11: - deviceDesc.deviceType = gfx::DeviceType::DirectX11; - break; - case Slang::RenderApiFlag::D3D12: - deviceDesc.deviceType = gfx::DeviceType::DirectX12; - break; - case Slang::RenderApiFlag::Vulkan: - deviceDesc.deviceType = gfx::DeviceType::Vulkan; - break; - default: - SLANG_IGNORE_TEST; - } - deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; - const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" }; - deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); - deviceDesc.slang.searchPaths = searchPaths; - auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); - if (SLANG_FAILED(createDeviceResult)) - { - SLANG_IGNORE_TEST; - } - // Ignore this test on swiftshader. Swiftshader seems to have a bug that causes the test - // to crash. - if (Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - SLANG_IGNORE_TEST; - } - getQueueHandleTestImpl(device, context); + SLANG_IGNORE_TEST; } - - SLANG_UNIT_TEST(getCmdQueueHandleD3D12) + Slang::ComPtr<IDevice> device; + IDevice::Desc deviceDesc = {}; + switch (api) { - return getQueueHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); + case Slang::RenderApiFlag::D3D11: deviceDesc.deviceType = gfx::DeviceType::DirectX11; break; + case Slang::RenderApiFlag::D3D12: deviceDesc.deviceType = gfx::DeviceType::DirectX12; break; + case Slang::RenderApiFlag::Vulkan: deviceDesc.deviceType = gfx::DeviceType::Vulkan; break; + default: SLANG_IGNORE_TEST; } - - SLANG_UNIT_TEST(getCmdQueueHandleVulkan) + deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; + const char* searchPaths[] = {"", "../../tools/gfx-unit-test", "tools/gfx-unit-test"}; + deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); + deviceDesc.slang.searchPaths = searchPaths; + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); + if (SLANG_FAILED(createDeviceResult)) + { + SLANG_IGNORE_TEST; + } + // Ignore this test on swiftshader. Swiftshader seems to have a bug that causes the test + // to crash. + if (Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) { - return getQueueHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); + SLANG_IGNORE_TEST; } + getQueueHandleTestImpl(device, context); +} + +SLANG_UNIT_TEST(getCmdQueueHandleD3D12) +{ + return getQueueHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); +} +SLANG_UNIT_TEST(getCmdQueueHandleVulkan) +{ + return getQueueHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/get-supported-resource-states-test.cpp b/tools/gfx-unit-test/get-supported-resource-states-test.cpp index fc7c57771..a3f331384 100644 --- a/tools/gfx-unit-test/get-supported-resource-states-test.cpp +++ b/tools/gfx-unit-test/get-supported-resource-states-test.cpp @@ -1,9 +1,8 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" #if SLANG_WINDOWS_FAMILY #include <d3d12.h> @@ -14,195 +13,181 @@ using namespace gfx; namespace { - using namespace gfx_test; +using namespace gfx_test; - struct GetSupportedResourceStatesBase - { - IDevice* device; - UnitTestContext* context; +struct GetSupportedResourceStatesBase +{ + IDevice* device; + UnitTestContext* context; - ResourceStateSet formatSupportedStates; - ResourceStateSet textureAllowedStates; - ResourceStateSet bufferAllowedStates; + ResourceStateSet formatSupportedStates; + ResourceStateSet textureAllowedStates; + ResourceStateSet bufferAllowedStates; - ComPtr<ITextureResource> texture; - ComPtr<IBufferResource> buffer; + ComPtr<ITextureResource> texture; + ComPtr<IBufferResource> buffer; - void init(IDevice* device, UnitTestContext* context) - { - this->device = device; - this->context = context; - } + void init(IDevice* device, UnitTestContext* context) + { + this->device = device; + this->context = context; + } - Format convertTypelessFormat(Format format) + Format convertTypelessFormat(Format format) + { + switch (format) { - switch (format) - { - case Format::R32G32B32A32_TYPELESS: - return Format::R32G32B32A32_FLOAT; - case Format::R32G32B32_TYPELESS: - return Format::R32G32B32_FLOAT; - case Format::R32G32_TYPELESS: - return Format::R32G32_FLOAT; - case Format::R32_TYPELESS: - return Format::R32_FLOAT; - case Format::R16G16B16A16_TYPELESS: - return Format::R16G16B16A16_FLOAT; - case Format::R16G16_TYPELESS: - return Format::R16G16_FLOAT; - case Format::R16_TYPELESS: - return Format::R16_FLOAT; - case Format::R8G8B8A8_TYPELESS: - return Format::R8G8B8A8_UNORM; - case Format::R8G8_TYPELESS: - return Format::R8G8_UNORM; - case Format::R8_TYPELESS: - return Format::R8_UNORM; - case Format::B8G8R8A8_TYPELESS: - return Format::B8G8R8A8_UNORM; - case Format::R10G10B10A2_TYPELESS: - return Format::R10G10B10A2_UINT; - default: - return Format::Unknown; - } + case Format::R32G32B32A32_TYPELESS: return Format::R32G32B32A32_FLOAT; + case Format::R32G32B32_TYPELESS: return Format::R32G32B32_FLOAT; + case Format::R32G32_TYPELESS: return Format::R32G32_FLOAT; + case Format::R32_TYPELESS: return Format::R32_FLOAT; + case Format::R16G16B16A16_TYPELESS: return Format::R16G16B16A16_FLOAT; + case Format::R16G16_TYPELESS: return Format::R16G16_FLOAT; + case Format::R16_TYPELESS: return Format::R16_FLOAT; + case Format::R8G8B8A8_TYPELESS: return Format::R8G8B8A8_UNORM; + case Format::R8G8_TYPELESS: return Format::R8G8_UNORM; + case Format::R8_TYPELESS: return Format::R8_UNORM; + case Format::B8G8R8A8_TYPELESS: return Format::B8G8R8A8_UNORM; + case Format::R10G10B10A2_TYPELESS: return Format::R10G10B10A2_UINT; + default: return Format::Unknown; } + } - void transitionResourceStates(IDevice* device) - { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + void transitionResourceStates(IDevice* device) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeResourceCommands(); - ResourceState currentTextureState = texture->getDesc()->defaultState; - ResourceState currentBufferState = buffer->getDesc()->defaultState; + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeResourceCommands(); + ResourceState currentTextureState = texture->getDesc()->defaultState; + ResourceState currentBufferState = buffer->getDesc()->defaultState; - for (uint32_t i = 0; i < (uint32_t)ResourceState::_Count; ++i) + for (uint32_t i = 0; i < (uint32_t)ResourceState::_Count; ++i) + { + auto nextState = (ResourceState)i; + if (formatSupportedStates.contains(nextState)) { - auto nextState = (ResourceState)i; - if (formatSupportedStates.contains(nextState)) + if (bufferAllowedStates.contains(nextState)) + { + encoder->bufferBarrier(buffer, currentBufferState, nextState); + currentBufferState = nextState; + } + if (textureAllowedStates.contains(nextState)) { - if (bufferAllowedStates.contains(nextState)) - { - encoder->bufferBarrier(buffer, currentBufferState, nextState); - currentBufferState = nextState; - } - if (textureAllowedStates.contains(nextState)) - { - encoder->textureBarrier(texture, currentTextureState, nextState); - currentTextureState = nextState; - } + encoder->textureBarrier(texture, currentTextureState, nextState); + currentTextureState = nextState; } } - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); } + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - void run() + void run() + { + // Skip Format::Unknown + for (uint32_t i = 1; i < (uint32_t)Format::_Count; ++i) { - // Skip Format::Unknown - for (uint32_t i = 1; i < (uint32_t)Format::_Count; ++i) - { - auto baseFormat = (Format)i; - FormatInfo info; - gfxGetFormatInfo(baseFormat, &info); - // Ignore 3-channel textures for now since validation layer seem to report unsupported errors there. - if (info.channelCount == 3) - continue; - - auto format = gfxIsTypelessFormat(baseFormat) ? convertTypelessFormat(baseFormat) : baseFormat; - GFX_CHECK_CALL_ABORT(device->getFormatSupportedResourceStates(format, &formatSupportedStates)); - - textureAllowedStates.add( - ResourceState::RenderTarget, - ResourceState::DepthRead, - ResourceState::DepthWrite, - ResourceState::Present, - ResourceState::ResolveSource, - ResourceState::ResolveDestination, - ResourceState::Undefined, - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopySource, - ResourceState::CopyDestination); - - bufferAllowedStates.add( - ResourceState::VertexBuffer, - ResourceState::IndexBuffer, - ResourceState::ConstantBuffer, - ResourceState::StreamOutput, - ResourceState::IndirectArgument, - ResourceState::AccelerationStructure, - ResourceState::Undefined, - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopySource, - ResourceState::CopyDestination); - - ResourceState currentState = ResourceState::CopySource; - ITextureResource::Extents extent; - extent.width = 4; - extent.height = 4; - extent.depth = 1; - - ITextureResource::Desc texDesc = {}; - texDesc.type = IResource::Type::Texture2D; - texDesc.numMipLevels = 1; - texDesc.arraySize = 1; - texDesc.size = extent; - texDesc.defaultState = currentState; - texDesc.allowedStates = formatSupportedStates & textureAllowedStates; - texDesc.memoryType = MemoryType::DeviceLocal; - texDesc.format = format; - - GFX_CHECK_CALL_ABORT(device->createTextureResource( - texDesc, - nullptr, - texture.writeRef())); - - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = 256; - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = formatSupportedStates & bufferAllowedStates; - bufferDesc.defaultState = currentState; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - nullptr, - buffer.writeRef())); - - transitionResourceStates(device); - } - } - }; + auto baseFormat = (Format)i; + FormatInfo info; + gfxGetFormatInfo(baseFormat, &info); + // Ignore 3-channel textures for now since validation layer seem to report unsupported + // errors there. + if (info.channelCount == 3) + continue; + + auto format = + gfxIsTypelessFormat(baseFormat) ? convertTypelessFormat(baseFormat) : baseFormat; + GFX_CHECK_CALL_ABORT( + device->getFormatSupportedResourceStates(format, &formatSupportedStates)); + + textureAllowedStates.add( + ResourceState::RenderTarget, + ResourceState::DepthRead, + ResourceState::DepthWrite, + ResourceState::Present, + ResourceState::ResolveSource, + ResourceState::ResolveDestination, + ResourceState::Undefined, + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopySource, + ResourceState::CopyDestination); + + bufferAllowedStates.add( + ResourceState::VertexBuffer, + ResourceState::IndexBuffer, + ResourceState::ConstantBuffer, + ResourceState::StreamOutput, + ResourceState::IndirectArgument, + ResourceState::AccelerationStructure, + ResourceState::Undefined, + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopySource, + ResourceState::CopyDestination); + + ResourceState currentState = ResourceState::CopySource; + ITextureResource::Extents extent; + extent.width = 4; + extent.height = 4; + extent.depth = 1; + + ITextureResource::Desc texDesc = {}; + texDesc.type = IResource::Type::Texture2D; + texDesc.numMipLevels = 1; + texDesc.arraySize = 1; + texDesc.size = extent; + texDesc.defaultState = currentState; + texDesc.allowedStates = formatSupportedStates & textureAllowedStates; + texDesc.memoryType = MemoryType::DeviceLocal; + texDesc.format = format; - void supportedResourceStatesTestImpl(IDevice* device, UnitTestContext* context) - { - GetSupportedResourceStatesBase test; - test.init(device, context); - test.run(); + GFX_CHECK_CALL_ABORT( + device->createTextureResource(texDesc, nullptr, texture.writeRef())); + + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = 256; + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = formatSupportedStates & bufferAllowedStates; + bufferDesc.defaultState = currentState; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, nullptr, buffer.writeRef())); + + transitionResourceStates(device); + } } +}; + +void supportedResourceStatesTestImpl(IDevice* device, UnitTestContext* context) +{ + GetSupportedResourceStatesBase test; + test.init(device, context); + test.run(); } +} // namespace namespace gfx_test { - SLANG_UNIT_TEST(getSupportedResourceStatesD3D12) - { - runTestImpl(supportedResourceStatesTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } +SLANG_UNIT_TEST(getSupportedResourceStatesD3D12) +{ + runTestImpl(supportedResourceStatesTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} - SLANG_UNIT_TEST(getSupportedResourceStatesVulkan) - { - runTestImpl(supportedResourceStatesTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(getSupportedResourceStatesVulkan) +{ + runTestImpl(supportedResourceStatesTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/get-texture-resource-handle-test.cpp b/tools/gfx-unit-test/get-texture-resource-handle-test.cpp index 6b4862707..238d5a4fe 100644 --- a/tools/gfx-unit-test/get-texture-resource-handle-test.cpp +++ b/tools/gfx-unit-test/get-texture-resource-handle-test.cpp @@ -1,9 +1,8 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" #if SLANG_WINDOWS_FAMILY #include <d3d12.h> @@ -13,90 +12,83 @@ using namespace gfx; namespace gfx_test { - void getTextureResourceHandleTestImpl(IDevice* device, UnitTestContext* context) - { - ITextureResource::Desc desc = {}; - desc.type = IResource::Type::Texture2D; - desc.numMipLevels = 1; - desc.size.width = 1; - desc.size.height = 1; - desc.size.depth = 1; - desc.defaultState = ResourceState::UnorderedAccess; - desc.format = Format::R16G16B16A16_FLOAT; +void getTextureResourceHandleTestImpl(IDevice* device, UnitTestContext* context) +{ + ITextureResource::Desc desc = {}; + desc.type = IResource::Type::Texture2D; + desc.numMipLevels = 1; + desc.size.width = 1; + desc.size.height = 1; + desc.size.depth = 1; + desc.defaultState = ResourceState::UnorderedAccess; + desc.format = Format::R16G16B16A16_FLOAT; - Slang::ComPtr<ITextureResource> buffer; - buffer = device->createTextureResource(desc); + Slang::ComPtr<ITextureResource> buffer; + buffer = device->createTextureResource(desc); - InteropHandle handle; - GFX_CHECK_CALL_ABORT(buffer->getNativeResourceHandle(&handle)); - if (device->getDeviceInfo().deviceType == gfx::DeviceType::Vulkan) - { - SLANG_CHECK(handle.handleValue != 0); - SLANG_CHECK(handle.api == InteropHandleAPI::Vulkan); - } + InteropHandle handle; + GFX_CHECK_CALL_ABORT(buffer->getNativeResourceHandle(&handle)); + if (device->getDeviceInfo().deviceType == gfx::DeviceType::Vulkan) + { + SLANG_CHECK(handle.handleValue != 0); + SLANG_CHECK(handle.api == InteropHandleAPI::Vulkan); + } #if SLANG_WINDOWS_FAMILY - else - { - SLANG_CHECK(handle.api == InteropHandleAPI::D3D12); - auto d3d12Handle = (ID3D12Resource*)handle.handleValue; - Slang::ComPtr<IUnknown> testHandle1; - GFX_CHECK_CALL_ABORT(d3d12Handle->QueryInterface<IUnknown>(testHandle1.writeRef())); - Slang::ComPtr<ID3D12Resource> testHandle2; - GFX_CHECK_CALL_ABORT(testHandle1->QueryInterface<ID3D12Resource>(testHandle2.writeRef())); - SLANG_CHECK(d3d12Handle == testHandle2.get()); - } -#endif + else + { + SLANG_CHECK(handle.api == InteropHandleAPI::D3D12); + auto d3d12Handle = (ID3D12Resource*)handle.handleValue; + Slang::ComPtr<IUnknown> testHandle1; + GFX_CHECK_CALL_ABORT(d3d12Handle->QueryInterface<IUnknown>(testHandle1.writeRef())); + Slang::ComPtr<ID3D12Resource> testHandle2; + GFX_CHECK_CALL_ABORT(testHandle1->QueryInterface<ID3D12Resource>(testHandle2.writeRef())); + SLANG_CHECK(d3d12Handle == testHandle2.get()); } +#endif +} - void getTextureResourceHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +void getTextureResourceHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +{ + if ((api & context->enabledApis) == 0) { - if ((api & context->enabledApis) == 0) - { - SLANG_IGNORE_TEST; - } - Slang::ComPtr<IDevice> device; - IDevice::Desc deviceDesc = {}; - switch (api) - { - case Slang::RenderApiFlag::D3D11: - deviceDesc.deviceType = gfx::DeviceType::DirectX11; - break; - case Slang::RenderApiFlag::D3D12: - deviceDesc.deviceType = gfx::DeviceType::DirectX12; - break; - case Slang::RenderApiFlag::Vulkan: - deviceDesc.deviceType = gfx::DeviceType::Vulkan; - break; - default: - SLANG_IGNORE_TEST; - } - deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; - const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" }; - deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); - deviceDesc.slang.searchPaths = searchPaths; - auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); - if (SLANG_FAILED(createDeviceResult)) - { - SLANG_IGNORE_TEST; - } - // Ignore this test on swiftshader. Swiftshader seems to have a bug that causes the test - // to crash. - if (Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) - { - SLANG_IGNORE_TEST; - } - getTextureResourceHandleTestImpl(device, context); + SLANG_IGNORE_TEST; } - - SLANG_UNIT_TEST(getTextureResourceHandleD3D12) + Slang::ComPtr<IDevice> device; + IDevice::Desc deviceDesc = {}; + switch (api) { - return getTextureResourceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); + case Slang::RenderApiFlag::D3D11: deviceDesc.deviceType = gfx::DeviceType::DirectX11; break; + case Slang::RenderApiFlag::D3D12: deviceDesc.deviceType = gfx::DeviceType::DirectX12; break; + case Slang::RenderApiFlag::Vulkan: deviceDesc.deviceType = gfx::DeviceType::Vulkan; break; + default: SLANG_IGNORE_TEST; } - - SLANG_UNIT_TEST(getTextureResourceHandleVulkan) + deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; + const char* searchPaths[] = {"", "../../tools/gfx-unit-test", "tools/gfx-unit-test"}; + deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); + deviceDesc.slang.searchPaths = searchPaths; + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); + if (SLANG_FAILED(createDeviceResult)) + { + SLANG_IGNORE_TEST; + } + // Ignore this test on swiftshader. Swiftshader seems to have a bug that causes the test + // to crash. + if (Slang::String(device->getDeviceInfo().adapterName).toLower().contains("swiftshader")) { - return getTextureResourceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); + SLANG_IGNORE_TEST; } + getTextureResourceHandleTestImpl(device, context); +} + +SLANG_UNIT_TEST(getTextureResourceHandleD3D12) +{ + return getTextureResourceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12); +} +SLANG_UNIT_TEST(getTextureResourceHandleVulkan) +{ + return getTextureResourceHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/gfx-test-texture-util.cpp b/tools/gfx-unit-test/gfx-test-texture-util.cpp index 21e82ab22..a4f86d1d8 100644 --- a/tools/gfx-unit-test/gfx-test-texture-util.cpp +++ b/tools/gfx-unit-test/gfx-test-texture-util.cpp @@ -1,15 +1,15 @@ #include "gfx-test-texture-util.h" -#include "gfx-test-util.h" -#include "tools/unit-test/slang-unit-test.h" +#include "gfx-test-util.h" #include "slang-com-ptr.h" +#include "tools/unit-test/slang-unit-test.h" -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable: 4996) +#pragma warning(disable : 4996) #endif #define STB_IMAGE_WRITE_IMPLEMENTATION #include "external/stb/stb_image_write.h" @@ -20,8 +20,9 @@ #define GFX_ENABLE_RENDERDOC_INTEGRATION 0 #if GFX_ENABLE_RENDERDOC_INTEGRATION -# include "external/renderdoc_app.h" -# include <windows.h> +#include "external/renderdoc_app.h" + +#include <windows.h> #endif using namespace Slang; @@ -29,232 +30,235 @@ using namespace gfx; namespace gfx_test { - TextureAspect getTextureAspect(Format format) +TextureAspect getTextureAspect(Format format) +{ + switch (format) { - switch (format) - { - case Format::D16_UNORM: - case Format::D32_FLOAT: - return TextureAspect::Depth; - default: - return TextureAspect::Color; - } + case Format::D16_UNORM: + case Format::D32_FLOAT: return TextureAspect::Depth; + default: return TextureAspect::Color; } +} - Size getTexelSize(Format format) - { - FormatInfo info; - GFX_CHECK_CALL_ABORT(gfxGetFormatInfo(format, &info)); - return info.blockSizeInBytes / info.pixelsPerBlock; - } +Size getTexelSize(Format format) +{ + FormatInfo info; + GFX_CHECK_CALL_ABORT(gfxGetFormatInfo(format, &info)); + return info.blockSizeInBytes / info.pixelsPerBlock; +} - GfxIndex getSubresourceIndex(GfxIndex mipLevel, GfxCount mipLevelCount, GfxIndex baseArrayLayer) - { - return baseArrayLayer * mipLevelCount + mipLevel; - } +GfxIndex getSubresourceIndex(GfxIndex mipLevel, GfxCount mipLevelCount, GfxIndex baseArrayLayer) +{ + return baseArrayLayer * mipLevelCount + mipLevel; +} - RefPtr<ValidationTextureFormatBase> getValidationTextureFormat(Format format) +RefPtr<ValidationTextureFormatBase> getValidationTextureFormat(Format format) +{ + switch (format) { - switch (format) - { - case Format::R32G32B32A32_TYPELESS: return new ValidationTextureFormat<uint32_t>(4); - case Format::R32G32B32_TYPELESS: return new ValidationTextureFormat<uint32_t>(3); - case Format::R32G32_TYPELESS: return new ValidationTextureFormat<uint32_t>(2); - case Format::R32_TYPELESS: return new ValidationTextureFormat<uint32_t>(1); - - case Format::R16G16B16A16_TYPELESS: return new ValidationTextureFormat<uint16_t>(4); - case Format::R16G16_TYPELESS: return new ValidationTextureFormat<uint16_t>(2); - case Format::R16_TYPELESS: return new ValidationTextureFormat<uint16_t>(1); - - case Format::R8G8B8A8_TYPELESS: return new ValidationTextureFormat<uint8_t>(4); - case Format::R8G8_TYPELESS: return new ValidationTextureFormat<uint8_t>(2); - case Format::R8_TYPELESS: return new ValidationTextureFormat<uint8_t>(1); - case Format::B8G8R8A8_TYPELESS: return new ValidationTextureFormat<uint8_t>(4); - - case Format::R32G32B32A32_FLOAT: return new ValidationTextureFormat<float>(4); - case Format::R32G32B32_FLOAT: return new ValidationTextureFormat<float>(3); - case Format::R32G32_FLOAT: return new ValidationTextureFormat<float>(2); - case Format::R32_FLOAT: return new ValidationTextureFormat<float>(1); - - case Format::R16G16B16A16_FLOAT: return new ValidationTextureFormat<uint16_t>(4); - case Format::R16G16_FLOAT: return new ValidationTextureFormat<uint16_t>(2); - case Format::R16_FLOAT: return new ValidationTextureFormat<uint16_t>(1); - - case Format::R64_UINT: return new ValidationTextureFormat<uint64_t>(1); - - case Format::R32G32B32A32_UINT: return new ValidationTextureFormat<uint32_t>(4); - case Format::R32G32B32_UINT: return new ValidationTextureFormat<uint32_t>(3); - case Format::R32G32_UINT: return new ValidationTextureFormat<uint32_t>(2); - case Format::R32_UINT: return new ValidationTextureFormat<uint32_t>(1); - - case Format::R16G16B16A16_UINT: return new ValidationTextureFormat<uint16_t>(4); - case Format::R16G16_UINT: return new ValidationTextureFormat<uint16_t>(2); - case Format::R16_UINT: return new ValidationTextureFormat<uint16_t>(1); - - case Format::R8G8B8A8_UINT: return new ValidationTextureFormat<uint8_t>(4); - case Format::R8G8_UINT: return new ValidationTextureFormat<uint8_t>(2); - case Format::R8_UINT: return new ValidationTextureFormat<uint8_t>(1); - - case Format::R64_SINT: return new ValidationTextureFormat<int64_t>(1); - - case Format::R32G32B32A32_SINT: return new ValidationTextureFormat<int32_t>(4); - case Format::R32G32B32_SINT: return new ValidationTextureFormat<int32_t>(3); - case Format::R32G32_SINT: return new ValidationTextureFormat<int32_t>(2); - case Format::R32_SINT: return new ValidationTextureFormat<int32_t>(1); - - case Format::R16G16B16A16_SINT: return new ValidationTextureFormat<int16_t>(4); - case Format::R16G16_SINT: return new ValidationTextureFormat<int16_t>(2); - case Format::R16_SINT: return new ValidationTextureFormat<int16_t>(1); - - case Format::R8G8B8A8_SINT: return new ValidationTextureFormat<int8_t>(4); - case Format::R8G8_SINT: return new ValidationTextureFormat<int8_t>(2); - case Format::R8_SINT: return new ValidationTextureFormat<int8_t>(1); - - case Format::R16G16B16A16_UNORM: return new ValidationTextureFormat<uint16_t>(4); - case Format::R16G16_UNORM: return new ValidationTextureFormat<uint16_t>(2); - case Format::R16_UNORM: return new ValidationTextureFormat<uint16_t>(1); - - case Format::R8G8B8A8_UNORM: return new ValidationTextureFormat<uint8_t>(4); - case Format::R8G8B8A8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(4); - case Format::R8G8_UNORM: return new ValidationTextureFormat<uint8_t>(2); - case Format::R8_UNORM: return new ValidationTextureFormat<uint8_t>(1); - case Format::B8G8R8A8_UNORM: return new ValidationTextureFormat<uint8_t>(4); - case Format::B8G8R8A8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(4); - case Format::B8G8R8X8_UNORM: return new ValidationTextureFormat<uint8_t>(3); - case Format::B8G8R8X8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(3); - - case Format::R16G16B16A16_SNORM: return new ValidationTextureFormat<int16_t>(4); - case Format::R16G16_SNORM: return new ValidationTextureFormat<int16_t>(2); - case Format::R16_SNORM: return new ValidationTextureFormat<int16_t>(1); - - case Format::R8G8B8A8_SNORM: return new ValidationTextureFormat<int8_t>(4); - case Format::R8G8_SNORM: return new ValidationTextureFormat<int8_t>(2); - case Format::R8_SNORM: return new ValidationTextureFormat<int8_t>(1); - - case Format::D32_FLOAT: return new ValidationTextureFormat<float>(1); - case Format::D16_UNORM: return new ValidationTextureFormat<uint16_t>(1); - - case Format::B4G4R4A4_UNORM: return new PackedValidationTextureFormat<uint16_t>(4, 4, 4, 4); - case Format::B5G6R5_UNORM: return new PackedValidationTextureFormat<uint16_t>(5, 6, 5, 0); - case Format::B5G5R5A1_UNORM: return new PackedValidationTextureFormat<uint16_t>(5, 5, 5, 1); - - case Format::R9G9B9E5_SHAREDEXP: return new ValidationTextureFormat<uint32_t>(1); - case Format::R10G10B10A2_TYPELESS: return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); - case Format::R10G10B10A2_UNORM: return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); - case Format::R10G10B10A2_UINT: return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); - case Format::R11G11B10_FLOAT: return new PackedValidationTextureFormat<uint32_t>(11, 11, 10, 0); - - // TODO: Add testing support for BC formats -// BC1_UNORM, -// BC1_UNORM_SRGB, -// BC2_UNORM, -// BC2_UNORM_SRGB, -// BC3_UNORM, -// BC3_UNORM_SRGB, -// BC4_UNORM, -// BC4_SNORM, -// BC5_UNORM, -// BC5_SNORM, -// BC6H_UF16, -// BC6H_SF16, -// BC7_UNORM, -// BC7_UNORM_SRGB, - default: - return nullptr; - } + case Format::R32G32B32A32_TYPELESS: return new ValidationTextureFormat<uint32_t>(4); + case Format::R32G32B32_TYPELESS: return new ValidationTextureFormat<uint32_t>(3); + case Format::R32G32_TYPELESS: return new ValidationTextureFormat<uint32_t>(2); + case Format::R32_TYPELESS: return new ValidationTextureFormat<uint32_t>(1); + + case Format::R16G16B16A16_TYPELESS: return new ValidationTextureFormat<uint16_t>(4); + case Format::R16G16_TYPELESS: return new ValidationTextureFormat<uint16_t>(2); + case Format::R16_TYPELESS: return new ValidationTextureFormat<uint16_t>(1); + + case Format::R8G8B8A8_TYPELESS: return new ValidationTextureFormat<uint8_t>(4); + case Format::R8G8_TYPELESS: return new ValidationTextureFormat<uint8_t>(2); + case Format::R8_TYPELESS: return new ValidationTextureFormat<uint8_t>(1); + case Format::B8G8R8A8_TYPELESS: return new ValidationTextureFormat<uint8_t>(4); + + case Format::R32G32B32A32_FLOAT: return new ValidationTextureFormat<float>(4); + case Format::R32G32B32_FLOAT: return new ValidationTextureFormat<float>(3); + case Format::R32G32_FLOAT: return new ValidationTextureFormat<float>(2); + case Format::R32_FLOAT: return new ValidationTextureFormat<float>(1); + + case Format::R16G16B16A16_FLOAT: return new ValidationTextureFormat<uint16_t>(4); + case Format::R16G16_FLOAT: return new ValidationTextureFormat<uint16_t>(2); + case Format::R16_FLOAT: return new ValidationTextureFormat<uint16_t>(1); + + case Format::R64_UINT: return new ValidationTextureFormat<uint64_t>(1); + + case Format::R32G32B32A32_UINT: return new ValidationTextureFormat<uint32_t>(4); + case Format::R32G32B32_UINT: return new ValidationTextureFormat<uint32_t>(3); + case Format::R32G32_UINT: return new ValidationTextureFormat<uint32_t>(2); + case Format::R32_UINT: return new ValidationTextureFormat<uint32_t>(1); + + case Format::R16G16B16A16_UINT: return new ValidationTextureFormat<uint16_t>(4); + case Format::R16G16_UINT: return new ValidationTextureFormat<uint16_t>(2); + case Format::R16_UINT: return new ValidationTextureFormat<uint16_t>(1); + + case Format::R8G8B8A8_UINT: return new ValidationTextureFormat<uint8_t>(4); + case Format::R8G8_UINT: return new ValidationTextureFormat<uint8_t>(2); + case Format::R8_UINT: return new ValidationTextureFormat<uint8_t>(1); + + case Format::R64_SINT: return new ValidationTextureFormat<int64_t>(1); + + case Format::R32G32B32A32_SINT: return new ValidationTextureFormat<int32_t>(4); + case Format::R32G32B32_SINT: return new ValidationTextureFormat<int32_t>(3); + case Format::R32G32_SINT: return new ValidationTextureFormat<int32_t>(2); + case Format::R32_SINT: return new ValidationTextureFormat<int32_t>(1); + + case Format::R16G16B16A16_SINT: return new ValidationTextureFormat<int16_t>(4); + case Format::R16G16_SINT: return new ValidationTextureFormat<int16_t>(2); + case Format::R16_SINT: return new ValidationTextureFormat<int16_t>(1); + + case Format::R8G8B8A8_SINT: return new ValidationTextureFormat<int8_t>(4); + case Format::R8G8_SINT: return new ValidationTextureFormat<int8_t>(2); + case Format::R8_SINT: return new ValidationTextureFormat<int8_t>(1); + + case Format::R16G16B16A16_UNORM: return new ValidationTextureFormat<uint16_t>(4); + case Format::R16G16_UNORM: return new ValidationTextureFormat<uint16_t>(2); + case Format::R16_UNORM: return new ValidationTextureFormat<uint16_t>(1); + + case Format::R8G8B8A8_UNORM: return new ValidationTextureFormat<uint8_t>(4); + case Format::R8G8B8A8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(4); + case Format::R8G8_UNORM: return new ValidationTextureFormat<uint8_t>(2); + case Format::R8_UNORM: return new ValidationTextureFormat<uint8_t>(1); + case Format::B8G8R8A8_UNORM: return new ValidationTextureFormat<uint8_t>(4); + case Format::B8G8R8A8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(4); + case Format::B8G8R8X8_UNORM: return new ValidationTextureFormat<uint8_t>(3); + case Format::B8G8R8X8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(3); + + case Format::R16G16B16A16_SNORM: return new ValidationTextureFormat<int16_t>(4); + case Format::R16G16_SNORM: return new ValidationTextureFormat<int16_t>(2); + case Format::R16_SNORM: return new ValidationTextureFormat<int16_t>(1); + + case Format::R8G8B8A8_SNORM: return new ValidationTextureFormat<int8_t>(4); + case Format::R8G8_SNORM: return new ValidationTextureFormat<int8_t>(2); + case Format::R8_SNORM: return new ValidationTextureFormat<int8_t>(1); + + case Format::D32_FLOAT: return new ValidationTextureFormat<float>(1); + case Format::D16_UNORM: return new ValidationTextureFormat<uint16_t>(1); + + case Format::B4G4R4A4_UNORM: return new PackedValidationTextureFormat<uint16_t>(4, 4, 4, 4); + case Format::B5G6R5_UNORM: return new PackedValidationTextureFormat<uint16_t>(5, 6, 5, 0); + case Format::B5G5R5A1_UNORM: return new PackedValidationTextureFormat<uint16_t>(5, 5, 5, 1); + + case Format::R9G9B9E5_SHAREDEXP: return new ValidationTextureFormat<uint32_t>(1); + case Format::R10G10B10A2_TYPELESS: + return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); + case Format::R10G10B10A2_UNORM: + return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); + case Format::R10G10B10A2_UINT: + return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); + case Format::R11G11B10_FLOAT: + return new PackedValidationTextureFormat<uint32_t>(11, 11, 10, 0); + + // TODO: Add testing support for BC formats + // BC1_UNORM, + // BC1_UNORM_SRGB, + // BC2_UNORM, + // BC2_UNORM_SRGB, + // BC3_UNORM, + // BC3_UNORM_SRGB, + // BC4_UNORM, + // BC4_SNORM, + // BC5_UNORM, + // BC5_SNORM, + // BC6H_UF16, + // BC6H_SF16, + // BC7_UNORM, + // BC7_UNORM_SRGB, + default: return nullptr; } +} - void generateTextureData(RefPtr<TextureInfo> texture, ValidationTextureFormatBase* validationFormat) - { - auto extents = texture->extents; - auto arrayLayers = texture->arrayLayerCount; - auto mipLevels = texture->mipLevelCount; - auto texelSize = getTexelSize(texture->format); +void generateTextureData(RefPtr<TextureInfo> texture, ValidationTextureFormatBase* validationFormat) +{ + auto extents = texture->extents; + auto arrayLayers = texture->arrayLayerCount; + auto mipLevels = texture->mipLevelCount; + auto texelSize = getTexelSize(texture->format); - for (GfxIndex layer = 0; layer < arrayLayers; ++layer) + for (GfxIndex layer = 0; layer < arrayLayers; ++layer) + { + for (GfxIndex mip = 0; mip < mipLevels; ++mip) { - for (GfxIndex mip = 0; mip < mipLevels; ++mip) + RefPtr<ValidationTextureData> subresource = new ValidationTextureData(); + + auto mipWidth = Math::Max(extents.width >> mip, 1); + auto mipHeight = Math::Max(extents.height >> mip, 1); + auto mipDepth = Math::Max(extents.depth >> mip, 1); + auto mipSize = mipWidth * mipHeight * mipDepth * texelSize; + subresource->textureData = malloc(mipSize); + SLANG_CHECK_ABORT(subresource->textureData); + + subresource->extents.width = mipWidth; + subresource->extents.height = mipHeight; + subresource->extents.depth = mipDepth; + subresource->strides.x = texelSize; + subresource->strides.y = mipWidth * texelSize; + subresource->strides.z = mipHeight * subresource->strides.y; + texture->subresourceObjects.add(subresource); + + for (int z = 0; z < mipDepth; ++z) { - RefPtr<ValidationTextureData> subresource = new ValidationTextureData(); - - auto mipWidth = Math::Max(extents.width >> mip, 1); - auto mipHeight = Math::Max(extents.height >> mip, 1); - auto mipDepth = Math::Max(extents.depth >> mip, 1); - auto mipSize = mipWidth * mipHeight * mipDepth * texelSize; - subresource->textureData = malloc(mipSize); - SLANG_CHECK_ABORT(subresource->textureData); - - subresource->extents.width = mipWidth; - subresource->extents.height = mipHeight; - subresource->extents.depth = mipDepth; - subresource->strides.x = texelSize; - subresource->strides.y = mipWidth * texelSize; - subresource->strides.z = mipHeight * subresource->strides.y; - texture->subresourceObjects.add(subresource); - - for (int z = 0; z < mipDepth; ++z) + for (int y = 0; y < mipHeight; ++y) { - for (int y = 0; y < mipHeight; ++y) + for (int x = 0; x < mipWidth; ++x) { - for (int x = 0; x < mipWidth; ++x) - { - auto texel = subresource->getBlockAt(x, y, z); - validationFormat->initializeTexel(texel, x, y, z, mip, layer); - } + auto texel = subresource->getBlockAt(x, y, z); + validationFormat->initializeTexel(texel, x, y, z, mip, layer); } } - - ITextureResource::SubresourceData subData = {}; - subData.data = subresource->textureData; - subData.strideY = subresource->strides.y; - subData.strideZ = subresource->strides.z; - texture->subresourceDatas.add(subData); } + + ITextureResource::SubresourceData subData = {}; + subData.data = subresource->textureData; + subData.strideY = subresource->strides.y; + subData.strideZ = subresource->strides.z; + texture->subresourceDatas.add(subData); } } +} - List<uint8_t> removePadding(ISlangBlob* pixels, GfxCount width, GfxCount height, Size rowPitch, Size pixelSize) +List<uint8_t> removePadding( + ISlangBlob* pixels, + GfxCount width, + GfxCount height, + Size rowPitch, + Size pixelSize) +{ + List<uint8_t> buffer; + buffer.setCount(height * rowPitch); + for (GfxIndex i = 0; i < height; ++i) { - List<uint8_t> buffer; - buffer.setCount(height * rowPitch); - for (GfxIndex i = 0; i < height; ++i) - { - Offset srcOffset = i * rowPitch; - Offset dstOffset = i * width * pixelSize; - memcpy(buffer.getBuffer() + dstOffset, (char*)pixels->getBufferPointer() + srcOffset, width * pixelSize); - } - - return buffer; + Offset srcOffset = i * rowPitch; + Offset dstOffset = i * width * pixelSize; + memcpy( + buffer.getBuffer() + dstOffset, + (char*)pixels->getBufferPointer() + srcOffset, + width * pixelSize); } - Slang::Result writeImage( - const char* filename, - ISlangBlob* pixels, - uint32_t width, - uint32_t height) - { - int stbResult = - stbi_write_hdr(filename, width, height, 4, (float*)pixels->getBufferPointer()); + return buffer; +} - return stbResult ? SLANG_OK : SLANG_FAIL; - } +Slang::Result writeImage(const char* filename, ISlangBlob* pixels, uint32_t width, uint32_t height) +{ + int stbResult = stbi_write_hdr(filename, width, height, 4, (float*)pixels->getBufferPointer()); - Slang::Result writeImage( - const char* filename, - ISlangBlob* pixels, - uint32_t width, - uint32_t height, - uint32_t rowPitch, - uint32_t pixelSize) - { - if (rowPitch == width * pixelSize) - return writeImage(filename, pixels, width, height); + return stbResult ? SLANG_OK : SLANG_FAIL; +} - List<uint8_t> buffer = removePadding(pixels, width, height, rowPitch, pixelSize); +Slang::Result writeImage( + const char* filename, + ISlangBlob* pixels, + uint32_t width, + uint32_t height, + uint32_t rowPitch, + uint32_t pixelSize) +{ + if (rowPitch == width * pixelSize) + return writeImage(filename, pixels, width, height); - int stbResult = - stbi_write_hdr(filename, width, height, 4, (float*)buffer.getBuffer()); + List<uint8_t> buffer = removePadding(pixels, width, height, rowPitch, pixelSize); - return stbResult ? SLANG_OK : SLANG_FAIL; - } + int stbResult = stbi_write_hdr(filename, width, height, 4, (float*)buffer.getBuffer()); + + return stbResult ? SLANG_OK : SLANG_FAIL; } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/gfx-test-texture-util.h b/tools/gfx-unit-test/gfx-test-texture-util.h index 7069ff667..7c6b9443f 100644 --- a/tools/gfx-unit-test/gfx-test-texture-util.h +++ b/tools/gfx-unit-test/gfx-test-texture-util.h @@ -10,187 +10,205 @@ using namespace gfx; namespace gfx_test { - struct Strides - { - Size x; - Size y; - Size z; - }; +struct Strides +{ + Size x; + Size y; + Size z; +}; - struct ValidationTextureFormatBase : RefObject - { - virtual void validateBlocksEqual(const void* actual, const void* expected) = 0; +struct ValidationTextureFormatBase : RefObject +{ + virtual void validateBlocksEqual(const void* actual, const void* expected) = 0; + + virtual void initializeTexel( + void* texel, + GfxIndex x, + GfxIndex y, + GfxIndex z, + GfxIndex mipLevel, + GfxIndex arrayLayer) = 0; +}; + +template<typename T> +struct ValidationTextureFormat : ValidationTextureFormatBase +{ + int componentCount; - virtual void initializeTexel(void* texel, GfxIndex x, GfxIndex y, GfxIndex z, GfxIndex mipLevel, GfxIndex arrayLayer) = 0; - }; + ValidationTextureFormat(int componentCount) + : componentCount(componentCount){}; - template <typename T> - struct ValidationTextureFormat : ValidationTextureFormatBase + virtual void validateBlocksEqual(const void* actual, const void* expected) override { - int componentCount; - - ValidationTextureFormat(int componentCount) : componentCount(componentCount) {}; + auto a = (const T*)actual; + auto e = (const T*)expected; - virtual void validateBlocksEqual(const void* actual, const void* expected) override + for (Int i = 0; i < componentCount; ++i) { - auto a = (const T*)actual; - auto e = (const T*)expected; - - for (Int i = 0; i < componentCount; ++i) - { - SLANG_CHECK(a[i] == e[i]); - } + SLANG_CHECK(a[i] == e[i]); } + } + + virtual void initializeTexel( + void* texel, + GfxIndex x, + GfxIndex y, + GfxIndex z, + GfxIndex mipLevel, + GfxIndex arrayLayer) override + { + auto temp = (T*)texel; - virtual void initializeTexel(void* texel, GfxIndex x, GfxIndex y, GfxIndex z, GfxIndex mipLevel, GfxIndex arrayLayer) override + switch (componentCount) { - auto temp = (T*)texel; - - switch (componentCount) - { - case 1: - temp[0] = T(x + y + z + mipLevel + arrayLayer); - break; - case 2: - temp[0] = T(x + z + arrayLayer); - temp[1] = T(y + mipLevel); - break; - case 3: - temp[0] = T(x + mipLevel); - temp[1] = T(y + arrayLayer); - temp[2] = T(z); - break; - case 4: - temp[0] = T(x + arrayLayer); - temp[1] = (T)y; - temp[2] = (T)z; - temp[3] = (T)mipLevel; - break; - default: - assert(!"component count should be no greater than 4"); - SLANG_CHECK_ABORT(false); - } + case 1: temp[0] = T(x + y + z + mipLevel + arrayLayer); break; + case 2: + temp[0] = T(x + z + arrayLayer); + temp[1] = T(y + mipLevel); + break; + case 3: + temp[0] = T(x + mipLevel); + temp[1] = T(y + arrayLayer); + temp[2] = T(z); + break; + case 4: + temp[0] = T(x + arrayLayer); + temp[1] = (T)y; + temp[2] = (T)z; + temp[3] = (T)mipLevel; + break; + default: assert(!"component count should be no greater than 4"); SLANG_CHECK_ABORT(false); } - }; + } +}; - template <typename T> - struct PackedValidationTextureFormat : ValidationTextureFormatBase - { - int rBits; - int gBits; - int bBits; - int aBits; +template<typename T> +struct PackedValidationTextureFormat : ValidationTextureFormatBase +{ + int rBits; + int gBits; + int bBits; + int aBits; + + PackedValidationTextureFormat(int rBits, int gBits, int bBits, int aBits) + : rBits(rBits), gBits(gBits), bBits(bBits), aBits(aBits){}; - PackedValidationTextureFormat(int rBits, int gBits, int bBits, int aBits) - : rBits(rBits), gBits(gBits), bBits(bBits), aBits(aBits) {}; + virtual void validateBlocksEqual(const void* actual, const void* expected) override + { + T a[4]; + T e[4]; + unpackTexel(*(const T*)actual, a); + unpackTexel(*(const T*)expected, e); - virtual void validateBlocksEqual(const void* actual, const void* expected) override + for (Int i = 0; i < 4; ++i) { - T a[4]; - T e[4]; - unpackTexel(*(const T*)actual, a); - unpackTexel(*(const T*)expected, e); - - for (Int i = 0; i < 4; ++i) - { - SLANG_CHECK(a[i] == e[i]); - } + SLANG_CHECK(a[i] == e[i]); } + } + + virtual void initializeTexel( + void* texel, + GfxIndex x, + GfxIndex y, + GfxIndex z, + GfxIndex mipLevel, + GfxIndex arrayLayer) override + { + T temp = 0; - virtual void initializeTexel(void* texel, GfxIndex x, GfxIndex y, GfxIndex z, GfxIndex mipLevel, GfxIndex arrayLayer) override + // The only formats which currently use this have either 3 or 4 channels. TODO: BC formats? + if (aBits == 0) { - T temp = 0; - - // The only formats which currently use this have either 3 or 4 channels. TODO: BC formats? - if (aBits == 0) - { - temp |= z; - temp <<= gBits; - temp |= (y + arrayLayer); - temp <<= rBits; - temp |= (x + mipLevel); - } - else - { - temp |= mipLevel; - temp <<= bBits; - temp |= z; - temp <<= gBits; - temp |= y; - temp <<= rBits; - temp |= (x + arrayLayer); - } - - *(T*)texel = temp; + temp |= z; + temp <<= gBits; + temp |= (y + arrayLayer); + temp <<= rBits; + temp |= (x + mipLevel); } - - void unpackTexel(T texel, T* outComponents) + else { - outComponents[0] = texel & ((1 << rBits) - 1); - texel >>= rBits; + temp |= mipLevel; + temp <<= bBits; + temp |= z; + temp <<= gBits; + temp |= y; + temp <<= rBits; + temp |= (x + arrayLayer); + } - outComponents[1] = texel & ((1 << gBits) - 1); - texel >>= gBits; + *(T*)texel = temp; + } - outComponents[2] = texel & ((1 << bBits) - 1); - texel >>= bBits; + void unpackTexel(T texel, T* outComponents) + { + outComponents[0] = texel & ((1 << rBits) - 1); + texel >>= rBits; - outComponents[3] = texel & ((1 << aBits) - 1); - texel >>= aBits; - } - }; + outComponents[1] = texel & ((1 << gBits) - 1); + texel >>= gBits; - // Struct containing texture data and information for a specific subresource. - struct ValidationTextureData : RefObject - { - const void* textureData; - ITextureResource::Extents extents; - Strides strides; + outComponents[2] = texel & ((1 << bBits) - 1); + texel >>= bBits; - void* getBlockAt(GfxIndex x, GfxIndex y, GfxIndex z) - { - assert(x >= 0 && x < extents.width); - assert(y >= 0 && y < extents.height); - assert(z >= 0 && z < extents.depth); + outComponents[3] = texel & ((1 << aBits) - 1); + texel >>= aBits; + } +}; - char* layerData = (char*)textureData + z * strides.z; - char* rowData = layerData + y * strides.y; - return rowData + x * strides.x; - } - }; +// Struct containing texture data and information for a specific subresource. +struct ValidationTextureData : RefObject +{ + const void* textureData; + ITextureResource::Extents extents; + Strides strides; - // Struct containing relevant information for a texture, including a list of its subresources - // and all relevant information for each subresource. - struct TextureInfo : RefObject + void* getBlockAt(GfxIndex x, GfxIndex y, GfxIndex z) { - Format format; - ITextureResource::Type textureType; - - ITextureResource::Extents extents; - GfxCount mipLevelCount; - GfxCount arrayLayerCount; - - List<RefPtr<ValidationTextureData>> subresourceObjects; - List<ITextureResource::SubresourceData> subresourceDatas; - }; - - TextureAspect getTextureAspect(Format format); - Size getTexelSize(Format format); - GfxIndex getSubresourceIndex(GfxIndex mipLevel, GfxCount mipLevelCount, GfxIndex baseArrayLayer); - RefPtr<ValidationTextureFormatBase> getValidationTextureFormat(Format format); - void generateTextureData(RefPtr<TextureInfo> texture, ValidationTextureFormatBase* validationFormat); - - List<uint8_t> removePadding(ISlangBlob* pixels, GfxCount width, GfxCount height, Size rowPitch, Size pixelSize); - Slang::Result writeImage( - const char* filename, - ISlangBlob* pixels, - uint32_t width, - uint32_t height); - Slang::Result writeImage( - const char* filename, - ISlangBlob* pixels, - uint32_t width, - uint32_t height, - uint32_t rowPitch, - uint32_t pixelSize); -} + assert(x >= 0 && x < extents.width); + assert(y >= 0 && y < extents.height); + assert(z >= 0 && z < extents.depth); + + char* layerData = (char*)textureData + z * strides.z; + char* rowData = layerData + y * strides.y; + return rowData + x * strides.x; + } +}; + +// Struct containing relevant information for a texture, including a list of its subresources +// and all relevant information for each subresource. +struct TextureInfo : RefObject +{ + Format format; + ITextureResource::Type textureType; + + ITextureResource::Extents extents; + GfxCount mipLevelCount; + GfxCount arrayLayerCount; + + List<RefPtr<ValidationTextureData>> subresourceObjects; + List<ITextureResource::SubresourceData> subresourceDatas; +}; + +TextureAspect getTextureAspect(Format format); +Size getTexelSize(Format format); +GfxIndex getSubresourceIndex(GfxIndex mipLevel, GfxCount mipLevelCount, GfxIndex baseArrayLayer); +RefPtr<ValidationTextureFormatBase> getValidationTextureFormat(Format format); +void generateTextureData( + RefPtr<TextureInfo> texture, + ValidationTextureFormatBase* validationFormat); + +List<uint8_t> removePadding( + ISlangBlob* pixels, + GfxCount width, + GfxCount height, + Size rowPitch, + Size pixelSize); +Slang::Result writeImage(const char* filename, ISlangBlob* pixels, uint32_t width, uint32_t height); +Slang::Result writeImage( + const char* filename, + ISlangBlob* pixels, + uint32_t width, + uint32_t height, + uint32_t rowPitch, + uint32_t pixelSize); +} // namespace gfx_test diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp index 1c7289325..18aaabdaf 100644 --- a/tools/gfx-unit-test/gfx-test-util.cpp +++ b/tools/gfx-unit-test/gfx-test-util.cpp @@ -1,350 +1,360 @@ #include "gfx-test-util.h" -#include "tools/unit-test/slang-unit-test.h" #include "slang-com-ptr.h" +#include "tools/unit-test/slang-unit-test.h" #define GFX_ENABLE_RENDERDOC_INTEGRATION 0 #define GFX_ENABLE_SPIRV_DEBUG 0 #if GFX_ENABLE_RENDERDOC_INTEGRATION -# include "external/renderdoc_app.h" -# include <windows.h> +#include "external/renderdoc_app.h" + +#include <windows.h> #endif using Slang::ComPtr; namespace gfx_test { - void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) +void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) +{ + if (diagnosticsBlob != nullptr) { - if (diagnosticsBlob != nullptr) - { - getTestReporter()->message(TestMessageType::Info, (const char*)diagnosticsBlob->getBufferPointer()); - } + getTestReporter()->message( + TestMessageType::Info, + (const char*)diagnosticsBlob->getBufferPointer()); } +} - Slang::Result loadComputeProgram( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - const char* shaderModuleName, - const char* entryPointName, - slang::ProgramLayout*& slangReflection) - { - Slang::ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if (!module) - return SLANG_FAIL; - - ComPtr<slang::IEntryPoint> computeEntryPoint; - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(module); - componentTypes.add(computeEntryPoint); - - Slang::ComPtr<slang::IComponentType> composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - ComPtr<slang::IComponentType> linkedProgram; - result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - composedProgram = linkedProgram; - slangReflection = composedProgram->getLayout(); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = composedProgram.get(); - - auto shaderProgram = device->createProgram(programDesc); - - outShaderProgram = shaderProgram; - return SLANG_OK; - } +Slang::Result loadComputeProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + const char* shaderModuleName, + const char* entryPointName, + slang::ProgramLayout*& slangReflection) +{ + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + ComPtr<slang::IEntryPoint> computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(module); + componentTypes.add(computeEntryPoint); + + Slang::ComPtr<slang::IComponentType> composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + ComPtr<slang::IComponentType> linkedProgram; + result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + composedProgram = linkedProgram; + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; +} - Slang::Result loadComputeProgram( - gfx::IDevice* device, - slang::ISession* slangSession, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - const char* shaderModuleName, - const char* entryPointName, - slang::ProgramLayout*& slangReflection) - { - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if (!module) - return SLANG_FAIL; - - ComPtr<slang::IEntryPoint> computeEntryPoint; - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(module); - componentTypes.add(computeEntryPoint); - - Slang::ComPtr<slang::IComponentType> composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - ComPtr<slang::IComponentType> linkedProgram; - result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - composedProgram = linkedProgram; - slangReflection = composedProgram->getLayout(); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = composedProgram.get(); - - auto shaderProgram = device->createProgram(programDesc); - - outShaderProgram = shaderProgram; - return SLANG_OK; - } +Slang::Result loadComputeProgram( + gfx::IDevice* device, + slang::ISession* slangSession, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + const char* shaderModuleName, + const char* entryPointName, + slang::ProgramLayout*& slangReflection) +{ + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + ComPtr<slang::IEntryPoint> computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(module); + componentTypes.add(computeEntryPoint); + + Slang::ComPtr<slang::IComponentType> composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + ComPtr<slang::IComponentType> linkedProgram; + result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + composedProgram = linkedProgram; + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; +} - Slang::Result loadComputeProgramFromSource( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - Slang::String source) - { - Slang::ComPtr<slang::IBlob> diagnosticsBlob; +Slang::Result loadComputeProgramFromSource( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + Slang::String source) +{ + Slang::ComPtr<slang::IBlob> diagnosticsBlob; - gfx::IShaderProgram::CreateDesc2 programDesc = {}; - programDesc.sourceType = gfx::ShaderModuleSourceType::SlangSource; - programDesc.sourceData = (void*)source.getBuffer(); - programDesc.sourceDataSize = source.getLength(); + gfx::IShaderProgram::CreateDesc2 programDesc = {}; + programDesc.sourceType = gfx::ShaderModuleSourceType::SlangSource; + programDesc.sourceData = (void*)source.getBuffer(); + programDesc.sourceDataSize = source.getLength(); - return device->createProgram2(programDesc, outShaderProgram.writeRef(), diagnosticsBlob.writeRef()); - } + return device->createProgram2( + programDesc, + outShaderProgram.writeRef(), + diagnosticsBlob.writeRef()); +} - Slang::Result loadGraphicsProgram( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - const char* shaderModuleName, - const char* vertexEntryPointName, - const char* fragmentEntryPointName, - slang::ProgramLayout*& slangReflection) - { - Slang::ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if (!module) - return SLANG_FAIL; - - ComPtr<slang::IEntryPoint> vertexEntryPoint; - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName(vertexEntryPointName, vertexEntryPoint.writeRef())); - - ComPtr<slang::IEntryPoint> fragmentEntryPoint; - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName(fragmentEntryPointName, fragmentEntryPoint.writeRef())); - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(module); - componentTypes.add(vertexEntryPoint); - componentTypes.add(fragmentEntryPoint); - - Slang::ComPtr<slang::IComponentType> composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - slangReflection = composedProgram->getLayout(); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = composedProgram.get(); - - auto shaderProgram = device->createProgram(programDesc); - - outShaderProgram = shaderProgram; - return SLANG_OK; - } +Slang::Result loadGraphicsProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + const char* shaderModuleName, + const char* vertexEntryPointName, + const char* fragmentEntryPointName, + slang::ProgramLayout*& slangReflection) +{ + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + ComPtr<slang::IEntryPoint> vertexEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(vertexEntryPointName, vertexEntryPoint.writeRef())); + + ComPtr<slang::IEntryPoint> fragmentEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(fragmentEntryPointName, fragmentEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(module); + componentTypes.add(vertexEntryPoint); + componentTypes.add(fragmentEntryPoint); + + Slang::ComPtr<slang::IComponentType> composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; +} - void compareComputeResult( - gfx::IDevice* device, - gfx::ITextureResource* texture, - gfx::ResourceState state, - void* expectedResult, - size_t expectedResultRowPitch, - size_t rowCount) +void compareComputeResult( + gfx::IDevice* device, + gfx::ITextureResource* texture, + gfx::ResourceState state, + void* expectedResult, + size_t expectedResultRowPitch, + size_t rowCount) +{ + // Read back the results. + ComPtr<ISlangBlob> resultBlob; + size_t rowPitch = 0; + size_t pixelSize = 0; + GFX_CHECK_CALL_ABORT( + device->readTextureResource(texture, state, resultBlob.writeRef(), &rowPitch, &pixelSize)); + // Compare results. + for (size_t row = 0; row < rowCount; row++) { - // Read back the results. - ComPtr<ISlangBlob> resultBlob; - size_t rowPitch = 0; - size_t pixelSize = 0; - GFX_CHECK_CALL_ABORT(device->readTextureResource( - texture, state, resultBlob.writeRef(), &rowPitch, &pixelSize)); - // Compare results. - for (size_t row = 0; row < rowCount; row++) - { - SLANG_CHECK( - memcmp( - (uint8_t*)resultBlob->getBufferPointer() + rowPitch * row, - (uint8_t*)expectedResult + expectedResultRowPitch * row, - expectedResultRowPitch) == 0); - } + SLANG_CHECK( + memcmp( + (uint8_t*)resultBlob->getBufferPointer() + rowPitch * row, + (uint8_t*)expectedResult + expectedResultRowPitch * row, + expectedResultRowPitch) == 0); } +} - void compareComputeResult(gfx::IDevice* device, gfx::IBufferResource* buffer, size_t offset, const void* expectedResult, size_t expectedBufferSize) - { - // Read back the results. - ComPtr<ISlangBlob> resultBlob; - GFX_CHECK_CALL_ABORT(device->readBufferResource( - buffer, offset, expectedBufferSize, resultBlob.writeRef())); - SLANG_CHECK(resultBlob->getBufferSize() == expectedBufferSize); - // Compare results. - SLANG_CHECK(memcmp(resultBlob->getBufferPointer(), (uint8_t*)expectedResult, expectedBufferSize) == 0); - } +void compareComputeResult( + gfx::IDevice* device, + gfx::IBufferResource* buffer, + size_t offset, + const void* expectedResult, + size_t expectedBufferSize) +{ + // Read back the results. + ComPtr<ISlangBlob> resultBlob; + GFX_CHECK_CALL_ABORT( + device->readBufferResource(buffer, offset, expectedBufferSize, resultBlob.writeRef())); + SLANG_CHECK(resultBlob->getBufferSize() == expectedBufferSize); + // Compare results. + SLANG_CHECK( + memcmp(resultBlob->getBufferPointer(), (uint8_t*)expectedResult, expectedBufferSize) == 0); +} - void compareComputeResultFuzzy(const float* result, float* expectedResult, size_t expectedBufferSize) +void compareComputeResultFuzzy( + const float* result, + float* expectedResult, + size_t expectedBufferSize) +{ + for (size_t i = 0; i < expectedBufferSize / sizeof(float); ++i) { - for (size_t i = 0; i < expectedBufferSize / sizeof(float); ++i) - { - SLANG_CHECK(abs(result[i] - expectedResult[i]) <= 0.01); - } + SLANG_CHECK(abs(result[i] - expectedResult[i]) <= 0.01); } +} - void compareComputeResultFuzzy(gfx::IDevice* device, gfx::IBufferResource* buffer, float* expectedResult, size_t expectedBufferSize) - { - // Read back the results. - ComPtr<ISlangBlob> resultBlob; - GFX_CHECK_CALL_ABORT(device->readBufferResource( - buffer, 0, expectedBufferSize, resultBlob.writeRef())); - SLANG_CHECK(resultBlob->getBufferSize() == expectedBufferSize); - // Compare results with a tolerance of 0.01. - auto result = (float*)resultBlob->getBufferPointer(); - compareComputeResultFuzzy(result, expectedResult, expectedBufferSize); - } +void compareComputeResultFuzzy( + gfx::IDevice* device, + gfx::IBufferResource* buffer, + float* expectedResult, + size_t expectedBufferSize) +{ + // Read back the results. + ComPtr<ISlangBlob> resultBlob; + GFX_CHECK_CALL_ABORT( + device->readBufferResource(buffer, 0, expectedBufferSize, resultBlob.writeRef())); + SLANG_CHECK(resultBlob->getBufferSize() == expectedBufferSize); + // Compare results with a tolerance of 0.01. + auto result = (float*)resultBlob->getBufferPointer(); + compareComputeResultFuzzy(result, expectedResult, expectedBufferSize); +} - Slang::ComPtr<gfx::IDevice> createTestingDevice( - UnitTestContext* context, - Slang::RenderApiFlag::Enum api, - Slang::List<const char*> additionalSearchPaths, - gfx::IDevice::ShaderCacheDesc shaderCache) +Slang::ComPtr<gfx::IDevice> createTestingDevice( + UnitTestContext* context, + Slang::RenderApiFlag::Enum api, + Slang::List<const char*> additionalSearchPaths, + gfx::IDevice::ShaderCacheDesc shaderCache) +{ + Slang::ComPtr<gfx::IDevice> device; + gfx::IDevice::Desc deviceDesc = {}; + switch (api) { - Slang::ComPtr<gfx::IDevice> device; - gfx::IDevice::Desc deviceDesc = {}; - switch (api) - { - case Slang::RenderApiFlag::D3D11: - deviceDesc.deviceType = gfx::DeviceType::DirectX11; - break; - case Slang::RenderApiFlag::D3D12: - deviceDesc.deviceType = gfx::DeviceType::DirectX12; - break; - case Slang::RenderApiFlag::Vulkan: - deviceDesc.deviceType = gfx::DeviceType::Vulkan; - break; - case Slang::RenderApiFlag::CPU: - deviceDesc.deviceType = gfx::DeviceType::CPU; - break; - case Slang::RenderApiFlag::CUDA: - deviceDesc.deviceType = gfx::DeviceType::CUDA; - break; - default: - SLANG_IGNORE_TEST - } - deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; - Slang::List<const char*> searchPaths = getSlangSearchPaths(); - searchPaths.addRange(additionalSearchPaths); - deviceDesc.slang.searchPaths = searchPaths.getBuffer(); - deviceDesc.slang.searchPathCount = (gfx::GfxCount)searchPaths.getCount(); - deviceDesc.shaderCache = shaderCache; - - gfx::D3D12DeviceExtendedDesc extDesc = {}; - extDesc.rootParameterShaderAttributeName = "root"; - - gfx::SlangSessionExtendedDesc slangExtDesc = {}; - Slang::List<slang::CompilerOptionEntry> entries; - slang::CompilerOptionEntry emitSpirvDirectlyEntry; - emitSpirvDirectlyEntry.name = slang::CompilerOptionName::EmitSpirvDirectly; - emitSpirvDirectlyEntry.value.intValue0 = 1; - entries.add(emitSpirvDirectlyEntry); + case Slang::RenderApiFlag::D3D11: deviceDesc.deviceType = gfx::DeviceType::DirectX11; break; + case Slang::RenderApiFlag::D3D12: deviceDesc.deviceType = gfx::DeviceType::DirectX12; break; + case Slang::RenderApiFlag::Vulkan: deviceDesc.deviceType = gfx::DeviceType::Vulkan; break; + case Slang::RenderApiFlag::CPU: deviceDesc.deviceType = gfx::DeviceType::CPU; break; + case Slang::RenderApiFlag::CUDA: deviceDesc.deviceType = gfx::DeviceType::CUDA; break; + default: SLANG_IGNORE_TEST + } + deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; + Slang::List<const char*> searchPaths = getSlangSearchPaths(); + searchPaths.addRange(additionalSearchPaths); + deviceDesc.slang.searchPaths = searchPaths.getBuffer(); + deviceDesc.slang.searchPathCount = (gfx::GfxCount)searchPaths.getCount(); + deviceDesc.shaderCache = shaderCache; + + gfx::D3D12DeviceExtendedDesc extDesc = {}; + extDesc.rootParameterShaderAttributeName = "root"; + + gfx::SlangSessionExtendedDesc slangExtDesc = {}; + Slang::List<slang::CompilerOptionEntry> entries; + slang::CompilerOptionEntry emitSpirvDirectlyEntry; + emitSpirvDirectlyEntry.name = slang::CompilerOptionName::EmitSpirvDirectly; + emitSpirvDirectlyEntry.value.intValue0 = 1; + entries.add(emitSpirvDirectlyEntry); #if GFX_ENABLE_SPIRV_DEBUG - slang::CompilerOptionEntry debugLevelCompilerOptionEntry; - debugLevelCompilerOptionEntry.name = slang::CompilerOptionName::DebugInformation; - debugLevelCompilerOptionEntry.value.intValue0 = SLANG_DEBUG_INFO_LEVEL_STANDARD; - entries.add(debugLevelCompilerOptionEntry); + slang::CompilerOptionEntry debugLevelCompilerOptionEntry; + debugLevelCompilerOptionEntry.name = slang::CompilerOptionName::DebugInformation; + debugLevelCompilerOptionEntry.value.intValue0 = SLANG_DEBUG_INFO_LEVEL_STANDARD; + entries.add(debugLevelCompilerOptionEntry); #endif - slangExtDesc.compilerOptionEntries = entries.getBuffer(); - slangExtDesc.compilerOptionEntryCount = (uint32_t)entries.getCount(); + slangExtDesc.compilerOptionEntries = entries.getBuffer(); + slangExtDesc.compilerOptionEntryCount = (uint32_t)entries.getCount(); - deviceDesc.extendedDescCount = 2; - void* extDescPtrs[2] = { &extDesc, &slangExtDesc }; - deviceDesc.extendedDescs = extDescPtrs; + deviceDesc.extendedDescCount = 2; + void* extDescPtrs[2] = {&extDesc, &slangExtDesc}; + deviceDesc.extendedDescs = extDescPtrs; - // TODO: We should also set the debug callback - // (And in general reduce the differences (and duplication) between - // here and render-test-main.cpp) + // TODO: We should also set the debug callback + // (And in general reduce the differences (and duplication) between + // here and render-test-main.cpp) #ifdef _DEBUG - gfx::gfxEnableDebugLayer(); + gfx::gfxEnableDebugLayer(); #endif - auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); - if (SLANG_FAILED(createDeviceResult)) - { - SLANG_IGNORE_TEST - } - return device; - } - - Slang::List<const char*> getSlangSearchPaths() + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); + if (SLANG_FAILED(createDeviceResult)) { - Slang::List<const char*> searchPaths; - searchPaths.add(""); - searchPaths.add("../../tools/gfx-unit-test"); - searchPaths.add("tools/gfx-unit-test"); - return searchPaths; + SLANG_IGNORE_TEST } + return device; +} + +Slang::List<const char*> getSlangSearchPaths() +{ + Slang::List<const char*> searchPaths; + searchPaths.add(""); + searchPaths.add("../../tools/gfx-unit-test"); + searchPaths.add("tools/gfx-unit-test"); + return searchPaths; +} #if GFX_ENABLE_RENDERDOC_INTEGRATION - RENDERDOC_API_1_1_2* rdoc_api = NULL; - void initializeRenderDoc() - { - if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) - { - pRENDERDOC_GetAPI RENDERDOC_GetAPI = - (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); - int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void**)&rdoc_api); - assert(ret == 1); - } - } - void renderDocBeginFrame() - { - if (!rdoc_api) initializeRenderDoc(); - if (rdoc_api) rdoc_api->StartFrameCapture(nullptr, nullptr); - } - void renderDocEndFrame() +RENDERDOC_API_1_1_2* rdoc_api = NULL; +void initializeRenderDoc() +{ + if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) { - if (rdoc_api) - rdoc_api->EndFrameCapture(nullptr, nullptr); - _fgetchar(); + pRENDERDOC_GetAPI RENDERDOC_GetAPI = + (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); + int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void**)&rdoc_api); + assert(ret == 1); } +} +void renderDocBeginFrame() +{ + if (!rdoc_api) + initializeRenderDoc(); + if (rdoc_api) + rdoc_api->StartFrameCapture(nullptr, nullptr); +} +void renderDocEndFrame() +{ + if (rdoc_api) + rdoc_api->EndFrameCapture(nullptr, nullptr); + _fgetchar(); +} #else - void initializeRenderDoc() {} - void renderDocBeginFrame() {} - void renderDocEndFrame() {} +void initializeRenderDoc() {} +void renderDocBeginFrame() {} +void renderDocEndFrame() {} #endif -} +} // namespace gfx_test diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h index 643830413..51b1feb1f 100644 --- a/tools/gfx-unit-test/gfx-test-util.h +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -7,137 +7,143 @@ namespace gfx_test { - /// Helper function for print out diagnostic messages output by Slang compiler. - void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob); - - /// Loads a compute shader module and produces a `gfx::IShaderProgram`. - Slang::Result loadComputeProgram( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - const char* shaderModuleName, - const char* entryPointName, - slang::ProgramLayout*& slangReflection); - - Slang::Result loadComputeProgram( - gfx::IDevice* device, - slang::ISession* slangSession, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - const char* shaderModuleName, - const char* entryPointName, - slang::ProgramLayout*& slangReflection); - - Slang::Result loadComputeProgramFromSource( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - Slang::String source); - - Slang::Result loadGraphicsProgram( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - const char* shaderModuleName, - const char* vertexEntryPointName, - const char* fragmentEntryPointName, - slang::ProgramLayout*& slangReflection); - - /// Reads back the content of `buffer` and compares it against `expectedResult`. - void compareComputeResult( - gfx::IDevice* device, - gfx::IBufferResource* buffer, - size_t offset, - const void* expectedResult, - size_t expectedBufferSize); - - /// Reads back the content of `texture` and compares it against `expectedResult`. - void compareComputeResult( - gfx::IDevice* device, - gfx::ITextureResource* texture, - gfx::ResourceState state, - void* expectedResult, - size_t expectedResultRowPitch, - size_t rowCount); - - void compareComputeResultFuzzy( - const float* result, - float* expectedResult, - size_t expectedBufferSize); - - /// Reads back the content of `buffer` and compares it against `expectedResult` with a set tolerance. - void compareComputeResultFuzzy( - gfx::IDevice* device, - gfx::IBufferResource* buffer, - float* expectedResult, - size_t expectedBufferSize); - - template<typename T, Slang::Index count> - void compareComputeResult( - gfx::IDevice* device, - gfx::IBufferResource* buffer, - Slang::Array<T, count> expectedResult) +/// Helper function for print out diagnostic messages output by Slang compiler. +void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob); + +/// Loads a compute shader module and produces a `gfx::IShaderProgram`. +Slang::Result loadComputeProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + const char* shaderModuleName, + const char* entryPointName, + slang::ProgramLayout*& slangReflection); + +Slang::Result loadComputeProgram( + gfx::IDevice* device, + slang::ISession* slangSession, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + const char* shaderModuleName, + const char* entryPointName, + slang::ProgramLayout*& slangReflection); + +Slang::Result loadComputeProgramFromSource( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + Slang::String source); + +Slang::Result loadGraphicsProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + const char* shaderModuleName, + const char* vertexEntryPointName, + const char* fragmentEntryPointName, + slang::ProgramLayout*& slangReflection); + +/// Reads back the content of `buffer` and compares it against `expectedResult`. +void compareComputeResult( + gfx::IDevice* device, + gfx::IBufferResource* buffer, + size_t offset, + const void* expectedResult, + size_t expectedBufferSize); + +/// Reads back the content of `texture` and compares it against `expectedResult`. +void compareComputeResult( + gfx::IDevice* device, + gfx::ITextureResource* texture, + gfx::ResourceState state, + void* expectedResult, + size_t expectedResultRowPitch, + size_t rowCount); + +void compareComputeResultFuzzy( + const float* result, + float* expectedResult, + size_t expectedBufferSize); + +/// Reads back the content of `buffer` and compares it against `expectedResult` with a set +/// tolerance. +void compareComputeResultFuzzy( + gfx::IDevice* device, + gfx::IBufferResource* buffer, + float* expectedResult, + size_t expectedBufferSize); + +template<typename T, Slang::Index count> +void compareComputeResult( + gfx::IDevice* device, + gfx::IBufferResource* buffer, + Slang::Array<T, count> expectedResult) +{ + Slang::List<uint8_t> expectedBuffer; + size_t bufferSize = sizeof(T) * count; + expectedBuffer.setCount(bufferSize); + memcpy(expectedBuffer.getBuffer(), expectedResult.begin(), bufferSize); + if (std::is_same<T, float>::value) + return compareComputeResultFuzzy( + device, + buffer, + (float*)expectedBuffer.getBuffer(), + bufferSize); + return compareComputeResult(device, buffer, 0, expectedBuffer.getBuffer(), bufferSize); +} + +Slang::ComPtr<gfx::IDevice> createTestingDevice( + UnitTestContext* context, + Slang::RenderApiFlag::Enum api, + Slang::List<const char*> additionalSearchPaths = {}, + gfx::IDevice::ShaderCacheDesc shaderCache = {}); + +Slang::List<const char*> getSlangSearchPaths(); + +void initializeRenderDoc(); +void renderDocBeginFrame(); +void renderDocEndFrame(); + +template<typename ImplFunc> +void runTestImpl( + const ImplFunc& f, + UnitTestContext* context, + Slang::RenderApiFlag::Enum api, + Slang::List<const char*> searchPaths = {}, + gfx::IDevice::ShaderCacheDesc shaderCache = {}) +{ + if ((api & context->enabledApis) == 0) { - Slang::List<uint8_t> expectedBuffer; - size_t bufferSize = sizeof(T) * count; - expectedBuffer.setCount(bufferSize); - memcpy(expectedBuffer.getBuffer(), expectedResult.begin(), bufferSize); - if (std::is_same<T, float>::value) return compareComputeResultFuzzy(device, buffer, (float*)expectedBuffer.getBuffer(), bufferSize); - return compareComputeResult(device, buffer, 0, expectedBuffer.getBuffer(), bufferSize); + SLANG_IGNORE_TEST } - - Slang::ComPtr<gfx::IDevice> createTestingDevice( - UnitTestContext* context, - Slang::RenderApiFlag::Enum api, - Slang::List<const char*> additionalSearchPaths = {}, - gfx::IDevice::ShaderCacheDesc shaderCache = {}); - - Slang::List<const char*> getSlangSearchPaths(); - - void initializeRenderDoc(); - void renderDocBeginFrame(); - void renderDocEndFrame(); - - template<typename ImplFunc> - void runTestImpl( - const ImplFunc& f, - UnitTestContext* context, - Slang::RenderApiFlag::Enum api, - Slang::List<const char*> searchPaths = {}, - gfx::IDevice::ShaderCacheDesc shaderCache = {}) + auto device = createTestingDevice(context, api, searchPaths, shaderCache); + if (!device) { - if ((api & context->enabledApis) == 0) - { - SLANG_IGNORE_TEST - } - auto device = createTestingDevice(context, api, searchPaths, shaderCache); - if (!device) - { - SLANG_IGNORE_TEST - } + SLANG_IGNORE_TEST + } #if SLANG_WIN32 - // Skip d3d12 tests on x86 now since dxc doesn't function correctly there on Windows 11. - if (api == Slang::RenderApiFlag::D3D12) - { - SLANG_IGNORE_TEST - } + // Skip d3d12 tests on x86 now since dxc doesn't function correctly there on Windows 11. + if (api == Slang::RenderApiFlag::D3D12) + { + SLANG_IGNORE_TEST + } #endif - // Skip d3d11 tests when we don't have DXBC support as they're bound to - // fail without a backend compiler - if (api == Slang::RenderApiFlag::D3D11 && !SLANG_ENABLE_DXBC_SUPPORT) - { - SLANG_IGNORE_TEST - } - try - { - renderDocBeginFrame(); - f(device, context); - } - catch (AbortTestException& e) - { - renderDocEndFrame(); - throw e; - } + // Skip d3d11 tests when we don't have DXBC support as they're bound to + // fail without a backend compiler + if (api == Slang::RenderApiFlag::D3D11 && !SLANG_ENABLE_DXBC_SUPPORT) + { + SLANG_IGNORE_TEST + } + try + { + renderDocBeginFrame(); + f(device, context); + } + catch (AbortTestException& e) + { renderDocEndFrame(); + throw e; } + renderDocEndFrame(); +} #define GFX_CHECK_CALL(x) SLANG_CHECK(!SLANG_FAILED(x)) #define GFX_CHECK_CALL_ABORT(x) SLANG_CHECK_ABORT(!SLANG_FAILED(x)) -} +} // namespace gfx_test diff --git a/tools/gfx-unit-test/instanced-draw-tests.cpp b/tools/gfx-unit-test/instanced-draw-tests.cpp index 6491e8944..adb1a1df1 100644 --- a/tools/gfx-unit-test/instanced-draw-tests.cpp +++ b/tools/gfx-unit-test/instanced-draw-tests.cpp @@ -1,550 +1,604 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - struct Vertex - { - float position[3]; - }; - - struct Instance - { - float position[3]; - float color[3]; - }; +struct Vertex +{ + float position[3]; +}; - static const int kVertexCount = 6; - static const Vertex kVertexData[kVertexCount] = - { - // Triangle 1 - { 0, 0, 0.5 }, - { 1, 0, 0.5 }, - { 0, 1, 0.5 }, - - // Triangle 2 - { -1, 0, 0.5 }, - { 0, 0, 0.5 }, - { -1, 1, 0.5 }, - }; +struct Instance +{ + float position[3]; + float color[3]; +}; + +static const int kVertexCount = 6; +static const Vertex kVertexData[kVertexCount] = { + // Triangle 1 + {0, 0, 0.5}, + {1, 0, 0.5}, + {0, 1, 0.5}, + + // Triangle 2 + {-1, 0, 0.5}, + {0, 0, 0.5}, + {-1, 1, 0.5}, +}; + +static const int kInstanceCount = 2; +static const Instance kInstanceData[kInstanceCount] = { + {{0, 0, 0}, {1, 0, 0}}, + {{0, -1, 0}, {0, 0, 1}}, +}; + +static const int kIndexCount = 6; +static const uint32_t kIndexData[kIndexCount] = { + 0, + 2, + 5, + 0, + 1, + 2, +}; + +const int kWidth = 256; +const int kHeight = 256; +const Format format = Format::R32G32B32A32_FLOAT; + +ComPtr<IBufferResource> createVertexBuffer(IDevice* device) +{ + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; + ComPtr<IBufferResource> vertexBuffer = + device->createBufferResource(vertexBufferDesc, &kVertexData[0]); + SLANG_CHECK_ABORT(vertexBuffer != nullptr); + return vertexBuffer; +} - static const int kInstanceCount = 2; - static const Instance kInstanceData[kInstanceCount] = - { - { { 0, 0, 0 }, { 1, 0, 0 } }, - { { 0, -1, 0 }, { 0, 0, 1 } }, - }; +ComPtr<IBufferResource> createInstanceBuffer(IDevice* device) +{ + IBufferResource::Desc instanceBufferDesc; + instanceBufferDesc.type = IResource::Type::Buffer; + instanceBufferDesc.sizeInBytes = kInstanceCount * sizeof(Instance); + instanceBufferDesc.defaultState = ResourceState::VertexBuffer; + instanceBufferDesc.allowedStates = ResourceState::VertexBuffer; + ComPtr<IBufferResource> instanceBuffer = + device->createBufferResource(instanceBufferDesc, &kInstanceData[0]); + SLANG_CHECK_ABORT(instanceBuffer != nullptr); + return instanceBuffer; +} - static const int kIndexCount = 6; - static const uint32_t kIndexData[kIndexCount] = - { - 0, 2, 5, - 0, 1, 2, - }; +ComPtr<IBufferResource> createIndexBuffer(IDevice* device) +{ + IBufferResource::Desc indexBufferDesc; + indexBufferDesc.type = IResource::Type::Buffer; + indexBufferDesc.sizeInBytes = kIndexCount * sizeof(uint32_t); + indexBufferDesc.defaultState = ResourceState::IndexBuffer; + indexBufferDesc.allowedStates = ResourceState::IndexBuffer; + ComPtr<IBufferResource> indexBuffer = + device->createBufferResource(indexBufferDesc, &kIndexData[0]); + SLANG_CHECK_ABORT(indexBuffer != nullptr); + return indexBuffer; +} - const int kWidth = 256; - const int kHeight = 256; - const Format format = Format::R32G32B32A32_FLOAT; +ComPtr<ITextureResource> createColorBuffer(IDevice* device) +{ + gfx::ITextureResource::Desc colorBufferDesc; + colorBufferDesc.type = IResource::Type::Texture2D; + colorBufferDesc.size.width = kWidth; + colorBufferDesc.size.height = kHeight; + colorBufferDesc.size.depth = 1; + colorBufferDesc.numMipLevels = 1; + colorBufferDesc.format = format; + colorBufferDesc.defaultState = ResourceState::RenderTarget; + colorBufferDesc.allowedStates = {ResourceState::RenderTarget, ResourceState::CopySource}; + ComPtr<ITextureResource> colorBuffer = device->createTextureResource(colorBufferDesc, nullptr); + SLANG_CHECK_ABORT(colorBuffer != nullptr); + return colorBuffer; +} - ComPtr<IBufferResource> createVertexBuffer(IDevice* device) - { - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; - ComPtr<IBufferResource> vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); - SLANG_CHECK_ABORT(vertexBuffer != nullptr); - return vertexBuffer; - } +class BaseDrawTest +{ +public: + ComPtr<IDevice> device; + UnitTestContext* context; - ComPtr<IBufferResource> createInstanceBuffer(IDevice* device) - { - IBufferResource::Desc instanceBufferDesc; - instanceBufferDesc.type = IResource::Type::Buffer; - instanceBufferDesc.sizeInBytes = kInstanceCount * sizeof(Instance); - instanceBufferDesc.defaultState = ResourceState::VertexBuffer; - instanceBufferDesc.allowedStates = ResourceState::VertexBuffer; - ComPtr<IBufferResource> instanceBuffer = device->createBufferResource(instanceBufferDesc, &kInstanceData[0]); - SLANG_CHECK_ABORT(instanceBuffer != nullptr); - return instanceBuffer; - } + ComPtr<ITransientResourceHeap> transientHeap; + ComPtr<IPipelineState> pipelineState; + ComPtr<IRenderPassLayout> renderPass; + ComPtr<IFramebuffer> framebuffer; - ComPtr<IBufferResource> createIndexBuffer(IDevice* device) - { - IBufferResource::Desc indexBufferDesc; - indexBufferDesc.type = IResource::Type::Buffer; - indexBufferDesc.sizeInBytes = kIndexCount * sizeof(uint32_t); - indexBufferDesc.defaultState = ResourceState::IndexBuffer; - indexBufferDesc.allowedStates = ResourceState::IndexBuffer; - ComPtr<IBufferResource> indexBuffer = device->createBufferResource(indexBufferDesc, &kIndexData[0]); - SLANG_CHECK_ABORT(indexBuffer != nullptr); - return indexBuffer; - } + ComPtr<IBufferResource> vertexBuffer; + ComPtr<IBufferResource> instanceBuffer; + ComPtr<ITextureResource> colorBuffer; - ComPtr<ITextureResource> createColorBuffer(IDevice* device) + void init(IDevice* device, UnitTestContext* context) { - gfx::ITextureResource::Desc colorBufferDesc; - colorBufferDesc.type = IResource::Type::Texture2D; - colorBufferDesc.size.width = kWidth; - colorBufferDesc.size.height = kHeight; - colorBufferDesc.size.depth = 1; - colorBufferDesc.numMipLevels = 1; - colorBufferDesc.format = format; - colorBufferDesc.defaultState = ResourceState::RenderTarget; - colorBufferDesc.allowedStates = { ResourceState::RenderTarget, ResourceState::CopySource }; - ComPtr<ITextureResource> colorBuffer = device->createTextureResource(colorBufferDesc, nullptr); - SLANG_CHECK_ABORT(colorBuffer != nullptr); - return colorBuffer; + this->device = device; + this->context = context; } - class BaseDrawTest + void createRequiredResources() { - public: - ComPtr<IDevice> device; - UnitTestContext* context; - - ComPtr<ITransientResourceHeap> transientHeap; - ComPtr<IPipelineState> pipelineState; - ComPtr<IRenderPassLayout> renderPass; - ComPtr<IFramebuffer> framebuffer; + VertexStreamDesc vertexStreams[] = { + {sizeof(Vertex), InputSlotClass::PerVertex, 0}, + {sizeof(Instance), InputSlotClass::PerInstance, 1}, + }; - ComPtr<IBufferResource> vertexBuffer; - ComPtr<IBufferResource> instanceBuffer; - ComPtr<ITextureResource> colorBuffer; + InputElementDesc inputElements[] = { + // Vertex buffer data + {"POSITIONA", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0}, - void init(IDevice* device, UnitTestContext* context) - { - this->device = device; - this->context = context; - } - - void createRequiredResources() - { - VertexStreamDesc vertexStreams[] = { - { sizeof(Vertex), InputSlotClass::PerVertex, 0 }, - { sizeof(Instance), InputSlotClass::PerInstance, 1 }, - }; - - InputElementDesc inputElements[] = { - // Vertex buffer data - { "POSITIONA", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0 }, - - // Instance buffer data - { "POSITIONB", 0, Format::R32G32B32_FLOAT, offsetof(Instance, position), 1 }, - { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Instance, color), 1 }, - }; - IInputLayout::Desc inputLayoutDesc = {}; - inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); - inputLayoutDesc.inputElements = inputElements; - inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); - inputLayoutDesc.vertexStreams = vertexStreams; - auto inputLayout = device->createInputLayout(inputLayoutDesc); - SLANG_CHECK_ABORT(inputLayout != nullptr); - - vertexBuffer = createVertexBuffer(device); - instanceBuffer = createInstanceBuffer(device); - colorBuffer = createColorBuffer(device); - - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadGraphicsProgram(device, shaderProgram, "graphics-smoke", "vertexMain", "fragmentMain", slangReflection)); - - IFramebufferLayout::TargetLayout targetLayout; - targetLayout.format = format; - targetLayout.sampleCount = 1; - - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &targetLayout; - ComPtr<gfx::IFramebufferLayout> framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc); - SLANG_CHECK_ABORT(framebufferLayout != nullptr); - - GraphicsPipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - pipelineDesc.inputLayout = inputLayout; - pipelineDesc.framebufferLayout = framebufferLayout; - pipelineDesc.depthStencil.depthTestEnable = false; - pipelineDesc.depthStencil.depthWriteEnable = false; - GFX_CHECK_CALL_ABORT( - device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); - - IRenderPassLayout::Desc renderPassDesc = {}; - renderPassDesc.framebufferLayout = framebufferLayout; - renderPassDesc.renderTargetCount = 1; - IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; - renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; - renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; - renderTargetAccess.initialState = ResourceState::RenderTarget; - renderTargetAccess.finalState = ResourceState::CopySource; - renderPassDesc.renderTargetAccess = &renderTargetAccess; - GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); - - gfx::IResourceView::Desc colorBufferViewDesc; - memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); - colorBufferViewDesc.format = format; - colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; - colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; - auto rtv = device->createTextureView(colorBuffer, colorBufferViewDesc); - - gfx::IFramebuffer::Desc framebufferDesc; - framebufferDesc.renderTargetCount = 1; - framebufferDesc.depthStencilView = nullptr; - framebufferDesc.renderTargetViews = rtv.readRef(); - framebufferDesc.layout = framebufferLayout; - GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); - } + // Instance buffer data + {"POSITIONB", 0, Format::R32G32B32_FLOAT, offsetof(Instance, position), 1}, + {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Instance, color), 1}, + }; + IInputLayout::Desc inputLayoutDesc = {}; + inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); + inputLayoutDesc.inputElements = inputElements; + inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); + inputLayoutDesc.vertexStreams = vertexStreams; + auto inputLayout = device->createInputLayout(inputLayoutDesc); + SLANG_CHECK_ABORT(inputLayout != nullptr); + + vertexBuffer = createVertexBuffer(device); + instanceBuffer = createInstanceBuffer(device); + colorBuffer = createColorBuffer(device); + + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadGraphicsProgram( + device, + shaderProgram, + "graphics-smoke", + "vertexMain", + "fragmentMain", + slangReflection)); + + IFramebufferLayout::TargetLayout targetLayout; + targetLayout.format = format; + targetLayout.sampleCount = 1; + + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &targetLayout; + ComPtr<gfx::IFramebufferLayout> framebufferLayout = + device->createFramebufferLayout(framebufferLayoutDesc); + SLANG_CHECK_ABORT(framebufferLayout != nullptr); + + GraphicsPipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + pipelineDesc.inputLayout = inputLayout; + pipelineDesc.framebufferLayout = framebufferLayout; + pipelineDesc.depthStencil.depthTestEnable = false; + pipelineDesc.depthStencil.depthWriteEnable = false; + GFX_CHECK_CALL_ABORT( + device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); + + IRenderPassLayout::Desc renderPassDesc = {}; + renderPassDesc.framebufferLayout = framebufferLayout; + renderPassDesc.renderTargetCount = 1; + IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; + renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; + renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; + renderTargetAccess.initialState = ResourceState::RenderTarget; + renderTargetAccess.finalState = ResourceState::CopySource; + renderPassDesc.renderTargetAccess = &renderTargetAccess; + GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = format; + colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; + auto rtv = device->createTextureView(colorBuffer, colorBufferViewDesc); + + gfx::IFramebuffer::Desc framebufferDesc; + framebufferDesc.renderTargetCount = 1; + framebufferDesc.depthStencilView = nullptr; + framebufferDesc.renderTargetViews = rtv.readRef(); + framebufferDesc.layout = framebufferLayout; + GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); + } - void checkTestResults(int pixelCount, int channelCount, const int* testXCoords, const int* testYCoords, float* testResults) + void checkTestResults( + int pixelCount, + int channelCount, + const int* testXCoords, + const int* testYCoords, + float* testResults) + { + // Read texture values back from four specific pixels located within the triangles + // and compare against expected values (because testing every single pixel will be too long + // and tedious and requires maintaining reference images). + ComPtr<ISlangBlob> resultBlob; + size_t rowPitch = 0; + size_t pixelSize = 0; + GFX_CHECK_CALL_ABORT(device->readTextureResource( + colorBuffer, + ResourceState::CopySource, + resultBlob.writeRef(), + &rowPitch, + &pixelSize)); + auto result = (float*)resultBlob->getBufferPointer(); + + int cursor = 0; + for (int i = 0; i < pixelCount; ++i) { - // Read texture values back from four specific pixels located within the triangles - // and compare against expected values (because testing every single pixel will be too long and tedious - // and requires maintaining reference images). - ComPtr<ISlangBlob> resultBlob; - size_t rowPitch = 0; - size_t pixelSize = 0; - GFX_CHECK_CALL_ABORT(device->readTextureResource( - colorBuffer, ResourceState::CopySource, resultBlob.writeRef(), &rowPitch, &pixelSize)); - auto result = (float*)resultBlob->getBufferPointer(); - - int cursor = 0; - for (int i = 0; i < pixelCount; ++i) + auto x = testXCoords[i]; + auto y = testYCoords[i]; + auto pixelPtr = result + x * channelCount + y * rowPitch / sizeof(float); + for (int j = 0; j < channelCount; ++j) { - auto x = testXCoords[i]; - auto y = testYCoords[i]; - auto pixelPtr = result + x * channelCount + y * rowPitch / sizeof(float); - for (int j = 0; j < channelCount; ++j) - { - testResults[cursor] = pixelPtr[j]; - cursor++; - } + testResults[cursor] = pixelPtr[j]; + cursor++; } - - float expectedResult[] = { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; - compareComputeResultFuzzy(testResults, expectedResult, sizeof(expectedResult)); } - }; - struct DrawInstancedTest : BaseDrawTest + float expectedResult[] = { + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f}; + compareComputeResultFuzzy(testResults, expectedResult, sizeof(expectedResult)); + } +}; + +struct DrawInstancedTest : BaseDrawTest +{ + void setUpAndDraw() { - void setUpAndDraw() - { - createRequiredResources(); + createRequiredResources(); - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); - auto rootObject = encoder->bindPipeline(pipelineState); + auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); + auto rootObject = encoder->bindPipeline(pipelineState); - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = kWidth; - viewport.extentY = kHeight; - encoder->setViewportAndScissor(viewport); + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = kWidth; + viewport.extentY = kHeight; + encoder->setViewportAndScissor(viewport); - uint32_t startVertex = 0; - uint32_t startInstanceLocation = 0; + uint32_t startVertex = 0; + uint32_t startInstanceLocation = 0; - encoder->setVertexBuffer(0, vertexBuffer); - encoder->setVertexBuffer(1, instanceBuffer); - encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + encoder->setVertexBuffer(0, vertexBuffer); + encoder->setVertexBuffer(1, instanceBuffer); + encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - encoder->drawInstanced(kVertexCount, kInstanceCount, startVertex, startInstanceLocation); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + encoder->drawInstanced(kVertexCount, kInstanceCount, startVertex, startInstanceLocation); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - void run() - { - setUpAndDraw(); + void run() + { + setUpAndDraw(); - const int kPixelCount = 4; - const int kChannelCount = 4; - int testXCoords[kPixelCount] = { 64, 192, 64, 192 }; - int testYCoords[kPixelCount] = { 100, 100, 250, 250 }; - float testResults[kPixelCount * kChannelCount]; + const int kPixelCount = 4; + const int kChannelCount = 4; + int testXCoords[kPixelCount] = {64, 192, 64, 192}; + int testYCoords[kPixelCount] = {100, 100, 250, 250}; + float testResults[kPixelCount * kChannelCount]; - checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); - } - }; + checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); + } +}; + +struct DrawIndexedInstancedTest : BaseDrawTest +{ + ComPtr<IBufferResource> indexBuffer; - struct DrawIndexedInstancedTest : BaseDrawTest + void setUpAndDraw() { - ComPtr<IBufferResource> indexBuffer; + createRequiredResources(); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + auto commandBuffer = transientHeap->createCommandBuffer(); + + auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); + auto rootObject = encoder->bindPipeline(pipelineState); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = kWidth; + viewport.extentY = kHeight; + encoder->setViewportAndScissor(viewport); + + uint32_t startIndex = 0; + int32_t startVertex = 0; + uint32_t startInstanceLocation = 0; + + encoder->setVertexBuffer(0, vertexBuffer); + encoder->setVertexBuffer(1, instanceBuffer); + encoder->setIndexBuffer(indexBuffer, Format::R32_UINT); + encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + + encoder->drawIndexedInstanced( + kIndexCount, + kInstanceCount, + startIndex, + startVertex, + startInstanceLocation); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - void setUpAndDraw() - { - createRequiredResources(); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - - auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); - auto rootObject = encoder->bindPipeline(pipelineState); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = kWidth; - viewport.extentY = kHeight; - encoder->setViewportAndScissor(viewport); - - uint32_t startIndex = 0; - int32_t startVertex = 0; - uint32_t startInstanceLocation = 0; - - encoder->setVertexBuffer(0, vertexBuffer); - encoder->setVertexBuffer(1, instanceBuffer); - encoder->setIndexBuffer(indexBuffer, Format::R32_UINT); - encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - - encoder->drawIndexedInstanced(kIndexCount, kInstanceCount, startIndex, startVertex, startInstanceLocation); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + void run() + { + indexBuffer = createIndexBuffer(device); - void run() - { - indexBuffer = createIndexBuffer(device); + setUpAndDraw(); - setUpAndDraw(); + const int kPixelCount = 4; + const int kChannelCount = 4; + int testXCoords[kPixelCount] = {64, 192, 64, 192}; + int testYCoords[kPixelCount] = {32, 100, 150, 250}; + float testResults[kPixelCount * kChannelCount]; - const int kPixelCount = 4; - const int kChannelCount = 4; - int testXCoords[kPixelCount] = { 64, 192, 64, 192 }; - int testYCoords[kPixelCount] = { 32, 100, 150, 250 }; - float testResults[kPixelCount * kChannelCount]; + checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); + } +}; - checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); - } - }; +struct DrawIndirectTest : BaseDrawTest +{ + ComPtr<IBufferResource> indirectBuffer; - struct DrawIndirectTest : BaseDrawTest + struct IndirectArgData { - ComPtr<IBufferResource> indirectBuffer; + float padding; // Ensure args and count don't start at 0 offset for testing purposes + IndirectDrawArguments args; + }; - struct IndirectArgData - { - float padding; // Ensure args and count don't start at 0 offset for testing purposes - IndirectDrawArguments args; + ComPtr<IBufferResource> createIndirectBuffer(IDevice* device) + { + static const IndirectArgData kIndirectData = { + 42.0f, // padding + {6, 2, 0, 0}, // args }; - ComPtr<IBufferResource> createIndirectBuffer(IDevice* device) - { - static const IndirectArgData kIndirectData = - { - 42.0f, // padding - {6, 2, 0, 0}, // args - }; - - IBufferResource::Desc indirectBufferDesc; - indirectBufferDesc.type = IResource::Type::Buffer; - indirectBufferDesc.sizeInBytes = sizeof(IndirectArgData); - indirectBufferDesc.defaultState = ResourceState::IndirectArgument; - indirectBufferDesc.allowedStates = ResourceState::IndirectArgument; - ComPtr<IBufferResource> indirectBuffer = device->createBufferResource(indirectBufferDesc, &kIndirectData); - SLANG_CHECK_ABORT(indirectBuffer != nullptr); - return indirectBuffer; - } - - void setUpAndDraw() - { - createRequiredResources(); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); + IBufferResource::Desc indirectBufferDesc; + indirectBufferDesc.type = IResource::Type::Buffer; + indirectBufferDesc.sizeInBytes = sizeof(IndirectArgData); + indirectBufferDesc.defaultState = ResourceState::IndirectArgument; + indirectBufferDesc.allowedStates = ResourceState::IndirectArgument; + ComPtr<IBufferResource> indirectBuffer = + device->createBufferResource(indirectBufferDesc, &kIndirectData); + SLANG_CHECK_ABORT(indirectBuffer != nullptr); + return indirectBuffer; + } - auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); - auto rootObject = encoder->bindPipeline(pipelineState); + void setUpAndDraw() + { + createRequiredResources(); - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = kWidth; - viewport.extentY = kHeight; - encoder->setViewportAndScissor(viewport); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + auto commandBuffer = transientHeap->createCommandBuffer(); - encoder->setVertexBuffer(0, vertexBuffer); - encoder->setVertexBuffer(1, instanceBuffer); - encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); + auto rootObject = encoder->bindPipeline(pipelineState); - uint32_t maxDrawCount = 1; - Offset argOffset = offsetof(IndirectArgData, args); + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = kWidth; + viewport.extentY = kHeight; + encoder->setViewportAndScissor(viewport); - encoder->drawIndirect(maxDrawCount, indirectBuffer, argOffset); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - void run() - { - indirectBuffer = createIndirectBuffer(device); + encoder->setVertexBuffer(0, vertexBuffer); + encoder->setVertexBuffer(1, instanceBuffer); + encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - setUpAndDraw(); + uint32_t maxDrawCount = 1; + Offset argOffset = offsetof(IndirectArgData, args); - const int kPixelCount = 4; - const int kChannelCount = 4; - int testXCoords[kPixelCount] = { 64, 192, 64, 192 }; - int testYCoords[kPixelCount] = { 100, 100, 250, 250 }; - float testResults[kPixelCount * kChannelCount]; - - checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); - } - }; + encoder->drawIndirect(maxDrawCount, indirectBuffer, argOffset); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - struct DrawIndexedIndirectTest : BaseDrawTest + void run() { - ComPtr<IBufferResource> indexBuffer; - ComPtr<IBufferResource> indirectBuffer; - - struct IndexedIndirectArgData - { - float padding; // Ensure args and count don't start at 0 offset for testing purposes - IndirectDrawIndexedArguments args; - }; - - ComPtr<IBufferResource> createIndirectBuffer(IDevice* device) - { - static const IndexedIndirectArgData kIndexedIndirectData = - { - 42.0f, // padding - {6, 2, 0, 0, 0}, // args - }; - - IBufferResource::Desc indirectBufferDesc; - indirectBufferDesc.type = IResource::Type::Buffer; - indirectBufferDesc.sizeInBytes = sizeof(IndexedIndirectArgData); - indirectBufferDesc.defaultState = ResourceState::IndirectArgument; - indirectBufferDesc.allowedStates = ResourceState::IndirectArgument; - ComPtr<IBufferResource> indexBuffer = device->createBufferResource(indirectBufferDesc, &kIndexedIndirectData); - SLANG_CHECK_ABORT(indexBuffer != nullptr); - return indexBuffer; - } + indirectBuffer = createIndirectBuffer(device); - void setUpAndDraw() - { - createRequiredResources(); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - - auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); - auto rootObject = encoder->bindPipeline(pipelineState); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = kWidth; - viewport.extentY = kHeight; - encoder->setViewportAndScissor(viewport); - - encoder->setVertexBuffer(0, vertexBuffer); - encoder->setVertexBuffer(1, instanceBuffer); - encoder->setIndexBuffer(indexBuffer, Format::R32_UINT); - encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - - uint32_t maxDrawCount = 1; - Offset argOffset = offsetof(IndexedIndirectArgData, args); - - encoder->drawIndexedIndirect(maxDrawCount, indirectBuffer, argOffset); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + setUpAndDraw(); - void run() - { - indexBuffer = createIndexBuffer(device); - indirectBuffer = createIndirectBuffer(device); + const int kPixelCount = 4; + const int kChannelCount = 4; + int testXCoords[kPixelCount] = {64, 192, 64, 192}; + int testYCoords[kPixelCount] = {100, 100, 250, 250}; + float testResults[kPixelCount * kChannelCount]; - setUpAndDraw(); + checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); + } +}; - const int kPixelCount = 4; - const int kChannelCount = 4; - int testXCoords[kPixelCount] = { 64, 192, 64, 192 }; - int testYCoords[kPixelCount] = { 32, 100, 150, 250 }; - float testResults[kPixelCount * kChannelCount]; +struct DrawIndexedIndirectTest : BaseDrawTest +{ + ComPtr<IBufferResource> indexBuffer; + ComPtr<IBufferResource> indirectBuffer; - checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); - } + struct IndexedIndirectArgData + { + float padding; // Ensure args and count don't start at 0 offset for testing purposes + IndirectDrawIndexedArguments args; }; - template <typename T> - void drawTestImpl(IDevice* device, UnitTestContext* context) + ComPtr<IBufferResource> createIndirectBuffer(IDevice* device) { - T test; - test.init(device, context); - test.run(); - } + static const IndexedIndirectArgData kIndexedIndirectData = { + 42.0f, // padding + {6, 2, 0, 0, 0}, // args + }; - SLANG_UNIT_TEST(drawInstancedD3D11) - { - runTestImpl(drawTestImpl<DrawInstancedTest>, unitTestContext, Slang::RenderApiFlag::D3D11); + IBufferResource::Desc indirectBufferDesc; + indirectBufferDesc.type = IResource::Type::Buffer; + indirectBufferDesc.sizeInBytes = sizeof(IndexedIndirectArgData); + indirectBufferDesc.defaultState = ResourceState::IndirectArgument; + indirectBufferDesc.allowedStates = ResourceState::IndirectArgument; + ComPtr<IBufferResource> indexBuffer = + device->createBufferResource(indirectBufferDesc, &kIndexedIndirectData); + SLANG_CHECK_ABORT(indexBuffer != nullptr); + return indexBuffer; } - SLANG_UNIT_TEST(drawIndexedInstancedD3D11) + void setUpAndDraw() { - runTestImpl(drawTestImpl<DrawIndexedInstancedTest>, unitTestContext, Slang::RenderApiFlag::D3D11); + createRequiredResources(); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + auto commandBuffer = transientHeap->createCommandBuffer(); + + auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); + auto rootObject = encoder->bindPipeline(pipelineState); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = kWidth; + viewport.extentY = kHeight; + encoder->setViewportAndScissor(viewport); + + encoder->setVertexBuffer(0, vertexBuffer); + encoder->setVertexBuffer(1, instanceBuffer); + encoder->setIndexBuffer(indexBuffer, Format::R32_UINT); + encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + + uint32_t maxDrawCount = 1; + Offset argOffset = offsetof(IndexedIndirectArgData, args); + + encoder->drawIndexedIndirect(maxDrawCount, indirectBuffer, argOffset); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(drawInstancedD3D12) + void run() { - runTestImpl(drawTestImpl<DrawInstancedTest>, unitTestContext, Slang::RenderApiFlag::D3D12); - } + indexBuffer = createIndexBuffer(device); + indirectBuffer = createIndirectBuffer(device); - SLANG_UNIT_TEST(drawIndexedInstancedD3D12) - { - runTestImpl(drawTestImpl<DrawIndexedInstancedTest>, unitTestContext, Slang::RenderApiFlag::D3D12); - } + setUpAndDraw(); - SLANG_UNIT_TEST(drawIndirectD3D12) - { - runTestImpl(drawTestImpl<DrawIndirectTest>, unitTestContext, Slang::RenderApiFlag::D3D12); - } + const int kPixelCount = 4; + const int kChannelCount = 4; + int testXCoords[kPixelCount] = {64, 192, 64, 192}; + int testYCoords[kPixelCount] = {32, 100, 150, 250}; + float testResults[kPixelCount * kChannelCount]; - SLANG_UNIT_TEST(drawIndexedIndirectD3D12) - { - runTestImpl(drawTestImpl<DrawIndexedIndirectTest>, unitTestContext, Slang::RenderApiFlag::D3D12); + checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); } +}; - SLANG_UNIT_TEST(drawInstancedVulkan) - { - runTestImpl(drawTestImpl<DrawInstancedTest>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +template<typename T> +void drawTestImpl(IDevice* device, UnitTestContext* context) +{ + T test; + test.init(device, context); + test.run(); +} - SLANG_UNIT_TEST(drawIndexedInstancedVulkan) - { - runTestImpl(drawTestImpl<DrawIndexedInstancedTest>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(drawInstancedD3D11) +{ + runTestImpl(drawTestImpl<DrawInstancedTest>, unitTestContext, Slang::RenderApiFlag::D3D11); +} - SLANG_UNIT_TEST(drawIndirectVulkan) - { - runTestImpl(drawTestImpl<DrawIndirectTest>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(drawIndexedInstancedD3D11) +{ + runTestImpl( + drawTestImpl<DrawIndexedInstancedTest>, + unitTestContext, + Slang::RenderApiFlag::D3D11); +} - SLANG_UNIT_TEST(drawIndexedIndirectVulkan) - { - runTestImpl(drawTestImpl<DrawIndexedIndirectTest>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(drawInstancedD3D12) +{ + runTestImpl(drawTestImpl<DrawInstancedTest>, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(drawIndexedInstancedD3D12) +{ + runTestImpl( + drawTestImpl<DrawIndexedInstancedTest>, + unitTestContext, + Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(drawIndirectD3D12) +{ + runTestImpl(drawTestImpl<DrawIndirectTest>, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(drawIndexedIndirectD3D12) +{ + runTestImpl( + drawTestImpl<DrawIndexedIndirectTest>, + unitTestContext, + Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(drawInstancedVulkan) +{ + runTestImpl(drawTestImpl<DrawInstancedTest>, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(drawIndexedInstancedVulkan) +{ + runTestImpl( + drawTestImpl<DrawIndexedInstancedTest>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(drawIndirectVulkan) +{ + runTestImpl(drawTestImpl<DrawIndirectTest>, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(drawIndexedIndirectVulkan) +{ + runTestImpl( + drawTestImpl<DrawIndexedIndirectTest>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/link-time-constant.cpp b/tools/gfx-unit-test/link-time-constant.cpp index a80a23c0c..047ecd3bc 100644 --- a/tools/gfx-unit-test/link-time-constant.cpp +++ b/tools/gfx-unit-test/link-time-constant.cpp @@ -1,162 +1,163 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" #include "source/core/slang-blob.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - static Slang::Result loadProgram( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - const char* shaderModuleName, - const char* entryPointName, - slang::ProgramLayout*& slangReflection, - const char* additionalModuleSource) - { - Slang::ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if (!module) - return SLANG_FAIL; - - auto additionalModuleBlob = Slang::UnownedRawBlob::create(additionalModuleSource, strlen(additionalModuleSource)); - slang::IModule* additionalModule = slangSession->loadModuleFromSource("linkedConstants", "path", - additionalModuleBlob); - - ComPtr<slang::IEntryPoint> computeEntryPoint; - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(module); - componentTypes.add(computeEntryPoint); - componentTypes.add(additionalModule); - - Slang::ComPtr<slang::IComponentType> composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - ComPtr<slang::IComponentType> linkedProgram; - result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - composedProgram = linkedProgram; - slangReflection = composedProgram->getLayout(); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = composedProgram.get(); - - auto shaderProgram = device->createProgram(programDesc); - - outShaderProgram = shaderProgram; - return SLANG_OK; - } +static Slang::Result loadProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + const char* shaderModuleName, + const char* entryPointName, + slang::ProgramLayout*& slangReflection, + const char* additionalModuleSource) +{ + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + auto additionalModuleBlob = + Slang::UnownedRawBlob::create(additionalModuleSource, strlen(additionalModuleSource)); + slang::IModule* additionalModule = + slangSession->loadModuleFromSource("linkedConstants", "path", additionalModuleBlob); + + ComPtr<slang::IEntryPoint> computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(module); + componentTypes.add(computeEntryPoint); + componentTypes.add(additionalModule); + + Slang::ComPtr<slang::IComponentType> composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + ComPtr<slang::IComponentType> linkedProgram; + result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + composedProgram = linkedProgram; + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; +} - void linkTimeConstantTestImpl(IDevice* device, UnitTestContext* context) - { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram, "link-time-constant", "computeMain", slangReflection, - R"( +void linkTimeConstantTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadProgram( + device, + shaderProgram, + "link-time-constant", + "computeMain", + slangReflection, + R"( export static const bool turnOnFeature = true; export static const float constValue = 2.0; export static const uint numthread = 2; export static const int arraySize = 4; )")); - - SlangUInt threadGroupSizes[3]; - slangReflection->findEntryPointByName("computeMain")->getComputeThreadGroupSize(3, threadGroupSizes); - SLANG_CHECK(threadGroupSizes[0] == 2 && threadGroupSizes[1] == 1 && threadGroupSizes[2] == 1); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(2.0)); - } - SLANG_UNIT_TEST(linkTimeConstantD3D12) + SlangUInt threadGroupSizes[3]; + slangReflection->findEntryPointByName("computeMain") + ->getComputeThreadGroupSize(3, threadGroupSizes); + SLANG_CHECK(threadGroupSizes[0] == 2 && threadGroupSizes[1] == 1 && threadGroupSizes[2] == 1); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - runTestImpl(linkTimeConstantTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - SLANG_UNIT_TEST(linkTimeConstantVulkan) - { - runTestImpl(linkTimeConstantTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(2.0)); } + +SLANG_UNIT_TEST(linkTimeConstantD3D12) +{ + runTestImpl(linkTimeConstantTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(linkTimeConstantVulkan) +{ + runTestImpl(linkTimeConstantTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/link-time-default.cpp b/tools/gfx-unit-test/link-time-default.cpp index be9198b82..d341e5dc0 100644 --- a/tools/gfx-unit-test/link-time-default.cpp +++ b/tools/gfx-unit-test/link-time-default.cpp @@ -1,22 +1,21 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" #include "source/core/slang-blob.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - static Slang::Result loadProgram( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - slang::ProgramLayout*& slangReflection, - bool linkSpecialization = false) - { - const char* moduleInterfaceSrc = R"( +static Slang::Result loadProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + slang::ProgramLayout*& slangReflection, + bool linkSpecialization = false) +{ + const char* moduleInterfaceSrc = R"( interface IFoo { static const int offset; @@ -47,7 +46,7 @@ namespace gfx_test } }; )"; - const char* module0Src = R"( + const char* module0Src = R"( import ifoo; extern struct Foo : IFoo = FooImpl; extern static const float c = 0.0; @@ -59,179 +58,170 @@ namespace gfx_test buffer[0] = foo.getValue() + foo.val2 + Foo.offset + c; } )"; - const char* module1Src = R"( + const char* module1Src = R"( import ifoo; export struct Foo : IFoo = BarImpl; export static const float c = 1.0; )"; - Slang::ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - auto moduleInterfaceBlob = Slang::UnownedRawBlob::create(moduleInterfaceSrc, strlen(moduleInterfaceSrc)); - auto module0Blob = Slang::UnownedRawBlob::create(module0Src, strlen(module0Src)); - auto module1Blob = Slang::UnownedRawBlob::create(module1Src, strlen(module1Src)); - slang::IModule* moduleInterface = slangSession->loadModuleFromSource("ifoo", "ifoo.slang", - moduleInterfaceBlob); - slang::IModule* module0 = slangSession->loadModuleFromSource("module0", "path0", - module0Blob); - slang::IModule* module1 = slangSession->loadModuleFromSource("module1", "path1", - module1Blob); - ComPtr<slang::IEntryPoint> computeEntryPoint; - SLANG_RETURN_ON_FAIL( - module0->findEntryPointByName("computeMain", computeEntryPoint.writeRef())); - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(moduleInterface); - componentTypes.add(module0); - if (linkSpecialization) - componentTypes.add(module1); - componentTypes.add(computeEntryPoint); - - Slang::ComPtr<slang::IComponentType> composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - ComPtr<slang::IComponentType> linkedProgram; - result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - composedProgram = linkedProgram; - slangReflection = composedProgram->getLayout(); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = composedProgram.get(); - - auto shaderProgram = device->createProgram(programDesc); - - outShaderProgram = shaderProgram; - return SLANG_OK; - } + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + auto moduleInterfaceBlob = + Slang::UnownedRawBlob::create(moduleInterfaceSrc, strlen(moduleInterfaceSrc)); + auto module0Blob = Slang::UnownedRawBlob::create(module0Src, strlen(module0Src)); + auto module1Blob = Slang::UnownedRawBlob::create(module1Src, strlen(module1Src)); + slang::IModule* moduleInterface = + slangSession->loadModuleFromSource("ifoo", "ifoo.slang", moduleInterfaceBlob); + slang::IModule* module0 = slangSession->loadModuleFromSource("module0", "path0", module0Blob); + slang::IModule* module1 = slangSession->loadModuleFromSource("module1", "path1", module1Blob); + ComPtr<slang::IEntryPoint> computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module0->findEntryPointByName("computeMain", computeEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(moduleInterface); + componentTypes.add(module0); + if (linkSpecialization) + componentTypes.add(module1); + componentTypes.add(computeEntryPoint); + + Slang::ComPtr<slang::IComponentType> composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + ComPtr<slang::IComponentType> linkedProgram; + result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + composedProgram = linkedProgram; + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; +} - void linkTimeDefaultTestImpl(IDevice* device, UnitTestContext* context) +void linkTimeDefaultTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + // Create pipeline without linking a specialization override module, so we should + // see the default value of `extern Foo`. + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram, slangReflection, false)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + // Create pipeline with a specialization override module linked in, so we should + // see the result of using `Bar` for `extern Foo`. + ComPtr<IShaderProgram> shaderProgram1; + GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram1, slangReflection, true)); + + ComputePipelineStateDesc pipelineDesc1 = {}; + pipelineDesc1.program = shaderProgram1.get(); + ComPtr<gfx::IPipelineState> pipelineState1; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc1, pipelineState1.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - // Create pipeline without linking a specialization override module, so we should - // see the default value of `extern Foo`. - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram, slangReflection, false)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - // Create pipeline with a specialization override module linked in, so we should - // see the result of using `Bar` for `extern Foo`. - ComPtr<IShaderProgram> shaderProgram1; - GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram1, slangReflection, true)); - - ComputePipelineStateDesc pipelineDesc1 = {}; - pipelineDesc1.program = shaderProgram1.get(); - ComPtr<gfx::IPipelineState> pipelineState1; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc1, pipelineState1.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(8.0)); - - // Now run again with the overrided program. - { - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState1); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(10.0)); - } + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - SLANG_UNIT_TEST(linkTimeDefaultD3D12) - { - runTestImpl(linkTimeDefaultTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(linkTimeDefaultVulkan) + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(8.0)); + + // Now run again with the overrided program. { - runTestImpl(linkTimeDefaultTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState1); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(10.0)); } + +SLANG_UNIT_TEST(linkTimeDefaultD3D12) +{ + runTestImpl(linkTimeDefaultTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(linkTimeDefaultVulkan) +{ + runTestImpl(linkTimeDefaultTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/link-time-options.cpp b/tools/gfx-unit-test/link-time-options.cpp index f14a918e8..590db576e 100644 --- a/tools/gfx-unit-test/link-time-options.cpp +++ b/tools/gfx-unit-test/link-time-options.cpp @@ -1,152 +1,148 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" #include "source/core/slang-blob.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - // In this test, - // we will run a compute shader that compiles to HLSL with a reference to the macro "DOWNSTREAM_VALUE" - // that will be provided to dxc through slang's link-time compiler options. - // The test verifies that `IComponentType2::linkWithOptions()` is able to produce a linked IComponentType - // with additional compiler options. Here we will specify a DownstreamArg compiler option to define - // the value of DOWNSTREAM_VALUE when running dxc. - // - static Slang::Result loadProgram( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - const char* shaderModuleName, - const char* entryPointName, - slang::ProgramLayout*& slangReflection) - { - Slang::ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if (!module) - return SLANG_FAIL; - - ComPtr<slang::IEntryPoint> computeEntryPoint; - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(module); - componentTypes.add(computeEntryPoint); - - Slang::ComPtr<slang::IComponentType> composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - ComPtr<slang::IComponentType> linkedProgram; - slang::CompilerOptionEntry entry; - entry.name = slang::CompilerOptionName::DownstreamArgs; - entry.value.kind = slang::CompilerOptionValueKind::String; - entry.value.stringValue0 = "dxc"; - entry.value.stringValue1 = "-DDOWNSTREAM_VALUE=4.0"; - result = composedProgram->linkWithOptions(linkedProgram.writeRef(), 1, &entry, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - composedProgram = linkedProgram; - slangReflection = composedProgram->getLayout(); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = composedProgram.get(); - - auto shaderProgram = device->createProgram(programDesc); - - outShaderProgram = shaderProgram; - return SLANG_OK; - } +// In this test, +// we will run a compute shader that compiles to HLSL with a reference to the macro +// "DOWNSTREAM_VALUE" that will be provided to dxc through slang's link-time compiler options. The +// test verifies that `IComponentType2::linkWithOptions()` is able to produce a linked +// IComponentType with additional compiler options. Here we will specify a DownstreamArg compiler +// option to define the value of DOWNSTREAM_VALUE when running dxc. +// +static Slang::Result loadProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + const char* shaderModuleName, + const char* entryPointName, + slang::ProgramLayout*& slangReflection) +{ + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + ComPtr<slang::IEntryPoint> computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(module); + componentTypes.add(computeEntryPoint); + + Slang::ComPtr<slang::IComponentType> composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + ComPtr<slang::IComponentType> linkedProgram; + slang::CompilerOptionEntry entry; + entry.name = slang::CompilerOptionName::DownstreamArgs; + entry.value.kind = slang::CompilerOptionValueKind::String; + entry.value.stringValue0 = "dxc"; + entry.value.stringValue1 = "-DDOWNSTREAM_VALUE=4.0"; + result = composedProgram + ->linkWithOptions(linkedProgram.writeRef(), 1, &entry, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + composedProgram = linkedProgram; + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; +} - void linkTimeOptionTestImpl(IDevice* device, UnitTestContext* context) +void linkTimeOptionTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT( + loadProgram(device, shaderProgram, "link-time-options", "computeMain", slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram, "link-time-options", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(4.0)); - } + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - SLANG_UNIT_TEST(linkTimeOptionD3D12) - { - runTestImpl(linkTimeOptionTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(4.0)); +} + +SLANG_UNIT_TEST(linkTimeOptionD3D12) +{ + runTestImpl(linkTimeOptionTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/link-time-type.cpp b/tools/gfx-unit-test/link-time-type.cpp index 39496b3fe..81c738126 100644 --- a/tools/gfx-unit-test/link-time-type.cpp +++ b/tools/gfx-unit-test/link-time-type.cpp @@ -1,21 +1,20 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" #include "source/core/slang-blob.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - static Slang::Result loadProgram( - gfx::IDevice* device, - Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, - slang::ProgramLayout*& slangReflection) - { - const char* moduleInterfaceSrc = R"( +static Slang::Result loadProgram( + gfx::IDevice* device, + Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, + slang::ProgramLayout*& slangReflection) +{ + const char* moduleInterfaceSrc = R"( interface IBase : IDifferentiable { [Differentiable] @@ -50,7 +49,7 @@ namespace gfx_test __init(int x) { val = x; } }; )"; - const char* module0Src = R"( + const char* module0Src = R"( import ifoo; extern struct Foo : IFoo; @@ -62,139 +61,133 @@ namespace gfx_test buffer[0] = foo.getValue() + foo.val2 + Foo.offset + foo.getBaseValue(); } )"; - const char* module1Src = R"( + const char* module1Src = R"( import ifoo; export struct Foo : IFoo = FooImpl;)"; - Slang::ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - auto moduleInterfaceBlob = Slang::UnownedRawBlob::create(moduleInterfaceSrc, strlen(moduleInterfaceSrc)); - auto module0Blob = Slang::UnownedRawBlob::create(module0Src, strlen(module0Src)); - auto module1Blob = Slang::UnownedRawBlob::create(module1Src, strlen(module1Src)); - slang::IModule* moduleInterface = slangSession->loadModuleFromSource("ifoo", "ifoo.slang", - moduleInterfaceBlob); - slang::IModule* module0 = slangSession->loadModuleFromSource("module0", "path0", - module0Blob); - slang::IModule* module1 = slangSession->loadModuleFromSource("module1", "path1", - module1Blob); - ComPtr<slang::IEntryPoint> computeEntryPoint; - SLANG_RETURN_ON_FAIL( - module0->findEntryPointByName("computeMain", computeEntryPoint.writeRef())); - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(moduleInterface); - componentTypes.add(module0); - componentTypes.add(module1); - componentTypes.add(computeEntryPoint); - - Slang::ComPtr<slang::IComponentType> composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - ComPtr<slang::IComponentType> linkedProgram; - result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - composedProgram = linkedProgram; - slangReflection = composedProgram->getLayout(); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = composedProgram.get(); - - auto shaderProgram = device->createProgram(programDesc); - - outShaderProgram = shaderProgram; - return SLANG_OK; - } + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + auto moduleInterfaceBlob = + Slang::UnownedRawBlob::create(moduleInterfaceSrc, strlen(moduleInterfaceSrc)); + auto module0Blob = Slang::UnownedRawBlob::create(module0Src, strlen(module0Src)); + auto module1Blob = Slang::UnownedRawBlob::create(module1Src, strlen(module1Src)); + slang::IModule* moduleInterface = + slangSession->loadModuleFromSource("ifoo", "ifoo.slang", moduleInterfaceBlob); + slang::IModule* module0 = slangSession->loadModuleFromSource("module0", "path0", module0Blob); + slang::IModule* module1 = slangSession->loadModuleFromSource("module1", "path1", module1Blob); + ComPtr<slang::IEntryPoint> computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module0->findEntryPointByName("computeMain", computeEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(moduleInterface); + componentTypes.add(module0); + componentTypes.add(module1); + componentTypes.add(computeEntryPoint); + + Slang::ComPtr<slang::IComponentType> composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + ComPtr<slang::IComponentType> linkedProgram; + result = composedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + composedProgram = linkedProgram; + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; +} - void linkTimeTypeTestImpl(IDevice* device, UnitTestContext* context) +void linkTimeTypeTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram, slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadProgram(device, shaderProgram, slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(11.0)); - } + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - SLANG_UNIT_TEST(linkTimeTypeD3D12) - { - runTestImpl(linkTimeTypeTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - SLANG_UNIT_TEST(linkTimeTypeVulkan) - { - runTestImpl(linkTimeTypeTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(11.0)); +} + +SLANG_UNIT_TEST(linkTimeTypeD3D12) +{ + runTestImpl(linkTimeTypeTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(linkTimeTypeVulkan) +{ + runTestImpl(linkTimeTypeTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/mutable-shader-object.cpp b/tools/gfx-unit-test/mutable-shader-object.cpp index cc9707643..9c91a7ca3 100644 --- a/tools/gfx-unit-test/mutable-shader-object.cpp +++ b/tools/gfx-unit-test/mutable-shader-object.cpp @@ -1,136 +1,141 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void mutableShaderObjectTestImpl(IDevice* device, UnitTestContext* context) +void mutableShaderObjectTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "mutable-shader-object", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; + const int numberCount = SLANG_COUNT_OF(initialData); + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = sizeof(initialData); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "mutable-shader-object", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - const int numberCount = SLANG_COUNT_OF(initialData); - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = sizeof(initialData); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, + slang::TypeReflection* addTransformerType = + slangReflection->findTypeByName("AddTransformer"); + + ComPtr<IShaderObject> transformer; + GFX_CHECK_CALL_ABORT(device->createMutableShaderObject( + addTransformerType, + ShaderObjectContainerType::None, + transformer.writeRef())); + // Set the `c` field of the `AddTransformer`. + float c = 1.0f; + ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + auto entryPointCursor = ShaderCursor(rootObject->getEntryPoint(0)); + + entryPointCursor.getPath("buffer").setResource(bufferView); + + // Bind the previously created transformer object to root object. + ComPtr<IShaderObject> transformerVersion; + transformer->getCurrentVersion(transientHeap, transformerVersion.writeRef()); + entryPointCursor.getPath("transformer").setObject(transformerVersion); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + + auto barrierEncoder = commandBuffer->encodeResourceCommands(); + barrierEncoder->bufferBarrier( + 1, + numbersBuffer.readRef(), ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - { - slang::TypeReflection* addTransformerType = - slangReflection->findTypeByName("AddTransformer"); - - ComPtr<IShaderObject> transformer; - GFX_CHECK_CALL_ABORT(device->createMutableShaderObject( - addTransformerType, ShaderObjectContainerType::None, transformer.writeRef())); - // Set the `c` field of the `AddTransformer`. - float c = 1.0f; - ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - auto entryPointCursor = ShaderCursor(rootObject->getEntryPoint(0)); - - entryPointCursor.getPath("buffer").setResource(bufferView); - - // Bind the previously created transformer object to root object. - ComPtr<IShaderObject> transformerVersion; - transformer->getCurrentVersion(transientHeap, transformerVersion.writeRef()); - entryPointCursor.getPath("transformer").setObject(transformerVersion); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - - auto barrierEncoder = commandBuffer->encodeResourceCommands(); - barrierEncoder->bufferBarrier(1, numbersBuffer.readRef(), ResourceState::UnorderedAccess, ResourceState::UnorderedAccess); - barrierEncoder->endEncoding(); - - encoder = commandBuffer->encodeComputeCommands(); - - rootObject = encoder->bindPipeline(pipelineState); - entryPointCursor = ShaderCursor(rootObject->getEntryPoint(0)); - - // Mutate `transformer` object and run again. - c = 2.0f; - ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); - transformer->getCurrentVersion(transientHeap, transformerVersion.writeRef()); - entryPointCursor.getPath("buffer").setResource(bufferView); - entryPointCursor.getPath("transformer").setObject(transformerVersion); - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(3.0f, 4.0f, 5.0f, 6.0f)); + ResourceState::UnorderedAccess); + barrierEncoder->endEncoding(); + + encoder = commandBuffer->encodeComputeCommands(); + + rootObject = encoder->bindPipeline(pipelineState); + entryPointCursor = ShaderCursor(rootObject->getEntryPoint(0)); + + // Mutate `transformer` object and run again. + c = 2.0f; + ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + transformer->getCurrentVersion(transientHeap, transformerVersion.writeRef()); + entryPointCursor.getPath("buffer").setResource(bufferView); + entryPointCursor.getPath("transformer").setObject(transformerVersion); + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - //SLANG_UNIT_TEST(mutableShaderObjectCPU) - //{ - // runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::CPU); - //} + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(3.0f, 4.0f, 5.0f, 6.0f)); +} - SLANG_UNIT_TEST(mutableShaderObjectD3D11) - { - runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::D3D11); - } +// SLANG_UNIT_TEST(mutableShaderObjectCPU) +//{ +// runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::CPU); +// } - SLANG_UNIT_TEST(mutableShaderObjectD3D12) - { - runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } +SLANG_UNIT_TEST(mutableShaderObjectD3D11) +{ + runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::D3D11); +} - SLANG_UNIT_TEST(mutableShaderObjectVulkan) - { - runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(mutableShaderObjectD3D12) +{ + runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(mutableShaderObjectVulkan) +{ + runTestImpl(mutableShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/nested-parameter-block.cpp b/tools/gfx-unit-test/nested-parameter-block.cpp index 98df615af..e904226ae 100644 --- a/tools/gfx-unit-test/nested-parameter-block.cpp +++ b/tools/gfx-unit-test/nested-parameter-block.cpp @@ -1,150 +1,162 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - Slang::ComPtr<IBufferResource> createBuffer( - IDevice* device, uint32_t data, ResourceState defaultState) - { - uint32_t initialData[] = {data, data, data, data}; - const int numberCount = SLANG_COUNT_OF(initialData); - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = sizeof(initialData); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(uint32_t) * 4; - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = defaultState; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT( - device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); - return numbersBuffer; - } +Slang::ComPtr<IBufferResource> createBuffer( + IDevice* device, + uint32_t data, + ResourceState defaultState) +{ + uint32_t initialData[] = {data, data, data, data}; + const int numberCount = SLANG_COUNT_OF(initialData); + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = sizeof(initialData); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(uint32_t) * 4; + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = defaultState; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + return numbersBuffer; +} - struct uint4 - { - uint32_t x, y, z, w; - }; +struct uint4 +{ + uint32_t x, y, z, w; +}; - void nestedParameterBlockTestImpl(IDevice* device, UnitTestContext* context) +void nestedParameterBlockTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "nested-parameter-block", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + ComPtr<IShaderObject> shaderObject; + SLANG_CHECK(SLANG_SUCCEEDED( + device->createMutableRootShaderObject(shaderProgram, shaderObject.writeRef()))); + + Slang::List<Slang::ComPtr<IBufferResource>> srvBuffers; + Slang::List<Slang::ComPtr<IResourceView>> srvs; + + for (uint32_t i = 0; i < 6; i++) { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "nested-parameter-block", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - ComPtr<IShaderObject> shaderObject; - SLANG_CHECK(SLANG_SUCCEEDED( - device->createMutableRootShaderObject(shaderProgram, shaderObject.writeRef()))); - - Slang::List<Slang::ComPtr<IBufferResource>> srvBuffers; - Slang::List<Slang::ComPtr<IResourceView>> srvs; - - for (uint32_t i = 0; i < 6; i++) - { - srvBuffers.add(createBuffer(device, i, gfx::ResourceState::ShaderResource)); - IResourceView::Desc srvDesc = {}; - srvDesc.type = IResourceView::Type::ShaderResource; - srvDesc.format = Format::Unknown; - srvDesc.bufferRange.offset = 0; - srvDesc.bufferRange.size = sizeof(uint32_t) * 4; - srvs.add(device->createBufferView(srvBuffers[i], nullptr, srvDesc)); - } - Slang::ComPtr<IBufferResource> resultBuffer = - createBuffer(device, 0, gfx::ResourceState::UnorderedAccess); - IResourceView::Desc resultBufferViewDesc = {}; - resultBufferViewDesc.type = IResourceView::Type::UnorderedAccess; - resultBufferViewDesc.format = Format::Unknown; - resultBufferViewDesc.bufferRange.offset = 0; - resultBufferViewDesc.bufferRange.size = sizeof(uint32_t) * 4; - Slang::ComPtr<IResourceView> resultBufferView; - SLANG_CHECK(SLANG_SUCCEEDED(device->createBufferView( - resultBuffer, nullptr, resultBufferViewDesc, resultBufferView.writeRef()))); - - Slang::ComPtr<IShaderObject> materialObject; - SLANG_CHECK(SLANG_SUCCEEDED(device->createMutableShaderObject( - slangReflection->findTypeByName("MaterialSystem"), - ShaderObjectContainerType::None, - materialObject.writeRef()))); - - Slang::ComPtr<IShaderObject> sceneObject; - SLANG_CHECK(SLANG_SUCCEEDED(device->createMutableShaderObject( - slangReflection->findTypeByName("Scene"), - ShaderObjectContainerType::None, - sceneObject.writeRef()))); - - ShaderCursor cursor(shaderObject); - cursor["resultBuffer"].setResource(resultBufferView); - cursor["scene"].setObject(sceneObject); - - Slang::ComPtr<IShaderObject> globalCB; - SLANG_CHECK(SLANG_SUCCEEDED(device->createShaderObject( - cursor[0].getTypeLayout()->getType(), - ShaderObjectContainerType::None, - globalCB.writeRef()))); - - cursor[0].setObject(globalCB); - auto initialData = uint4{20, 20, 20, 20}; - globalCB->setData(ShaderOffset(), &initialData, sizeof(initialData)); - - ShaderCursor sceneCursor(sceneObject); - sceneCursor["sceneCb"].setData(uint4{100, 100, 100, 100}); - sceneCursor["data"].setResource(srvs[1]); - sceneCursor["material"].setObject(materialObject); - - ShaderCursor materialCursor(materialObject); - materialCursor["cb"].setData(uint4{1000, 1000, 1000, 1000}); - materialCursor["data"].setResource(srvs[2]); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - encoder->bindPipelineWithRootObject(pipelineState, shaderObject); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult(device, resultBuffer, Slang::makeArray<uint32_t>(1123u, 1123u, 1123u, 1123u)); + srvBuffers.add(createBuffer(device, i, gfx::ResourceState::ShaderResource)); + IResourceView::Desc srvDesc = {}; + srvDesc.type = IResourceView::Type::ShaderResource; + srvDesc.format = Format::Unknown; + srvDesc.bufferRange.offset = 0; + srvDesc.bufferRange.size = sizeof(uint32_t) * 4; + srvs.add(device->createBufferView(srvBuffers[i], nullptr, srvDesc)); } - - SLANG_UNIT_TEST(nestedParameterBlockTestD3D12) + Slang::ComPtr<IBufferResource> resultBuffer = + createBuffer(device, 0, gfx::ResourceState::UnorderedAccess); + IResourceView::Desc resultBufferViewDesc = {}; + resultBufferViewDesc.type = IResourceView::Type::UnorderedAccess; + resultBufferViewDesc.format = Format::Unknown; + resultBufferViewDesc.bufferRange.offset = 0; + resultBufferViewDesc.bufferRange.size = sizeof(uint32_t) * 4; + Slang::ComPtr<IResourceView> resultBufferView; + SLANG_CHECK(SLANG_SUCCEEDED(device->createBufferView( + resultBuffer, + nullptr, + resultBufferViewDesc, + resultBufferView.writeRef()))); + + Slang::ComPtr<IShaderObject> materialObject; + SLANG_CHECK(SLANG_SUCCEEDED(device->createMutableShaderObject( + slangReflection->findTypeByName("MaterialSystem"), + ShaderObjectContainerType::None, + materialObject.writeRef()))); + + Slang::ComPtr<IShaderObject> sceneObject; + SLANG_CHECK(SLANG_SUCCEEDED(device->createMutableShaderObject( + slangReflection->findTypeByName("Scene"), + ShaderObjectContainerType::None, + sceneObject.writeRef()))); + + ShaderCursor cursor(shaderObject); + cursor["resultBuffer"].setResource(resultBufferView); + cursor["scene"].setObject(sceneObject); + + Slang::ComPtr<IShaderObject> globalCB; + SLANG_CHECK(SLANG_SUCCEEDED(device->createShaderObject( + cursor[0].getTypeLayout()->getType(), + ShaderObjectContainerType::None, + globalCB.writeRef()))); + + cursor[0].setObject(globalCB); + auto initialData = uint4{20, 20, 20, 20}; + globalCB->setData(ShaderOffset(), &initialData, sizeof(initialData)); + + ShaderCursor sceneCursor(sceneObject); + sceneCursor["sceneCb"].setData(uint4{100, 100, 100, 100}); + sceneCursor["data"].setResource(srvs[1]); + sceneCursor["material"].setObject(materialObject); + + ShaderCursor materialCursor(materialObject); + materialCursor["cb"].setData(uint4{1000, 1000, 1000, 1000}); + materialCursor["data"].setResource(srvs[2]); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - runTestImpl(nestedParameterBlockTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - SLANG_UNIT_TEST(nestedParameterBlockTestVulkan) - { - runTestImpl(nestedParameterBlockTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + encoder->bindPipelineWithRootObject(pipelineState, shaderObject); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + + compareComputeResult( + device, + resultBuffer, + Slang::makeArray<uint32_t>(1123u, 1123u, 1123u, 1123u)); +} + +SLANG_UNIT_TEST(nestedParameterBlockTestD3D12) +{ + runTestImpl(nestedParameterBlockTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(nestedParameterBlockTestVulkan) +{ + runTestImpl(nestedParameterBlockTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/precompiled-module-2.cpp b/tools/gfx-unit-test/precompiled-module-2.cpp index f997b2a7b..0a5ea3ac0 100644 --- a/tools/gfx-unit-test/precompiled-module-2.cpp +++ b/tools/gfx-unit-test/precompiled-module-2.cpp @@ -1,121 +1,125 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" #include "source/core/slang-blob.h" -#include "source/core/slang-memory-file-system.h" #include "source/core/slang-io.h" +#include "source/core/slang-memory-file-system.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - // Test that mixing precompiled and non-precompiled modules is working. +// Test that mixing precompiled and non-precompiled modules is working. - static Slang::Result precompileProgram( - gfx::IDevice* device, - ISlangMutableFileSystem* fileSys, - const char* shaderModuleName, - bool precompileToTarget) +static Slang::Result precompileProgram( + gfx::IDevice* device, + ISlangMutableFileSystem* fileSys, + const char* shaderModuleName, + bool precompileToTarget) +{ + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + slang::SessionDesc sessionDesc = {}; + auto searchPaths = getSlangSearchPaths(); + sessionDesc.searchPathCount = searchPaths.getCount(); + sessionDesc.searchPaths = searchPaths.getBuffer(); + auto globalSession = slangSession->getGlobalSession(); + globalSession->createSession(sessionDesc, slangSession.writeRef()); + + slang::IModule* module; { - Slang::ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - slang::SessionDesc sessionDesc = {}; - auto searchPaths = getSlangSearchPaths(); - sessionDesc.searchPathCount = searchPaths.getCount(); - sessionDesc.searchPaths = searchPaths.getBuffer(); - auto globalSession = slangSession->getGlobalSession(); - globalSession->createSession(sessionDesc, slangSession.writeRef()); - - slang::IModule* module; - { - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - } - if (!module) - return SLANG_FAIL; + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + } + if (!module) + return SLANG_FAIL; - if (precompileToTarget) + if (precompileToTarget) + { + SlangCompileTarget target; + switch (device->getDeviceInfo().deviceType) { - SlangCompileTarget target; - switch (device->getDeviceInfo().deviceType) - { - case gfx::DeviceType::DirectX12: - target = SLANG_DXIL; - break; - case gfx::DeviceType::Vulkan: - target = SLANG_SPIRV; - break; - default: - return SLANG_FAIL; - } - - ComPtr<slang::IModulePrecompileService_Experimental> precompileService; - if (module->queryInterface(slang::SLANG_UUID_IModulePrecompileService_Experimental, (void**)precompileService.writeRef()) == SLANG_OK) - { - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - precompileService->precompileForTarget(target, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - } + case gfx::DeviceType::DirectX12: target = SLANG_DXIL; break; + case gfx::DeviceType::Vulkan: target = SLANG_SPIRV; break; + default: return SLANG_FAIL; } - // Write loaded modules to memory file system. - for (SlangInt i = 0; i < slangSession->getLoadedModuleCount(); i++) + ComPtr<slang::IModulePrecompileService_Experimental> precompileService; + if (module->queryInterface( + slang::SLANG_UUID_IModulePrecompileService_Experimental, + (void**)precompileService.writeRef()) == SLANG_OK) { - auto module = slangSession->getLoadedModule(i); - auto path = module->getFilePath(); - if (path) - { - auto name = module->getName(); - ComPtr<ISlangBlob> outBlob; - module->serialize(outBlob.writeRef()); - fileSys->saveFileBlob((Slang::String(name) + ".slang-module").getBuffer(), outBlob); - } + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + precompileService->precompileForTarget(target, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); } - return SLANG_OK; } - void precompiledModule2TestImplCommon(IDevice* device, UnitTestContext* context, bool precompileToTarget) + // Write loaded modules to memory file system. + for (SlangInt i = 0; i < slangSession->getLoadedModuleCount(); i++) { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - // First, load and compile the slang source. - ComPtr<ISlangMutableFileSystem> memoryFileSystem = ComPtr<ISlangMutableFileSystem>(new Slang::MemoryFileSystem()); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(precompileProgram(device, memoryFileSystem.get(), "precompiled-module-imported", precompileToTarget)); - - // Next, load the precompiled slang program. - Slang::ComPtr<slang::ISession> slangSession; - device->getSlangSession(slangSession.writeRef()); - slang::SessionDesc sessionDesc = {}; - sessionDesc.targetCount = 1; - slang::TargetDesc targetDesc = {}; - switch (device->getDeviceInfo().deviceType) + auto module = slangSession->getLoadedModule(i); + auto path = module->getFilePath(); + if (path) { - case gfx::DeviceType::DirectX12: - targetDesc.format = SLANG_DXIL; - targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("sm_6_1"); - break; - case gfx::DeviceType::Vulkan: - targetDesc.format = SLANG_SPIRV; - targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("GLSL_460"); - break; + auto name = module->getName(); + ComPtr<ISlangBlob> outBlob; + module->serialize(outBlob.writeRef()); + fileSys->saveFileBlob((Slang::String(name) + ".slang-module").getBuffer(), outBlob); } - sessionDesc.targets = &targetDesc; - sessionDesc.fileSystem = memoryFileSystem.get(); - auto globalSession = slangSession->getGlobalSession(); - globalSession->createSession(sessionDesc, slangSession.writeRef()); + } + return SLANG_OK; +} + +void precompiledModule2TestImplCommon( + IDevice* device, + UnitTestContext* context, + bool precompileToTarget) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + // First, load and compile the slang source. + ComPtr<ISlangMutableFileSystem> memoryFileSystem = + ComPtr<ISlangMutableFileSystem>(new Slang::MemoryFileSystem()); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(precompileProgram( + device, + memoryFileSystem.get(), + "precompiled-module-imported", + precompileToTarget)); + + // Next, load the precompiled slang program. + Slang::ComPtr<slang::ISession> slangSession; + device->getSlangSession(slangSession.writeRef()); + slang::SessionDesc sessionDesc = {}; + sessionDesc.targetCount = 1; + slang::TargetDesc targetDesc = {}; + switch (device->getDeviceInfo().deviceType) + { + case gfx::DeviceType::DirectX12: + targetDesc.format = SLANG_DXIL; + targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("sm_6_1"); + break; + case gfx::DeviceType::Vulkan: + targetDesc.format = SLANG_SPIRV; + targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("GLSL_460"); + break; + } + sessionDesc.targets = &targetDesc; + sessionDesc.fileSystem = memoryFileSystem.get(); + auto globalSession = slangSession->getGlobalSession(); + globalSession->createSession(sessionDesc, slangSession.writeRef()); - const char* moduleSrc = R"( + const char* moduleSrc = R"( import "precompiled-module-imported"; // Main entry-point. @@ -131,99 +135,100 @@ namespace gfx_test buffer[sv_dispatchThreadID.x] = helperFunc() + helperFunc1(); } )"; - memoryFileSystem->saveFile("precompiled-module.slang", moduleSrc, strlen(moduleSrc)); - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, slangSession, shaderProgram, "precompiled-module", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); + memoryFileSystem->saveFile("precompiled-module.slang", moduleSrc, strlen(moduleSrc)); + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + slangSession, + shaderProgram, + "precompiled-module", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - auto rootObject = encoder->bindPipeline(pipelineState); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); + auto rootObject = encoder->bindPipeline(pipelineState); - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(3.0f, 3.0f, 3.0f, 3.0f)); + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - void precompiledModule2TestImpl(IDevice* device, UnitTestContext* context) - { - precompiledModule2TestImplCommon(device, context, false); - } + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(3.0f, 3.0f, 3.0f, 3.0f)); +} - void precompiledTargetModule2TestImpl(IDevice* device, UnitTestContext* context) - { - precompiledModule2TestImplCommon(device, context, true); - } +void precompiledModule2TestImpl(IDevice* device, UnitTestContext* context) +{ + precompiledModule2TestImplCommon(device, context, false); +} - SLANG_UNIT_TEST(precompiledModule2D3D12) - { - runTestImpl(precompiledModule2TestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } +void precompiledTargetModule2TestImpl(IDevice* device, UnitTestContext* context) +{ + precompiledModule2TestImplCommon(device, context, true); +} - SLANG_UNIT_TEST(precompiledTargetModule2D3D12) - { - runTestImpl(precompiledTargetModule2TestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } +SLANG_UNIT_TEST(precompiledModule2D3D12) +{ + runTestImpl(precompiledModule2TestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} - SLANG_UNIT_TEST(precompiledModule2Vulkan) - { - runTestImpl(precompiledModule2TestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(precompiledTargetModule2D3D12) +{ + runTestImpl(precompiledTargetModule2TestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} - SLANG_UNIT_TEST(precompiledTargetModule2Vulkan) - { - runTestImpl(precompiledTargetModule2TestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(precompiledModule2Vulkan) +{ + runTestImpl(precompiledModule2TestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +} +SLANG_UNIT_TEST(precompiledTargetModule2Vulkan) +{ + runTestImpl(precompiledTargetModule2TestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/precompiled-module-cache.cpp b/tools/gfx-unit-test/precompiled-module-cache.cpp index 97d6e1c34..1c10f759b 100644 --- a/tools/gfx-unit-test/precompiled-module-cache.cpp +++ b/tools/gfx-unit-test/precompiled-module-cache.cpp @@ -1,95 +1,97 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" #include "source/core/slang-blob.h" -#include "source/core/slang-memory-file-system.h" #include "source/core/slang-io.h" +#include "source/core/slang-memory-file-system.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - // Test that precompiled module cache is working. +// Test that precompiled module cache is working. - Slang::ComPtr<slang::ISession> createSession(gfx::IDevice* device, ISlangFileSystemExt* fileSys) +Slang::ComPtr<slang::ISession> createSession(gfx::IDevice* device, ISlangFileSystemExt* fileSys) +{ + Slang::ComPtr<slang::ISession> slangSession; + device->getSlangSession(slangSession.writeRef()); + slang::SessionDesc sessionDesc = {}; + sessionDesc.searchPathCount = 1; + const char* searchPath = "cache/"; + sessionDesc.searchPaths = &searchPath; + sessionDesc.targetCount = 1; + sessionDesc.compilerOptionEntryCount = 1; + slang::CompilerOptionEntry entry; + entry.name = slang::CompilerOptionName::UseUpToDateBinaryModule; + entry.value.kind = slang::CompilerOptionValueKind::Int; + entry.value.intValue0 = 1; + sessionDesc.compilerOptionEntries = &entry; + slang::TargetDesc targetDesc = {}; + switch (device->getDeviceInfo().deviceType) { - Slang::ComPtr<slang::ISession> slangSession; - device->getSlangSession(slangSession.writeRef()); - slang::SessionDesc sessionDesc = {}; - sessionDesc.searchPathCount = 1; - const char* searchPath = "cache/"; - sessionDesc.searchPaths = &searchPath; - sessionDesc.targetCount = 1; - sessionDesc.compilerOptionEntryCount = 1; - slang::CompilerOptionEntry entry; - entry.name = slang::CompilerOptionName::UseUpToDateBinaryModule; - entry.value.kind = slang::CompilerOptionValueKind::Int; - entry.value.intValue0 = 1; - sessionDesc.compilerOptionEntries = &entry; - slang::TargetDesc targetDesc = {}; - switch (device->getDeviceInfo().deviceType) - { - case gfx::DeviceType::DirectX12: - targetDesc.format = SLANG_DXIL; - targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("sm_6_1"); - break; - case gfx::DeviceType::Vulkan: - targetDesc.format = SLANG_SPIRV; - targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("GLSL_460"); - break; - } - sessionDesc.targets = &targetDesc; - sessionDesc.fileSystem = fileSys; - auto globalSession = slangSession->getGlobalSession(); - globalSession->createSession(sessionDesc, slangSession.writeRef()); - return slangSession; + case gfx::DeviceType::DirectX12: + targetDesc.format = SLANG_DXIL; + targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("sm_6_1"); + break; + case gfx::DeviceType::Vulkan: + targetDesc.format = SLANG_SPIRV; + targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("GLSL_460"); + break; } + sessionDesc.targets = &targetDesc; + sessionDesc.fileSystem = fileSys; + auto globalSession = slangSession->getGlobalSession(); + globalSession->createSession(sessionDesc, slangSession.writeRef()); + return slangSession; +} - static Slang::Result precompileProgram( - gfx::IDevice* device, - ISlangMutableFileSystem* fileSys, - const char* shaderModuleName) - { - Slang::ComPtr<slang::ISession> slangSession = createSession(device, fileSys); +static Slang::Result precompileProgram( + gfx::IDevice* device, + ISlangMutableFileSystem* fileSys, + const char* shaderModuleName) +{ + Slang::ComPtr<slang::ISession> slangSession = createSession(device, fileSys); - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if (!module) - return SLANG_FAIL; + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; - // Write loaded modules to memory file system. - for (SlangInt i = 0; i < slangSession->getLoadedModuleCount(); i++) + // Write loaded modules to memory file system. + for (SlangInt i = 0; i < slangSession->getLoadedModuleCount(); i++) + { + auto module = slangSession->getLoadedModule(i); + auto path = module->getFilePath(); + if (path) { - auto module = slangSession->getLoadedModule(i); - auto path = module->getFilePath(); - if (path) - { - auto name = module->getName(); - ComPtr<ISlangBlob> outBlob; - module->serialize(outBlob.writeRef()); - fileSys->saveFileBlob((Slang::String("cache/") + Slang::String(name) + ".slang-module").getBuffer(), outBlob); - } + auto name = module->getName(); + ComPtr<ISlangBlob> outBlob; + module->serialize(outBlob.writeRef()); + fileSys->saveFileBlob( + (Slang::String("cache/") + Slang::String(name) + ".slang-module").getBuffer(), + outBlob); } - return SLANG_OK; } + return SLANG_OK; +} - void precompiledModuleCacheTestImpl(IDevice* device, UnitTestContext* context) - { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - // First, Initialize our file system. - ComPtr<ISlangMutableFileSystem> memoryFileSystem = ComPtr<ISlangMutableFileSystem>(new Slang::MemoryFileSystem()); - memoryFileSystem->createDirectory("cache"); - - const char* moduleSrc = R"( +void precompiledModuleCacheTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + // First, Initialize our file system. + ComPtr<ISlangMutableFileSystem> memoryFileSystem = + ComPtr<ISlangMutableFileSystem>(new Slang::MemoryFileSystem()); + memoryFileSystem->createDirectory("cache"); + + const char* moduleSrc = R"( import "precompiled-module-imported"; // Main entry-point. @@ -105,9 +107,9 @@ namespace gfx_test buffer[sv_dispatchThreadID.x] = helperFunc() + helperFunc1(); } )"; - memoryFileSystem->saveFile("precompiled-module.slang", moduleSrc, strlen(moduleSrc)); + memoryFileSystem->saveFile("precompiled-module.slang", moduleSrc, strlen(moduleSrc)); - const char* moduleSrc2 = R"( + const char* moduleSrc2 = R"( module "precompiled-module-imported"; __include "precompiled-module-included.slang"; @@ -120,8 +122,8 @@ namespace gfx_test } } )"; - memoryFileSystem->saveFile("precompiled-module-imported.slang", moduleSrc2, strlen(moduleSrc2)); - const char* moduleSrc3 = R"( + memoryFileSystem->saveFile("precompiled-module-imported.slang", moduleSrc2, strlen(moduleSrc2)); + const char* moduleSrc3 = R"( implementing "precompiled-module-imported"; namespace ns @@ -132,85 +134,90 @@ namespace gfx_test } } )"; - memoryFileSystem->saveFile("precompiled-module-included.slang", moduleSrc3, strlen(moduleSrc3)); - - // Precompile a module. - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(precompileProgram(device, memoryFileSystem.get(), "precompiled-module-imported")); - - // Next, load the precompiled slang program. - Slang::ComPtr<slang::ISession> slangSession = createSession(device, memoryFileSystem); - ComPtr<ISlangBlob> binaryBlob; - memoryFileSystem->loadFile("cache/precompiled-module-imported.slang-module", binaryBlob.writeRef()); - auto upToDate = slangSession->isBinaryModuleUpToDate("precompiled-module-imported.slang", binaryBlob); - SLANG_CHECK(upToDate); // The module should be up-to-date. - - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, slangSession, shaderProgram, "precompiled-module", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); + memoryFileSystem->saveFile("precompiled-module-included.slang", moduleSrc3, strlen(moduleSrc3)); + + // Precompile a module. + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT( + precompileProgram(device, memoryFileSystem.get(), "precompiled-module-imported")); + + // Next, load the precompiled slang program. + Slang::ComPtr<slang::ISession> slangSession = createSession(device, memoryFileSystem); + ComPtr<ISlangBlob> binaryBlob; + memoryFileSystem->loadFile( + "cache/precompiled-module-imported.slang-module", + binaryBlob.writeRef()); + auto upToDate = + slangSession->isBinaryModuleUpToDate("precompiled-module-imported.slang", binaryBlob); + SLANG_CHECK(upToDate); // The module should be up-to-date. + + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + slangSession, + shaderProgram, + "precompiled-module", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - auto rootObject = encoder->bindPipeline(pipelineState); + auto rootObject = encoder->bindPipeline(pipelineState); - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(3.0f, 3.0f, 3.0f, 3.0f)); + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(3.0f, 3.0f, 3.0f, 3.0f)); - // Now we change the source and check if the precompiled module is still up-to-date. - const char* moduleSrc4 = R"( + // Now we change the source and check if the precompiled module is still up-to-date. + const char* moduleSrc4 = R"( implementing "precompiled-module-imported"; namespace ns { public int helperFunc1() { @@ -218,21 +225,22 @@ namespace gfx_test } } )"; - memoryFileSystem->saveFile("precompiled-module-included.slang", moduleSrc4, strlen(moduleSrc4)); - - slangSession = createSession(device, memoryFileSystem); - upToDate = slangSession->isBinaryModuleUpToDate("precompiled-module-imported.slang", binaryBlob); - SLANG_CHECK(!upToDate); // The module should not be up-to-date because the source has changed. - } + memoryFileSystem->saveFile("precompiled-module-included.slang", moduleSrc4, strlen(moduleSrc4)); - SLANG_UNIT_TEST(precompiledModuleCacheD3D12) - { - runTestImpl(precompiledModuleCacheTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + slangSession = createSession(device, memoryFileSystem); + upToDate = + slangSession->isBinaryModuleUpToDate("precompiled-module-imported.slang", binaryBlob); + SLANG_CHECK(!upToDate); // The module should not be up-to-date because the source has changed. +} - SLANG_UNIT_TEST(precompiledModuleCacheVulkan) - { - runTestImpl(precompiledModuleCacheTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(precompiledModuleCacheD3D12) +{ + runTestImpl(precompiledModuleCacheTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} +SLANG_UNIT_TEST(precompiledModuleCacheVulkan) +{ + runTestImpl(precompiledModuleCacheTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/precompiled-module.cpp b/tools/gfx-unit-test/precompiled-module.cpp index 026575120..2ecc412c4 100644 --- a/tools/gfx-unit-test/precompiled-module.cpp +++ b/tools/gfx-unit-test/precompiled-module.cpp @@ -1,160 +1,161 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" #include "source/core/slang-blob.h" #include "source/core/slang-memory-file-system.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - static Slang::Result precompileProgram( - gfx::IDevice* device, - ISlangMutableFileSystem* fileSys, - const char* shaderModuleName) +static Slang::Result precompileProgram( + gfx::IDevice* device, + ISlangMutableFileSystem* fileSys, + const char* shaderModuleName) +{ + Slang::ComPtr<slang::ISession> slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + slang::SessionDesc sessionDesc = {}; + auto searchPaths = getSlangSearchPaths(); + sessionDesc.searchPathCount = searchPaths.getCount(); + sessionDesc.searchPaths = searchPaths.getBuffer(); + auto globalSession = slangSession->getGlobalSession(); + globalSession->createSession(sessionDesc, slangSession.writeRef()); + + Slang::ComPtr<slang::IBlob> diagnosticsBlob; + slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + // Write loaded modules to memory file system. + for (SlangInt i = 0; i < slangSession->getLoadedModuleCount(); i++) { - Slang::ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - slang::SessionDesc sessionDesc = {}; - auto searchPaths = getSlangSearchPaths(); - sessionDesc.searchPathCount = searchPaths.getCount(); - sessionDesc.searchPaths = searchPaths.getBuffer(); - auto globalSession = slangSession->getGlobalSession(); - globalSession->createSession(sessionDesc, slangSession.writeRef()); - - Slang::ComPtr<slang::IBlob> diagnosticsBlob; - slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if (!module) - return SLANG_FAIL; - - // Write loaded modules to memory file system. - for (SlangInt i = 0; i < slangSession->getLoadedModuleCount(); i++) + auto module = slangSession->getLoadedModule(i); + auto path = module->getFilePath(); + if (path) { - auto module = slangSession->getLoadedModule(i); - auto path = module->getFilePath(); - if (path) - { - auto name = module->getName(); - ComPtr<ISlangBlob> outBlob; - module->serialize(outBlob.writeRef()); - fileSys->saveFileBlob((Slang::String(name) + ".slang-module").getBuffer(), outBlob); - } + auto name = module->getName(); + ComPtr<ISlangBlob> outBlob; + module->serialize(outBlob.writeRef()); + fileSys->saveFileBlob((Slang::String(name) + ".slang-module").getBuffer(), outBlob); } - return SLANG_OK; } + return SLANG_OK; +} - void precompiledModuleTestImpl(IDevice* device, UnitTestContext* context) +void precompiledModuleTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + // First, load and compile the slang source. + ComPtr<ISlangMutableFileSystem> memoryFileSystem = + ComPtr<ISlangMutableFileSystem>(new Slang::MemoryFileSystem()); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(precompileProgram(device, memoryFileSystem.get(), "precompiled-module")); + + // Next, load the precompiled slang program. + Slang::ComPtr<slang::ISession> slangSession; + device->getSlangSession(slangSession.writeRef()); + slang::SessionDesc sessionDesc = {}; + sessionDesc.targetCount = 1; + slang::TargetDesc targetDesc = {}; + switch (device->getDeviceInfo().deviceType) { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - // First, load and compile the slang source. - ComPtr<ISlangMutableFileSystem> memoryFileSystem = ComPtr<ISlangMutableFileSystem>(new Slang::MemoryFileSystem()); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(precompileProgram(device, memoryFileSystem.get(), "precompiled-module")); - - // Next, load the precompiled slang program. - Slang::ComPtr<slang::ISession> slangSession; - device->getSlangSession(slangSession.writeRef()); - slang::SessionDesc sessionDesc = {}; - sessionDesc.targetCount = 1; - slang::TargetDesc targetDesc = {}; - switch (device->getDeviceInfo().deviceType) - { - case gfx::DeviceType::DirectX12: - targetDesc.format = SLANG_DXIL; - targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("sm_6_1"); - break; - case gfx::DeviceType::Vulkan: - targetDesc.format = SLANG_SPIRV; - targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("GLSL_460"); - break; - } - sessionDesc.targets = &targetDesc; - sessionDesc.fileSystem = memoryFileSystem.get(); - auto globalSession = slangSession->getGlobalSession(); - globalSession->createSession(sessionDesc, slangSession.writeRef()); - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, slangSession, shaderProgram, "precompiled-module", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); + case gfx::DeviceType::DirectX12: + targetDesc.format = SLANG_DXIL; + targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("sm_6_1"); + break; + case gfx::DeviceType::Vulkan: + targetDesc.format = SLANG_SPIRV; + targetDesc.profile = device->getSlangSession()->getGlobalSession()->findProfile("GLSL_460"); + break; + } + sessionDesc.targets = &targetDesc; + sessionDesc.fileSystem = memoryFileSystem.get(); + auto globalSession = slangSession->getGlobalSession(); + globalSession->createSession(sessionDesc, slangSession.writeRef()); + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + slangSession, + shaderProgram, + "precompiled-module", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - auto rootObject = encoder->bindPipeline(pipelineState); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); + auto rootObject = encoder->bindPipeline(pipelineState); - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(3.0f, 3.0f, 3.0f, 3.0f)); + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(precompiledModuleD3D12) - { - runTestImpl(precompiledModuleTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(3.0f, 3.0f, 3.0f, 3.0f)); +} - SLANG_UNIT_TEST(precompiledModuleVulkan) - { - runTestImpl(precompiledModuleTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(precompiledModuleD3D12) +{ + runTestImpl(precompiledModuleTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} +SLANG_UNIT_TEST(precompiledModuleVulkan) +{ + runTestImpl(precompiledModuleTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/ray-tracing-tests.cpp b/tools/gfx-unit-test/ray-tracing-tests.cpp index 97a6ad7d1..0e7fd2765 100644 --- a/tools/gfx-unit-test/ray-tracing-tests.cpp +++ b/tools/gfx-unit-test/ray-tracing-tests.cpp @@ -1,11 +1,10 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" -#include "gfx-test-util.h" #include "gfx-test-texture-util.h" +#include "gfx-test-util.h" +#include "slang-gfx.h" +#include "source/core/slang-basic.h" #include "tools/gfx-util/shader-cursor.h" #include "tools/platform/vector-math.h" -#include "source/core/slang-basic.h" +#include "tools/unit-test/slang-unit-test.h" #include <chrono> @@ -14,482 +13,495 @@ using namespace Slang; namespace gfx_test { - struct Vertex - { - float position[3]; - }; - - static const int kVertexCount = 9; - static const Vertex kVertexData[kVertexCount] = - { - // Triangle 1 - { 0, 0, 1 }, - { 4, 0, 1 }, - { 0, 4, 1 }, - - // Triangle 2 - { -4, 0, 1 }, - { 0, 0, 1 }, - { 0, 4, 1 }, - - // Triangle 3 - { 0, 0, 1 }, - { 4, 0, 1 }, - { 0, -4, 1 }, - }; - static const int kIndexCount = 9; - static const uint32_t kIndexData[kIndexCount] = - { - 0, 1, 2, - 3, 4, 5, - 6, 7, 8, - }; - - struct BaseRayTracingTest +struct Vertex +{ + float position[3]; +}; + +static const int kVertexCount = 9; +static const Vertex kVertexData[kVertexCount] = { + // Triangle 1 + {0, 0, 1}, + {4, 0, 1}, + {0, 4, 1}, + + // Triangle 2 + {-4, 0, 1}, + {0, 0, 1}, + {0, 4, 1}, + + // Triangle 3 + {0, 0, 1}, + {4, 0, 1}, + {0, -4, 1}, +}; +static const int kIndexCount = 9; +static const uint32_t kIndexData[kIndexCount] = { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, +}; + +struct BaseRayTracingTest +{ + IDevice* device; + UnitTestContext* context; + + ComPtr<IFramebufferLayout> framebufferLayout; + ComPtr<ITransientResourceHeap> transientHeap; + ComPtr<ICommandQueue> queue; + + ComPtr<IPipelineState> renderPipelineState; + ComPtr<IBufferResource> vertexBuffer; + ComPtr<IBufferResource> indexBuffer; + ComPtr<IBufferResource> transformBuffer; + ComPtr<IBufferResource> instanceBuffer; + ComPtr<IBufferResource> BLASBuffer; + ComPtr<IAccelerationStructure> BLAS; + ComPtr<IBufferResource> TLASBuffer; + ComPtr<IAccelerationStructure> TLAS; + ComPtr<ITextureResource> resultTexture; + ComPtr<IResourceView> resultTextureUAV; + ComPtr<IShaderTable> shaderTable; + + uint32_t width = 2; + uint32_t height = 2; + + void init(IDevice* device, UnitTestContext* context) { - IDevice* device; - UnitTestContext* context; - - ComPtr<IFramebufferLayout> framebufferLayout; - ComPtr<ITransientResourceHeap> transientHeap; - ComPtr<ICommandQueue> queue; - - ComPtr<IPipelineState> renderPipelineState; - ComPtr<IBufferResource> vertexBuffer; - ComPtr<IBufferResource> indexBuffer; - ComPtr<IBufferResource> transformBuffer; - ComPtr<IBufferResource> instanceBuffer; - ComPtr<IBufferResource> BLASBuffer; - ComPtr<IAccelerationStructure> BLAS; - ComPtr<IBufferResource> TLASBuffer; - ComPtr<IAccelerationStructure> TLAS; - ComPtr<ITextureResource> resultTexture; - ComPtr<IResourceView> resultTextureUAV; - ComPtr<IShaderTable> shaderTable; - - uint32_t width = 2; - uint32_t height = 2; - - void init(IDevice* device, UnitTestContext* context) + if (!device->hasFeature("ray-tracing")) { - if (!device->hasFeature("ray-tracing")) - { - SLANG_IGNORE_TEST; - } - - this->device = device; - this->context = context; + SLANG_IGNORE_TEST; } - // Load and compile shader code from source. - gfx::Result loadShaderProgram(gfx::IDevice* device, gfx::IShaderProgram** outProgram) - { - ComPtr<slang::ISession> slangSession; - slangSession = device->getSlangSession(); - - ComPtr<slang::IBlob> diagnosticsBlob; - slang::IModule* module = slangSession->loadModule("ray-tracing-test-shaders", diagnosticsBlob.writeRef()); - if (!module) - return SLANG_FAIL; - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(module); - ComPtr<slang::IEntryPoint> entryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("rayGenShaderA", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("rayGenShaderB", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("missShaderA", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("missShaderB", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName("closestHitShaderA", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName("closestHitShaderB", entryPoint.writeRef())); - componentTypes.add(entryPoint); - - ComPtr<slang::IComponentType> linkedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - linkedProgram.writeRef(), - diagnosticsBlob.writeRef()); - SLANG_RETURN_ON_FAIL(result); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); - - return SLANG_OK; - } + this->device = device; + this->context = context; + } - void createResultTexture() - { - ITextureResource::Desc resultTextureDesc = {}; - resultTextureDesc.type = IResource::Type::Texture2D; - resultTextureDesc.numMipLevels = 1; - resultTextureDesc.size.width = width; - resultTextureDesc.size.height = height; - resultTextureDesc.size.depth = 1; - resultTextureDesc.defaultState = ResourceState::UnorderedAccess; - resultTextureDesc.format = Format::R32G32B32A32_FLOAT; - resultTexture = device->createTextureResource(resultTextureDesc); - IResourceView::Desc resultUAVDesc = {}; - resultUAVDesc.format = resultTextureDesc.format; - resultUAVDesc.type = IResourceView::Type::UnorderedAccess; - resultTextureUAV = device->createTextureView(resultTexture, resultUAVDesc); - } + // Load and compile shader code from source. + gfx::Result loadShaderProgram(gfx::IDevice* device, gfx::IShaderProgram** outProgram) + { + ComPtr<slang::ISession> slangSession; + slangSession = device->getSlangSession(); + + ComPtr<slang::IBlob> diagnosticsBlob; + slang::IModule* module = + slangSession->loadModule("ray-tracing-test-shaders", diagnosticsBlob.writeRef()); + if (!module) + return SLANG_FAIL; + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(module); + ComPtr<slang::IEntryPoint> entryPoint; + SLANG_RETURN_ON_FAIL(module->findEntryPointByName("rayGenShaderA", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL(module->findEntryPointByName("rayGenShaderB", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL(module->findEntryPointByName("missShaderA", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL(module->findEntryPointByName("missShaderB", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("closestHitShaderA", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("closestHitShaderB", entryPoint.writeRef())); + componentTypes.add(entryPoint); + + ComPtr<slang::IComponentType> linkedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + linkedProgram.writeRef(), + diagnosticsBlob.writeRef()); + SLANG_RETURN_ON_FAIL(result); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = linkedProgram; + SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + + return SLANG_OK; + } - void createRequiredResources() - { - ICommandQueue::Desc queueDesc = {}; - queueDesc.type = ICommandQueue::QueueType::Graphics; - queue = device->createCommandQueue(queueDesc); - - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::ShaderResource; - vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); - SLANG_CHECK_ABORT(vertexBuffer != nullptr); - - IBufferResource::Desc indexBufferDesc; - indexBufferDesc.type = IResource::Type::Buffer; - indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t); - indexBufferDesc.defaultState = ResourceState::ShaderResource; - indexBuffer = device->createBufferResource(indexBufferDesc, &kIndexData[0]); - SLANG_CHECK_ABORT(indexBuffer != nullptr); - - IBufferResource::Desc transformBufferDesc; - transformBufferDesc.type = IResource::Type::Buffer; - transformBufferDesc.sizeInBytes = sizeof(float) * 12; - transformBufferDesc.defaultState = ResourceState::ShaderResource; - float transformData[12] = { - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }; - transformBuffer = device->createBufferResource(transformBufferDesc, &transformData); - SLANG_CHECK_ABORT(transformBuffer != nullptr); - - createResultTexture(); - - IFramebufferLayout::TargetLayout renderTargetLayout = { Format::R8G8B8A8_UNORM, 1 }; - IFramebufferLayout::TargetLayout depthLayout = { gfx::Format::D32_FLOAT, 1 }; - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &renderTargetLayout; - framebufferLayoutDesc.depthStencil = &depthLayout; - GFX_CHECK_CALL_ABORT( - device->createFramebufferLayout(framebufferLayoutDesc, framebufferLayout.writeRef())); + void createResultTexture() + { + ITextureResource::Desc resultTextureDesc = {}; + resultTextureDesc.type = IResource::Type::Texture2D; + resultTextureDesc.numMipLevels = 1; + resultTextureDesc.size.width = width; + resultTextureDesc.size.height = height; + resultTextureDesc.size.depth = 1; + resultTextureDesc.defaultState = ResourceState::UnorderedAccess; + resultTextureDesc.format = Format::R32G32B32A32_FLOAT; + resultTexture = device->createTextureResource(resultTextureDesc); + IResourceView::Desc resultUAVDesc = {}; + resultUAVDesc.format = resultTextureDesc.format; + resultUAVDesc.type = IResourceView::Type::UnorderedAccess; + resultTextureUAV = device->createTextureView(resultTexture, resultUAVDesc); + } - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096 * 1024; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - // Build bottom level acceleration structure. - { - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel; - accelerationStructureBuildInputs.flags = - IAccelerationStructure::BuildFlags::AllowCompaction; - IAccelerationStructure::GeometryDesc geomDesc; - geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque; - geomDesc.type = IAccelerationStructure::GeometryType::Triangles; - geomDesc.content.triangles.indexCount = kIndexCount; - geomDesc.content.triangles.indexData = indexBuffer->getDeviceAddress(); - geomDesc.content.triangles.indexFormat = Format::R32_UINT; - geomDesc.content.triangles.vertexCount = kVertexCount; - geomDesc.content.triangles.vertexData = vertexBuffer->getDeviceAddress(); - geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT; - geomDesc.content.triangles.vertexStride = sizeof(Vertex); - geomDesc.content.triangles.transform3x4 = transformBuffer->getDeviceAddress(); - accelerationStructureBuildInputs.geometryDescs = &geomDesc; - - // Query buffer size for acceleration structure build. - GFX_CHECK_CALL_ABORT(device->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo)); - // Allocate buffers for acceleration structure. - IBufferResource::Desc asDraftBufferDesc; - asDraftBufferDesc.type = IResource::Type::Buffer; - asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure; - asDraftBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; - ComPtr<IBufferResource> draftBuffer = device->createBufferResource(asDraftBufferDesc); - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; - scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr<IBufferResource> scratchBuffer = device->createBufferResource(scratchBufferDesc); - - // Build acceleration structure. - ComPtr<IQueryPool> compactedSizeQuery; - IQueryPool::Desc queryPoolDesc; - queryPoolDesc.count = 1; - queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize; - GFX_CHECK_CALL_ABORT( - device->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef())); - - ComPtr<IAccelerationStructure> draftAS; - IAccelerationStructure::CreateDesc draftCreateDesc; - draftCreateDesc.buffer = draftBuffer; - draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel; - draftCreateDesc.offset = 0; - draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; - GFX_CHECK_CALL_ABORT( - device->createAccelerationStructure(draftCreateDesc, draftAS.writeRef())); - - compactedSizeQuery->reset(); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = draftAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); - AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; - compactedSizeQueryDesc.queryPool = compactedSizeQuery; - compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize; - encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - - uint64_t compactedSize = 0; - compactedSizeQuery->getResult(0, 1, &compactedSize); - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = (size_t)compactedSize; - BLASBuffer = device->createBufferResource(asBufferDesc); - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = BLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::BottomLevel; - createDesc.offset = 0; - createDesc.size = (size_t)compactedSize; - device->createAccelerationStructure(createDesc, BLAS.writeRef()); - - commandBuffer = transientHeap->createCommandBuffer(); - encoder = commandBuffer->encodeRayTracingCommands(); - encoder->copyAccelerationStructure(BLAS, draftAS, AccelerationStructureCopyMode::Compact); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - // Build top level acceleration structure. - { - List<IAccelerationStructure::InstanceDesc> instanceDescs; - instanceDescs.setCount(1); - instanceDescs[0].accelerationStructure = BLAS->getDeviceAddress(); - instanceDescs[0].flags = - IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable; - instanceDescs[0].instanceContributionToHitGroupIndex = 0; - instanceDescs[0].instanceID = 0; - instanceDescs[0].instanceMask = 0xFF; - float transformMatrix[] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }; - memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12); - - IBufferResource::Desc instanceBufferDesc; - instanceBufferDesc.type = IResource::Type::Buffer; - instanceBufferDesc.sizeInBytes = - instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc); - instanceBufferDesc.defaultState = ResourceState::ShaderResource; - instanceBuffer = device->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer()); - SLANG_CHECK_ABORT(instanceBuffer != nullptr); - - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {}; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {}; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel; - accelerationStructureBuildInputs.instanceDescs = instanceBuffer->getDeviceAddress(); - - // Query buffer size for acceleration structure build. - GFX_CHECK_CALL_ABORT(device->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo)); - - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; - TLASBuffer = device->createBufferResource(asBufferDesc); - - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; - scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr<IBufferResource> scratchBuffer = device->createBufferResource(scratchBufferDesc); - - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = TLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::TopLevel; - createDesc.offset = 0; - createDesc.size = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; - GFX_CHECK_CALL_ABORT(device->createAccelerationStructure(createDesc, TLAS.writeRef())); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = TLAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); - encoder->buildAccelerationStructure(buildDesc, 0, nullptr); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - const char* hitgroupNames[] = { "hitgroupA", "hitgroupB"}; - - ComPtr<IShaderProgram> rayTracingProgram; + void createRequiredResources() + { + ICommandQueue::Desc queueDesc = {}; + queueDesc.type = ICommandQueue::QueueType::Graphics; + queue = device->createCommandQueue(queueDesc); + + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::ShaderResource; + vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); + SLANG_CHECK_ABORT(vertexBuffer != nullptr); + + IBufferResource::Desc indexBufferDesc; + indexBufferDesc.type = IResource::Type::Buffer; + indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t); + indexBufferDesc.defaultState = ResourceState::ShaderResource; + indexBuffer = device->createBufferResource(indexBufferDesc, &kIndexData[0]); + SLANG_CHECK_ABORT(indexBuffer != nullptr); + + IBufferResource::Desc transformBufferDesc; + transformBufferDesc.type = IResource::Type::Buffer; + transformBufferDesc.sizeInBytes = sizeof(float) * 12; + transformBufferDesc.defaultState = ResourceState::ShaderResource; + float transformData[12] = + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; + transformBuffer = device->createBufferResource(transformBufferDesc, &transformData); + SLANG_CHECK_ABORT(transformBuffer != nullptr); + + createResultTexture(); + + IFramebufferLayout::TargetLayout renderTargetLayout = {Format::R8G8B8A8_UNORM, 1}; + IFramebufferLayout::TargetLayout depthLayout = {gfx::Format::D32_FLOAT, 1}; + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &renderTargetLayout; + framebufferLayoutDesc.depthStencil = &depthLayout; + GFX_CHECK_CALL_ABORT( + device->createFramebufferLayout(framebufferLayoutDesc, framebufferLayout.writeRef())); + + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096 * 1024; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + // Build bottom level acceleration structure. + { + IAccelerationStructure::BuildInputs accelerationStructureBuildInputs; + IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo; + accelerationStructureBuildInputs.descCount = 1; + accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel; + accelerationStructureBuildInputs.flags = + IAccelerationStructure::BuildFlags::AllowCompaction; + IAccelerationStructure::GeometryDesc geomDesc; + geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque; + geomDesc.type = IAccelerationStructure::GeometryType::Triangles; + geomDesc.content.triangles.indexCount = kIndexCount; + geomDesc.content.triangles.indexData = indexBuffer->getDeviceAddress(); + geomDesc.content.triangles.indexFormat = Format::R32_UINT; + geomDesc.content.triangles.vertexCount = kVertexCount; + geomDesc.content.triangles.vertexData = vertexBuffer->getDeviceAddress(); + geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT; + geomDesc.content.triangles.vertexStride = sizeof(Vertex); + geomDesc.content.triangles.transform3x4 = transformBuffer->getDeviceAddress(); + accelerationStructureBuildInputs.geometryDescs = &geomDesc; + + // Query buffer size for acceleration structure build. + GFX_CHECK_CALL_ABORT(device->getAccelerationStructurePrebuildInfo( + accelerationStructureBuildInputs, + &accelerationStructurePrebuildInfo)); + // Allocate buffers for acceleration structure. + IBufferResource::Desc asDraftBufferDesc; + asDraftBufferDesc.type = IResource::Type::Buffer; + asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure; + asDraftBufferDesc.sizeInBytes = + (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; + ComPtr<IBufferResource> draftBuffer = device->createBufferResource(asDraftBufferDesc); + IBufferResource::Desc scratchBufferDesc; + scratchBufferDesc.type = IResource::Type::Buffer; + scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; + scratchBufferDesc.sizeInBytes = + (size_t)accelerationStructurePrebuildInfo.scratchDataSize; + ComPtr<IBufferResource> scratchBuffer = device->createBufferResource(scratchBufferDesc); + + // Build acceleration structure. + ComPtr<IQueryPool> compactedSizeQuery; + IQueryPool::Desc queryPoolDesc; + queryPoolDesc.count = 1; + queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize; GFX_CHECK_CALL_ABORT( - loadShaderProgram(device, rayTracingProgram.writeRef())); - RayTracingPipelineStateDesc rtpDesc = {}; - rtpDesc.program = rayTracingProgram; - rtpDesc.hitGroupCount = 2; - HitGroupDesc hitGroups[2]; - hitGroups[0].closestHitEntryPoint = "closestHitShaderA"; - hitGroups[0].hitGroupName = hitgroupNames[0]; - hitGroups[1].closestHitEntryPoint = "closestHitShaderB"; - hitGroups[1].hitGroupName = hitgroupNames[1]; - rtpDesc.hitGroups = hitGroups; - rtpDesc.maxRayPayloadSize = 64; - rtpDesc.maxRecursion = 2; + device->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef())); + + ComPtr<IAccelerationStructure> draftAS; + IAccelerationStructure::CreateDesc draftCreateDesc; + draftCreateDesc.buffer = draftBuffer; + draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel; + draftCreateDesc.offset = 0; + draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; GFX_CHECK_CALL_ABORT( - device->createRayTracingPipelineState(rtpDesc, renderPipelineState.writeRef())); - SLANG_CHECK_ABORT(renderPipelineState != nullptr); - - const char* raygenNames[] = { "rayGenShaderA", "rayGenShaderB" }; - const char* missNames[] = { "missShaderA", "missShaderB" }; - - IShaderTable::Desc shaderTableDesc = {}; - shaderTableDesc.program = rayTracingProgram; - shaderTableDesc.hitGroupCount = 2; - shaderTableDesc.hitGroupNames = hitgroupNames; - shaderTableDesc.rayGenShaderCount = 2; - shaderTableDesc.rayGenShaderEntryPointNames = raygenNames; - shaderTableDesc.missShaderCount = 2; - shaderTableDesc.missShaderEntryPointNames = missNames; - GFX_CHECK_CALL_ABORT(device->createShaderTable(shaderTableDesc, shaderTable.writeRef())); - } - - void checkTestResults(float* expectedResult, uint32_t count) - { - ComPtr<ISlangBlob> resultBlob; - size_t rowPitch = 0; - size_t pixelSize = 0; - auto cmdBuffer = transientHeap->createCommandBuffer(); - auto encoder = cmdBuffer->encodeResourceCommands(); - encoder->textureBarrier(resultTexture.get(), ResourceState::UnorderedAccess, ResourceState::CopySource); + device->createAccelerationStructure(draftCreateDesc, draftAS.writeRef())); + + compactedSizeQuery->reset(); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeRayTracingCommands(); + IAccelerationStructure::BuildDesc buildDesc = {}; + buildDesc.dest = draftAS; + buildDesc.inputs = accelerationStructureBuildInputs; + buildDesc.scratchData = scratchBuffer->getDeviceAddress(); + AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; + compactedSizeQueryDesc.queryPool = compactedSizeQuery; + compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize; + encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc); encoder->endEncoding(); - cmdBuffer->close(); - queue->executeCommandBuffer(cmdBuffer.get()); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); queue->waitOnHost(); - GFX_CHECK_CALL_ABORT(device->readTextureResource( - resultTexture, ResourceState::CopySource, resultBlob.writeRef(), &rowPitch, &pixelSize)); -#if 0 // for debugging only - writeImage("test.hdr", resultBlob, width, height, (uint32_t)rowPitch, (uint32_t)pixelSize); -#endif - auto buffer = removePadding(resultBlob, width, height, rowPitch, pixelSize); - auto actualData = (float*)buffer.getBuffer(); - SLANG_CHECK(memcmp(actualData, expectedResult, count * sizeof(float)) == 0) - } - }; - - struct RayTracingTestA : BaseRayTracingTest - { - void renderFrame() - { - ComPtr<ICommandBuffer> renderCommandBuffer = - transientHeap->createCommandBuffer(); - auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands(); - IShaderObject* rootObject = nullptr; - renderEncoder->bindPipeline(renderPipelineState, &rootObject); - auto cursor = ShaderCursor(rootObject); - cursor["resultTexture"].setResource(resultTextureUAV); - cursor["sceneBVH"].setResource(TLAS); - renderEncoder->dispatchRays(0, shaderTable, width, height, 1); - renderEncoder->endEncoding(); - renderCommandBuffer->close(); - queue->executeCommandBuffer(renderCommandBuffer); + uint64_t compactedSize = 0; + compactedSizeQuery->getResult(0, 1, &compactedSize); + IBufferResource::Desc asBufferDesc; + asBufferDesc.type = IResource::Type::Buffer; + asBufferDesc.defaultState = ResourceState::AccelerationStructure; + asBufferDesc.sizeInBytes = (size_t)compactedSize; + BLASBuffer = device->createBufferResource(asBufferDesc); + IAccelerationStructure::CreateDesc createDesc; + createDesc.buffer = BLASBuffer; + createDesc.kind = IAccelerationStructure::Kind::BottomLevel; + createDesc.offset = 0; + createDesc.size = (size_t)compactedSize; + device->createAccelerationStructure(createDesc, BLAS.writeRef()); + + commandBuffer = transientHeap->createCommandBuffer(); + encoder = commandBuffer->encodeRayTracingCommands(); + encoder->copyAccelerationStructure( + BLAS, + draftAS, + AccelerationStructureCopyMode::Compact); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); queue->waitOnHost(); } - void run() - { - createRequiredResources(); - renderFrame(); - - float expectedResult[16] = { 1, 1, 1, 1, - 0, 0, 1, 1, - 0, 1, 0, 1, - 1, 0, 0, 1 }; - checkTestResults(expectedResult, 16); - } - }; - - struct RayTracingTestB : BaseRayTracingTest - { - void renderFrame() + // Build top level acceleration structure. { - ComPtr<ICommandBuffer> renderCommandBuffer = - transientHeap->createCommandBuffer(); - auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands(); - IShaderObject* rootObject = nullptr; - renderEncoder->bindPipeline(renderPipelineState, &rootObject); - auto cursor = ShaderCursor(rootObject); - cursor["resultTexture"].setResource(resultTextureUAV); - cursor["sceneBVH"].setResource(TLAS); - renderEncoder->dispatchRays(1, shaderTable, width, height, 1); - renderEncoder->endEncoding(); - renderCommandBuffer->close(); - queue->executeCommandBuffer(renderCommandBuffer); + List<IAccelerationStructure::InstanceDesc> instanceDescs; + instanceDescs.setCount(1); + instanceDescs[0].accelerationStructure = BLAS->getDeviceAddress(); + instanceDescs[0].flags = + IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable; + instanceDescs[0].instanceContributionToHitGroupIndex = 0; + instanceDescs[0].instanceID = 0; + instanceDescs[0].instanceMask = 0xFF; + float transformMatrix[] = + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; + memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12); + + IBufferResource::Desc instanceBufferDesc; + instanceBufferDesc.type = IResource::Type::Buffer; + instanceBufferDesc.sizeInBytes = + instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc); + instanceBufferDesc.defaultState = ResourceState::ShaderResource; + instanceBuffer = + device->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer()); + SLANG_CHECK_ABORT(instanceBuffer != nullptr); + + IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {}; + IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {}; + accelerationStructureBuildInputs.descCount = 1; + accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel; + accelerationStructureBuildInputs.instanceDescs = instanceBuffer->getDeviceAddress(); + + // Query buffer size for acceleration structure build. + GFX_CHECK_CALL_ABORT(device->getAccelerationStructurePrebuildInfo( + accelerationStructureBuildInputs, + &accelerationStructurePrebuildInfo)); + + IBufferResource::Desc asBufferDesc; + asBufferDesc.type = IResource::Type::Buffer; + asBufferDesc.defaultState = ResourceState::AccelerationStructure; + asBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; + TLASBuffer = device->createBufferResource(asBufferDesc); + + IBufferResource::Desc scratchBufferDesc; + scratchBufferDesc.type = IResource::Type::Buffer; + scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; + scratchBufferDesc.sizeInBytes = + (size_t)accelerationStructurePrebuildInfo.scratchDataSize; + ComPtr<IBufferResource> scratchBuffer = device->createBufferResource(scratchBufferDesc); + + IAccelerationStructure::CreateDesc createDesc; + createDesc.buffer = TLASBuffer; + createDesc.kind = IAccelerationStructure::Kind::TopLevel; + createDesc.offset = 0; + createDesc.size = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; + GFX_CHECK_CALL_ABORT(device->createAccelerationStructure(createDesc, TLAS.writeRef())); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeRayTracingCommands(); + IAccelerationStructure::BuildDesc buildDesc = {}; + buildDesc.dest = TLAS; + buildDesc.inputs = accelerationStructureBuildInputs; + buildDesc.scratchData = scratchBuffer->getDeviceAddress(); + encoder->buildAccelerationStructure(buildDesc, 0, nullptr); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); queue->waitOnHost(); } - void run() - { - createRequiredResources(); - renderFrame(); - - float expectedResult[16] = { 0, 0, 0, 1, - 1, 1, 0, 1, - 1, 0, 1, 1, - 0, 1, 1, 1 }; - checkTestResults(expectedResult, 16); - } - }; + const char* hitgroupNames[] = {"hitgroupA", "hitgroupB"}; + + ComPtr<IShaderProgram> rayTracingProgram; + GFX_CHECK_CALL_ABORT(loadShaderProgram(device, rayTracingProgram.writeRef())); + RayTracingPipelineStateDesc rtpDesc = {}; + rtpDesc.program = rayTracingProgram; + rtpDesc.hitGroupCount = 2; + HitGroupDesc hitGroups[2]; + hitGroups[0].closestHitEntryPoint = "closestHitShaderA"; + hitGroups[0].hitGroupName = hitgroupNames[0]; + hitGroups[1].closestHitEntryPoint = "closestHitShaderB"; + hitGroups[1].hitGroupName = hitgroupNames[1]; + rtpDesc.hitGroups = hitGroups; + rtpDesc.maxRayPayloadSize = 64; + rtpDesc.maxRecursion = 2; + GFX_CHECK_CALL_ABORT( + device->createRayTracingPipelineState(rtpDesc, renderPipelineState.writeRef())); + SLANG_CHECK_ABORT(renderPipelineState != nullptr); + + const char* raygenNames[] = {"rayGenShaderA", "rayGenShaderB"}; + const char* missNames[] = {"missShaderA", "missShaderB"}; + + IShaderTable::Desc shaderTableDesc = {}; + shaderTableDesc.program = rayTracingProgram; + shaderTableDesc.hitGroupCount = 2; + shaderTableDesc.hitGroupNames = hitgroupNames; + shaderTableDesc.rayGenShaderCount = 2; + shaderTableDesc.rayGenShaderEntryPointNames = raygenNames; + shaderTableDesc.missShaderCount = 2; + shaderTableDesc.missShaderEntryPointNames = missNames; + GFX_CHECK_CALL_ABORT(device->createShaderTable(shaderTableDesc, shaderTable.writeRef())); + } - template <typename T> - void rayTracingTestImpl(IDevice* device, UnitTestContext* context) + void checkTestResults(float* expectedResult, uint32_t count) { - T test; - test.init(device, context); - test.run(); + ComPtr<ISlangBlob> resultBlob; + size_t rowPitch = 0; + size_t pixelSize = 0; + auto cmdBuffer = transientHeap->createCommandBuffer(); + auto encoder = cmdBuffer->encodeResourceCommands(); + encoder->textureBarrier( + resultTexture.get(), + ResourceState::UnorderedAccess, + ResourceState::CopySource); + encoder->endEncoding(); + cmdBuffer->close(); + queue->executeCommandBuffer(cmdBuffer.get()); + queue->waitOnHost(); + + GFX_CHECK_CALL_ABORT(device->readTextureResource( + resultTexture, + ResourceState::CopySource, + resultBlob.writeRef(), + &rowPitch, + &pixelSize)); +#if 0 // for debugging only + writeImage("test.hdr", resultBlob, width, height, (uint32_t)rowPitch, (uint32_t)pixelSize); +#endif + auto buffer = removePadding(resultBlob, width, height, rowPitch, pixelSize); + auto actualData = (float*)buffer.getBuffer(); + SLANG_CHECK(memcmp(actualData, expectedResult, count * sizeof(float)) == 0) } +}; - SLANG_UNIT_TEST(RayTracingTestAD3D12) +struct RayTracingTestA : BaseRayTracingTest +{ + void renderFrame() { - runTestImpl(rayTracingTestImpl<RayTracingTestA>, unitTestContext, Slang::RenderApiFlag::D3D12); + ComPtr<ICommandBuffer> renderCommandBuffer = transientHeap->createCommandBuffer(); + auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands(); + IShaderObject* rootObject = nullptr; + renderEncoder->bindPipeline(renderPipelineState, &rootObject); + auto cursor = ShaderCursor(rootObject); + cursor["resultTexture"].setResource(resultTextureUAV); + cursor["sceneBVH"].setResource(TLAS); + renderEncoder->dispatchRays(0, shaderTable, width, height, 1); + renderEncoder->endEncoding(); + renderCommandBuffer->close(); + queue->executeCommandBuffer(renderCommandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(RayTracingTestAVulkan) + void run() { - runTestImpl(rayTracingTestImpl<RayTracingTestA>, unitTestContext, Slang::RenderApiFlag::Vulkan); + createRequiredResources(); + renderFrame(); + + float expectedResult[16] = {1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1}; + checkTestResults(expectedResult, 16); } +}; - SLANG_UNIT_TEST(RayTracingTestBD3D12) +struct RayTracingTestB : BaseRayTracingTest +{ + void renderFrame() { - runTestImpl(rayTracingTestImpl<RayTracingTestB>, unitTestContext, Slang::RenderApiFlag::D3D12); + ComPtr<ICommandBuffer> renderCommandBuffer = transientHeap->createCommandBuffer(); + auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands(); + IShaderObject* rootObject = nullptr; + renderEncoder->bindPipeline(renderPipelineState, &rootObject); + auto cursor = ShaderCursor(rootObject); + cursor["resultTexture"].setResource(resultTextureUAV); + cursor["sceneBVH"].setResource(TLAS); + renderEncoder->dispatchRays(1, shaderTable, width, height, 1); + renderEncoder->endEncoding(); + renderCommandBuffer->close(); + queue->executeCommandBuffer(renderCommandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(RayTracingTestBVulkan) + void run() { - runTestImpl(rayTracingTestImpl<RayTracingTestB>, unitTestContext, Slang::RenderApiFlag::Vulkan); + createRequiredResources(); + renderFrame(); + + float expectedResult[16] = {0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1}; + checkTestResults(expectedResult, 16); } +}; + +template<typename T> +void rayTracingTestImpl(IDevice* device, UnitTestContext* context) +{ + T test; + test.init(device, context); + test.run(); +} + +SLANG_UNIT_TEST(RayTracingTestAD3D12) +{ + runTestImpl(rayTracingTestImpl<RayTracingTestA>, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(RayTracingTestAVulkan) +{ + runTestImpl(rayTracingTestImpl<RayTracingTestA>, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(RayTracingTestBD3D12) +{ + runTestImpl(rayTracingTestImpl<RayTracingTestB>, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(RayTracingTestBVulkan) +{ + runTestImpl(rayTracingTestImpl<RayTracingTestB>, unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/resolve-resource-tests.cpp b/tools/gfx-unit-test/resolve-resource-tests.cpp index af2bf68e9..ea25b609f 100644 --- a/tools/gfx-unit-test/resolve-resource-tests.cpp +++ b/tools/gfx-unit-test/resolve-resource-tests.cpp @@ -1,9 +1,8 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" #if SLANG_WINDOWS_FAMILY #include <d3d12.h> @@ -14,320 +13,356 @@ using namespace gfx; namespace { - using namespace gfx_test; +using namespace gfx_test; - struct Vertex - { - float position[3]; - float color[3]; - }; +struct Vertex +{ + float position[3]; + float color[3]; +}; + +static const int kVertexCount = 12; +static const Vertex kVertexData[kVertexCount] = { + // Triangle 1 + {{0, 0, 0.5}, {1, 0, 0}}, + {{1, 1, 0.5}, {1, 0, 0}}, + {{-1, 1, 0.5}, {1, 0, 0}}, + + // Triangle 2 + {{-1, 1, 0.5}, {0, 1, 0}}, + {{0, 0, 0.5}, {0, 1, 0}}, + {{-1, -1, 0.5}, {0, 1, 0}}, + + // Triangle 3 + {{-1, -1, 0.5}, {0, 0, 1}}, + {{0, 0, 0.5}, {0, 0, 1}}, + {{1, -1, 0.5}, {0, 0, 1}}, + + // Triangle 4 + {{1, -1, 0.5}, {0, 0, 0}}, + {{0, 0, 0.5}, {0, 0, 0}}, + {{1, 1, 0.5}, {0, 0, 0}}, +}; + +const int kWidth = 256; +const int kHeight = 256; +Format format = Format::R32G32B32A32_FLOAT; + +ComPtr<IBufferResource> createVertexBuffer(IDevice* device) +{ + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; + ComPtr<IBufferResource> vertexBuffer = + device->createBufferResource(vertexBufferDesc, &kVertexData[0]); + SLANG_CHECK_ABORT(vertexBuffer != nullptr); + return vertexBuffer; +} + +struct BaseResolveResourceTest +{ + IDevice* device; + UnitTestContext* context; + + ComPtr<ITextureResource> msaaTexture; + ComPtr<ITextureResource> dstTexture; + + ComPtr<ITransientResourceHeap> transientHeap; + ComPtr<IPipelineState> pipelineState; + ComPtr<IRenderPassLayout> renderPass; + ComPtr<IFramebuffer> framebuffer; + + ComPtr<IBufferResource> vertexBuffer; - static const int kVertexCount = 12; - static const Vertex kVertexData[kVertexCount] = + struct TextureInfo { - // Triangle 1 - { { 0, 0, 0.5 }, { 1, 0, 0 } }, - { { 1, 1, 0.5 }, { 1, 0, 0 } }, - { { -1, 1, 0.5 }, { 1, 0, 0 } }, - - // Triangle 2 - { { -1, 1, 0.5 }, { 0, 1, 0 } }, - { { 0, 0, 0.5 }, { 0, 1, 0 } }, - { { -1, -1, 0.5 }, { 0, 1, 0 } }, - - // Triangle 3 - { { -1, -1, 0.5 }, { 0, 0, 1 } }, - { { 0, 0, 0.5 }, { 0, 0, 1 } }, - { { 1, -1, 0.5 }, { 0, 0, 1 } }, - - // Triangle 4 - { { 1, -1, 0.5 }, { 0, 0, 0 } }, - { { 0, 0, 0.5 }, { 0, 0, 0 } }, - { { 1, 1, 0.5 }, { 0, 0, 0 } }, + ITextureResource::Extents extent; + int numMipLevels; + int arraySize; + ITextureResource::SubresourceData const* initData; }; - const int kWidth = 256; - const int kHeight = 256; - Format format = Format::R32G32B32A32_FLOAT; - - ComPtr<IBufferResource> createVertexBuffer(IDevice* device) + void init(IDevice* device, UnitTestContext* context) { - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; - ComPtr<IBufferResource> vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); - SLANG_CHECK_ABORT(vertexBuffer != nullptr); - return vertexBuffer; + this->device = device; + this->context = context; } - struct BaseResolveResourceTest + void createRequiredResources( + TextureInfo msaaTextureInfo, + TextureInfo dstTextureInfo, + Format format) { - IDevice* device; - UnitTestContext* context; - - ComPtr<ITextureResource> msaaTexture; - ComPtr<ITextureResource> dstTexture; - - ComPtr<ITransientResourceHeap> transientHeap; - ComPtr<IPipelineState> pipelineState; - ComPtr<IRenderPassLayout> renderPass; - ComPtr<IFramebuffer> framebuffer; - - ComPtr<IBufferResource> vertexBuffer; - - struct TextureInfo - { - ITextureResource::Extents extent; - int numMipLevels; - int arraySize; - ITextureResource::SubresourceData const* initData; + VertexStreamDesc vertexStreams[] = { + {sizeof(Vertex), InputSlotClass::PerVertex, 0}, }; - void init(IDevice* device, UnitTestContext* context) - { - this->device = device; - this->context = context; - } + InputElementDesc inputElements[] = { + // Vertex buffer data + {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0}, + {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color), 0}, + }; - void createRequiredResources(TextureInfo msaaTextureInfo, TextureInfo dstTextureInfo, Format format) - { - VertexStreamDesc vertexStreams[] = { - { sizeof(Vertex), InputSlotClass::PerVertex, 0 }, - }; - - InputElementDesc inputElements[] = { - // Vertex buffer data - { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0 }, - { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color), 0 }, - }; - - ITextureResource::Desc msaaTexDesc = {}; - msaaTexDesc.type = IResource::Type::Texture2D; - msaaTexDesc.numMipLevels = dstTextureInfo.numMipLevels; - msaaTexDesc.arraySize = dstTextureInfo.arraySize; - msaaTexDesc.size = dstTextureInfo.extent; - msaaTexDesc.defaultState = ResourceState::RenderTarget; - msaaTexDesc.allowedStates = ResourceStateSet( - ResourceState::RenderTarget, - ResourceState::ResolveSource); - msaaTexDesc.format = format; - msaaTexDesc.sampleDesc.numSamples = 4; - - GFX_CHECK_CALL_ABORT(device->createTextureResource( - msaaTexDesc, - msaaTextureInfo.initData, - msaaTexture.writeRef())); - - ITextureResource::Desc dstTexDesc = {}; - dstTexDesc.type = IResource::Type::Texture2D; - dstTexDesc.numMipLevels = dstTextureInfo.numMipLevels; - dstTexDesc.arraySize = dstTextureInfo.arraySize; - dstTexDesc.size = dstTextureInfo.extent; - dstTexDesc.defaultState = ResourceState::ResolveDestination; - dstTexDesc.allowedStates = ResourceStateSet( - ResourceState::ResolveDestination, - ResourceState::CopySource); - dstTexDesc.format = format; - - GFX_CHECK_CALL_ABORT(device->createTextureResource( - dstTexDesc, - dstTextureInfo.initData, - dstTexture.writeRef())); - - IInputLayout::Desc inputLayoutDesc = {}; - inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); - inputLayoutDesc.inputElements = inputElements; - inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); - inputLayoutDesc.vertexStreams = vertexStreams; - auto inputLayout = device->createInputLayout(inputLayoutDesc); - SLANG_CHECK_ABORT(inputLayout != nullptr); - - vertexBuffer = createVertexBuffer(device); - - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadGraphicsProgram(device, shaderProgram, "resolve-resource-shader", "vertexMain", "fragmentMain", slangReflection)); - - IFramebufferLayout::TargetLayout targetLayout; - targetLayout.format = format; - targetLayout.sampleCount = 4; - - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &targetLayout; - ComPtr<gfx::IFramebufferLayout> framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc); - SLANG_CHECK_ABORT(framebufferLayout != nullptr); - - GraphicsPipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - pipelineDesc.inputLayout = inputLayout; - pipelineDesc.framebufferLayout = framebufferLayout; - pipelineDesc.depthStencil.depthTestEnable = false; - pipelineDesc.depthStencil.depthWriteEnable = false; - GFX_CHECK_CALL_ABORT( - device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); - - IRenderPassLayout::Desc renderPassDesc = {}; - renderPassDesc.framebufferLayout = framebufferLayout; - renderPassDesc.renderTargetCount = 1; - IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; - renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; - renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; - renderTargetAccess.initialState = ResourceState::RenderTarget; - renderTargetAccess.finalState = ResourceState::ResolveSource; - renderPassDesc.renderTargetAccess = &renderTargetAccess; - GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); - - gfx::IResourceView::Desc colorBufferViewDesc; - memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); - colorBufferViewDesc.format = format; - colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; - colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; - auto rtv = device->createTextureView(msaaTexture, colorBufferViewDesc); - - gfx::IFramebuffer::Desc framebufferDesc; - framebufferDesc.renderTargetCount = 1; - framebufferDesc.depthStencilView = nullptr; - framebufferDesc.renderTargetViews = rtv.readRef(); - framebufferDesc.layout = framebufferLayout; - GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); - } + ITextureResource::Desc msaaTexDesc = {}; + msaaTexDesc.type = IResource::Type::Texture2D; + msaaTexDesc.numMipLevels = dstTextureInfo.numMipLevels; + msaaTexDesc.arraySize = dstTextureInfo.arraySize; + msaaTexDesc.size = dstTextureInfo.extent; + msaaTexDesc.defaultState = ResourceState::RenderTarget; + msaaTexDesc.allowedStates = + ResourceStateSet(ResourceState::RenderTarget, ResourceState::ResolveSource); + msaaTexDesc.format = format; + msaaTexDesc.sampleDesc.numSamples = 4; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + msaaTexDesc, + msaaTextureInfo.initData, + msaaTexture.writeRef())); + + ITextureResource::Desc dstTexDesc = {}; + dstTexDesc.type = IResource::Type::Texture2D; + dstTexDesc.numMipLevels = dstTextureInfo.numMipLevels; + dstTexDesc.arraySize = dstTextureInfo.arraySize; + dstTexDesc.size = dstTextureInfo.extent; + dstTexDesc.defaultState = ResourceState::ResolveDestination; + dstTexDesc.allowedStates = + ResourceStateSet(ResourceState::ResolveDestination, ResourceState::CopySource); + dstTexDesc.format = format; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + dstTexDesc, + dstTextureInfo.initData, + dstTexture.writeRef())); + + IInputLayout::Desc inputLayoutDesc = {}; + inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); + inputLayoutDesc.inputElements = inputElements; + inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); + inputLayoutDesc.vertexStreams = vertexStreams; + auto inputLayout = device->createInputLayout(inputLayoutDesc); + SLANG_CHECK_ABORT(inputLayout != nullptr); + + vertexBuffer = createVertexBuffer(device); + + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadGraphicsProgram( + device, + shaderProgram, + "resolve-resource-shader", + "vertexMain", + "fragmentMain", + slangReflection)); + + IFramebufferLayout::TargetLayout targetLayout; + targetLayout.format = format; + targetLayout.sampleCount = 4; + + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &targetLayout; + ComPtr<gfx::IFramebufferLayout> framebufferLayout = + device->createFramebufferLayout(framebufferLayoutDesc); + SLANG_CHECK_ABORT(framebufferLayout != nullptr); + + GraphicsPipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + pipelineDesc.inputLayout = inputLayout; + pipelineDesc.framebufferLayout = framebufferLayout; + pipelineDesc.depthStencil.depthTestEnable = false; + pipelineDesc.depthStencil.depthWriteEnable = false; + GFX_CHECK_CALL_ABORT( + device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); + + IRenderPassLayout::Desc renderPassDesc = {}; + renderPassDesc.framebufferLayout = framebufferLayout; + renderPassDesc.renderTargetCount = 1; + IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; + renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; + renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; + renderTargetAccess.initialState = ResourceState::RenderTarget; + renderTargetAccess.finalState = ResourceState::ResolveSource; + renderPassDesc.renderTargetAccess = &renderTargetAccess; + GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = format; + colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; + auto rtv = device->createTextureView(msaaTexture, colorBufferViewDesc); + + gfx::IFramebuffer::Desc framebufferDesc; + framebufferDesc.renderTargetCount = 1; + framebufferDesc.depthStencilView = nullptr; + framebufferDesc.renderTargetViews = rtv.readRef(); + framebufferDesc.layout = framebufferLayout; + GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); + } - void submitGPUWork(SubresourceRange msaaSubresource, SubresourceRange dstSubresource, ITextureResource::Extents extent) - { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto renderEncoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); - auto rootObject = renderEncoder->bindPipeline(pipelineState); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = kWidth; - viewport.extentY = kHeight; - renderEncoder->setViewportAndScissor(viewport); - - renderEncoder->setVertexBuffer(0, vertexBuffer); - renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - renderEncoder->draw(kVertexCount, 0); - renderEncoder->endEncoding(); - - auto resourceEncoder = commandBuffer->encodeResourceCommands(); - - resourceEncoder->resolveResource(msaaTexture, ResourceState::ResolveSource, msaaSubresource, dstTexture, ResourceState::ResolveDestination, dstSubresource); - resourceEncoder->textureSubresourceBarrier(dstTexture, dstSubresource, ResourceState::ResolveDestination, ResourceState::CopySource); - resourceEncoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + void submitGPUWork( + SubresourceRange msaaSubresource, + SubresourceRange dstSubresource, + ITextureResource::Extents extent) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto renderEncoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); + auto rootObject = renderEncoder->bindPipeline(pipelineState); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = kWidth; + viewport.extentY = kHeight; + renderEncoder->setViewportAndScissor(viewport); + + renderEncoder->setVertexBuffer(0, vertexBuffer); + renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + renderEncoder->draw(kVertexCount, 0); + renderEncoder->endEncoding(); + + auto resourceEncoder = commandBuffer->encodeResourceCommands(); + + resourceEncoder->resolveResource( + msaaTexture, + ResourceState::ResolveSource, + msaaSubresource, + dstTexture, + ResourceState::ResolveDestination, + dstSubresource); + resourceEncoder->textureSubresourceBarrier( + dstTexture, + dstSubresource, + ResourceState::ResolveDestination, + ResourceState::CopySource); + resourceEncoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - void checkTestResults(int pixelCount, int channelCount, const int* testXCoords, const int* testYCoords, float* testResults) + void checkTestResults( + int pixelCount, + int channelCount, + const int* testXCoords, + const int* testYCoords, + float* testResults) + { + // Read texture values back from four specific pixels located within the triangles + // and compare against expected values (because testing every single pixel will be too long + // and tedious and requires maintaining reference images). + ComPtr<ISlangBlob> resultBlob; + size_t rowPitch = 0; + size_t pixelSize = 0; + GFX_CHECK_CALL_ABORT(device->readTextureResource( + dstTexture, + ResourceState::CopySource, + resultBlob.writeRef(), + &rowPitch, + &pixelSize)); + auto result = (float*)resultBlob->getBufferPointer(); + + int cursor = 0; + for (int i = 0; i < pixelCount; ++i) { - // Read texture values back from four specific pixels located within the triangles - // and compare against expected values (because testing every single pixel will be too long and tedious - // and requires maintaining reference images). - ComPtr<ISlangBlob> resultBlob; - size_t rowPitch = 0; - size_t pixelSize = 0; - GFX_CHECK_CALL_ABORT(device->readTextureResource( - dstTexture, ResourceState::CopySource, resultBlob.writeRef(), &rowPitch, &pixelSize)); - auto result = (float*)resultBlob->getBufferPointer(); - - int cursor = 0; - for (int i = 0; i < pixelCount; ++i) + auto x = testXCoords[i]; + auto y = testYCoords[i]; + auto pixelPtr = result + x * channelCount + y * rowPitch / sizeof(float); + for (int j = 0; j < channelCount; ++j) { - auto x = testXCoords[i]; - auto y = testYCoords[i]; - auto pixelPtr = result + x * channelCount + y * rowPitch / sizeof(float); - for (int j = 0; j < channelCount; ++j) - { - testResults[cursor] = pixelPtr[j]; - cursor++; - } + testResults[cursor] = pixelPtr[j]; + cursor++; } - - float expectedResult[] = { 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f, - 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 0.0f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f }; - SLANG_CHECK(memcmp(testResults, expectedResult, 128) == 0); } - }; - // TODO: Add more tests? + float expectedResult[] = {0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f, 0.0f, + 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, + 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f}; + SLANG_CHECK(memcmp(testResults, expectedResult, 128) == 0); + } +}; - struct ResolveResourceSimple : BaseResolveResourceTest - { - void run() - { - ITextureResource::Extents extent = {}; - extent.width = kWidth; - extent.height = kHeight; - extent.depth = 1; - - TextureInfo msaaTextureInfo = { extent, 1, 1, nullptr }; - TextureInfo dstTextureInfo = { extent, 1, 1, nullptr }; - - createRequiredResources(msaaTextureInfo, dstTextureInfo, format); - - SubresourceRange msaaSubresource = {}; - msaaSubresource.aspectMask = TextureAspect::Color; - msaaSubresource.mipLevel = 0; - msaaSubresource.mipLevelCount = 1; - msaaSubresource.baseArrayLayer = 0; - msaaSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = TextureAspect::Color; - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - submitGPUWork(msaaSubresource, dstSubresource, extent); - - const int kPixelCount = 8; - const int kChannelCount = 4; - int testXCoords[kPixelCount] = { 64, 127, 191, 64, 191, 64, 127, 191 }; - int testYCoords[kPixelCount] = { 64, 64, 64, 127, 127, 191, 191, 191 }; - float testResults[kPixelCount * kChannelCount]; - - checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); - } - }; +// TODO: Add more tests? - template<typename T> - void resolveResourceTestImpl(IDevice* device, UnitTestContext* context) +struct ResolveResourceSimple : BaseResolveResourceTest +{ + void run() { - T test; - test.init(device, context); - test.run(); + ITextureResource::Extents extent = {}; + extent.width = kWidth; + extent.height = kHeight; + extent.depth = 1; + + TextureInfo msaaTextureInfo = {extent, 1, 1, nullptr}; + TextureInfo dstTextureInfo = {extent, 1, 1, nullptr}; + + createRequiredResources(msaaTextureInfo, dstTextureInfo, format); + + SubresourceRange msaaSubresource = {}; + msaaSubresource.aspectMask = TextureAspect::Color; + msaaSubresource.mipLevel = 0; + msaaSubresource.mipLevelCount = 1; + msaaSubresource.baseArrayLayer = 0; + msaaSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = TextureAspect::Color; + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + submitGPUWork(msaaSubresource, dstSubresource, extent); + + const int kPixelCount = 8; + const int kChannelCount = 4; + int testXCoords[kPixelCount] = {64, 127, 191, 64, 191, 64, 127, 191}; + int testYCoords[kPixelCount] = {64, 64, 64, 127, 127, 191, 191, 191}; + float testResults[kPixelCount * kChannelCount]; + + checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); } +}; + +template<typename T> +void resolveResourceTestImpl(IDevice* device, UnitTestContext* context) +{ + T test; + test.init(device, context); + test.run(); } +} // namespace namespace gfx_test { - SLANG_UNIT_TEST(resolveResourceSimpleD3D12) - { - runTestImpl(resolveResourceTestImpl<ResolveResourceSimple>, unitTestContext, Slang::RenderApiFlag::D3D12); - } +SLANG_UNIT_TEST(resolveResourceSimpleD3D12) +{ + runTestImpl( + resolveResourceTestImpl<ResolveResourceSimple>, + unitTestContext, + Slang::RenderApiFlag::D3D12); +} - SLANG_UNIT_TEST(resolveResourceSimpleVulkan) - { - runTestImpl(resolveResourceTestImpl<ResolveResourceSimple>, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(resolveResourceSimpleVulkan) +{ + runTestImpl( + resolveResourceTestImpl<ResolveResourceSimple>, + unitTestContext, + Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/root-mutable-shader-object.cpp b/tools/gfx-unit-test/root-mutable-shader-object.cpp index 1d489786e..fce4cc0da 100644 --- a/tools/gfx-unit-test/root-mutable-shader-object.cpp +++ b/tools/gfx-unit-test/root-mutable-shader-object.cpp @@ -1,119 +1,123 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void mutableRootShaderObjectTestImpl(IDevice* device, UnitTestContext* context) +void mutableRootShaderObjectTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "mutable-shader-object", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; + const int numberCount = SLANG_COUNT_OF(initialData); + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = sizeof(initialData); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + ComPtr<IShaderObject> rootObject; + device->createMutableRootShaderObject(shaderProgram, rootObject.writeRef()); + auto entryPointCursor = ShaderCursor(rootObject->getEntryPoint(0)); + entryPointCursor.getPath("buffer").setResource(bufferView); + + slang::TypeReflection* addTransformerType = slangReflection->findTypeByName("AddTransformer"); + ComPtr<IShaderObject> transformer; + GFX_CHECK_CALL_ABORT(device->createMutableShaderObject( + addTransformerType, + ShaderObjectContainerType::None, + transformer.writeRef())); + entryPointCursor.getPath("transformer").setObject(transformer); + + // Set the `c` field of the `AddTransformer`. + float c = 1.0f; + ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "mutable-shader-object", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - const int numberCount = SLANG_COUNT_OF(initialData); - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = sizeof(initialData); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + { + auto encoder = commandBuffer->encodeComputeCommands(); + encoder->bindPipelineWithRootObject(pipelineState, rootObject); + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + } + + auto barrierEncoder = commandBuffer->encodeResourceCommands(); + barrierEncoder->bufferBarrier( + 1, + numbersBuffer.readRef(), ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - ComPtr<IShaderObject> rootObject; - device->createMutableRootShaderObject(shaderProgram, rootObject.writeRef()); - auto entryPointCursor = ShaderCursor(rootObject->getEntryPoint(0)); - entryPointCursor.getPath("buffer").setResource(bufferView); - - slang::TypeReflection* addTransformerType = - slangReflection->findTypeByName("AddTransformer"); - ComPtr<IShaderObject> transformer; - GFX_CHECK_CALL_ABORT(device->createMutableShaderObject( - addTransformerType, ShaderObjectContainerType::None, transformer.writeRef())); - entryPointCursor.getPath("transformer").setObject(transformer); - - // Set the `c` field of the `AddTransformer`. - float c = 1.0f; - ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + ResourceState::UnorderedAccess); + barrierEncoder->endEncoding(); + // Mutate `transformer` object and run again. + c = 2.0f; + ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - { - auto encoder = commandBuffer->encodeComputeCommands(); - encoder->bindPipelineWithRootObject(pipelineState, rootObject); - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - } - - auto barrierEncoder = commandBuffer->encodeResourceCommands(); - barrierEncoder->bufferBarrier(1, numbersBuffer.readRef(), ResourceState::UnorderedAccess, ResourceState::UnorderedAccess); - barrierEncoder->endEncoding(); - - // Mutate `transformer` object and run again. - c = 2.0f; - ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); - { - auto encoder = commandBuffer->encodeComputeCommands(); - encoder->bindPipelineWithRootObject(pipelineState, rootObject); - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - } - - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); + auto encoder = commandBuffer->encodeComputeCommands(); + encoder->bindPipelineWithRootObject(pipelineState, rootObject); + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); } - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<float>(3.0f, 4.0f, 5.0f, 6.0f)); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(mutableRootShaderObjectD3D12) - { - runTestImpl(mutableRootShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(3.0f, 4.0f, 5.0f, 6.0f)); +} - /*SLANG_UNIT_TEST(mutableRootShaderObjectVulkan) - { - runTestImpl(mutableRootShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - }*/ +SLANG_UNIT_TEST(mutableRootShaderObjectD3D12) +{ + runTestImpl(mutableRootShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); } + +/*SLANG_UNIT_TEST(mutableRootShaderObjectVulkan) +{ + runTestImpl(mutableRootShaderObjectTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +}*/ +} // namespace gfx_test diff --git a/tools/gfx-unit-test/root-shader-parameter.cpp b/tools/gfx-unit-test/root-shader-parameter.cpp index 1a7be91c4..f933ec48a 100644 --- a/tools/gfx-unit-test/root-shader-parameter.cpp +++ b/tools/gfx-unit-test/root-shader-parameter.cpp @@ -1,139 +1,151 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - static ComPtr<IBufferResource> createBuffer(IDevice* device, uint32_t content) +static ComPtr<IBufferResource> createBuffer(IDevice* device, uint32_t content) +{ + ComPtr<IBufferResource> buffer; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = sizeof(uint32_t); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)&content, buffer.writeRef())); + + return buffer; +} +void rootShaderParameterTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "root-shader-parameter", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + Slang::List<ComPtr<IBufferResource>> buffers; + Slang::List<ComPtr<IResourceView>> srvs, uavs; + + for (uint32_t i = 0; i < 9; i++) { - ComPtr<IBufferResource> buffer; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = sizeof(uint32_t); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT( - device->createBufferResource(bufferDesc, (void*)&content, buffer.writeRef())); + buffers.add(createBuffer(device, i == 0 ? 10 : i)); - return buffer; - } - void rootShaderParameterTestImpl(IDevice* device, UnitTestContext* context) - { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "root-shader-parameter", "computeMain", slangReflection)); + device->createBufferView(buffers[i], nullptr, viewDesc, bufferView.writeRef())); + uavs.add(bufferView); - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; + viewDesc.type = IResourceView::Type::ShaderResource; + viewDesc.format = Format::Unknown; GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - Slang::List<ComPtr<IBufferResource>> buffers; - Slang::List<ComPtr<IResourceView>> srvs, uavs; - - for (uint32_t i = 0; i < 9; i++) - { - buffers.add(createBuffer(device, i == 0 ? 10 : i)); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(buffers[i], nullptr, viewDesc, bufferView.writeRef())); - uavs.add(bufferView); - - viewDesc.type = IResourceView::Type::ShaderResource; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(buffers[i], nullptr, viewDesc, bufferView.writeRef())); - srvs.add(bufferView); - } + device->createBufferView(buffers[i], nullptr, viewDesc, bufferView.writeRef())); + srvs.add(bufferView); + } - ComPtr<IShaderObject> rootObject; - device->createMutableRootShaderObject(shaderProgram, rootObject.writeRef()); + ComPtr<IShaderObject> rootObject; + device->createMutableRootShaderObject(shaderProgram, rootObject.writeRef()); + + ComPtr<IShaderObject> g, s1, s2; + device->createMutableShaderObject( + slangReflection->findTypeByName("S0"), + ShaderObjectContainerType::None, + g.writeRef()); + device->createMutableShaderObject( + slangReflection->findTypeByName("S1"), + ShaderObjectContainerType::None, + s1.writeRef()); + device->createMutableShaderObject( + slangReflection->findTypeByName("S1"), + ShaderObjectContainerType::None, + s2.writeRef()); - ComPtr<IShaderObject> g, s1, s2; - device->createMutableShaderObject( - slangReflection->findTypeByName("S0"), ShaderObjectContainerType::None, g.writeRef()); - device->createMutableShaderObject( - slangReflection->findTypeByName("S1"), ShaderObjectContainerType::None, s1.writeRef()); - device->createMutableShaderObject( - slangReflection->findTypeByName("S1"), ShaderObjectContainerType::None, s2.writeRef()); + { + auto cursor = ShaderCursor(s1); + cursor["c0"].setResource(srvs[2]); + cursor["c1"].setResource(uavs[3]); + cursor["c2"].setResource(srvs[4]); + } + { + auto cursor = ShaderCursor(s2); + cursor["c0"].setResource(srvs[5]); + cursor["c1"].setResource(uavs[6]); + cursor["c2"].setResource(srvs[7]); + } + { + auto cursor = ShaderCursor(g); + cursor["b0"].setResource(srvs[0]); + cursor["b1"].setResource(srvs[1]); + cursor["s1"].setObject(s1); + cursor["s2"].setObject(s2); + } + { + auto cursor = ShaderCursor(rootObject); + cursor["g"].setObject(g); + cursor["buffer"].setResource(uavs[8]); + } - { - auto cursor = ShaderCursor(s1); - cursor["c0"].setResource(srvs[2]); - cursor["c1"].setResource(uavs[3]); - cursor["c2"].setResource(srvs[4]); - } - { - auto cursor = ShaderCursor(s2); - cursor["c0"].setResource(srvs[5]); - cursor["c1"].setResource(uavs[6]); - cursor["c2"].setResource(srvs[7]); - } - { - auto cursor = ShaderCursor(g); - cursor["b0"].setResource(srvs[0]); - cursor["b1"].setResource(srvs[1]); - cursor["s1"].setObject(s1); - cursor["s2"].setObject(s2); - } - { - auto cursor = ShaderCursor(rootObject); - cursor["g"].setObject(g); - cursor["buffer"].setResource(uavs[8]); - } + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + auto commandBuffer = transientHeap->createCommandBuffer(); { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - { - auto encoder = commandBuffer->encodeComputeCommands(); - encoder->bindPipelineWithRootObject(pipelineState, rootObject); - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - } - - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); + auto encoder = commandBuffer->encodeComputeCommands(); + encoder->bindPipelineWithRootObject(pipelineState, rootObject); + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); } - compareComputeResult( - device, buffers[8], Slang::makeArray<uint32_t>(10 - 1 + 2 - 3 + 4 + 5 - 6 + 7)); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(rootShaderParameterD3D12) - { - runTestImpl(rootShaderParameterTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + compareComputeResult( + device, + buffers[8], + Slang::makeArray<uint32_t>(10 - 1 + 2 - 3 + 4 + 5 - 6 + 7)); +} - SLANG_UNIT_TEST(rootShaderParameterVulkan) - { - runTestImpl(rootShaderParameterTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(rootShaderParameterD3D12) +{ + runTestImpl(rootShaderParameterTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(rootShaderParameterVulkan) +{ + runTestImpl(rootShaderParameterTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/sampler-array.cpp b/tools/gfx-unit-test/sampler-array.cpp index 945c31b07..720aa0a2c 100644 --- a/tools/gfx-unit-test/sampler-array.cpp +++ b/tools/gfx-unit-test/sampler-array.cpp @@ -1,159 +1,160 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - static ComPtr<IBufferResource> createBuffer(IDevice* device, uint32_t content) - { - ComPtr<IBufferResource> buffer; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = sizeof(uint32_t); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT( - device->createBufferResource(bufferDesc, (void*)&content, buffer.writeRef())); +static ComPtr<IBufferResource> createBuffer(IDevice* device, uint32_t content) +{ + ComPtr<IBufferResource> buffer; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = sizeof(uint32_t); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)&content, buffer.writeRef())); + + return buffer; +} +void samplerArrayTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT( + loadComputeProgram(device, shaderProgram, "sampler-array", "computeMain", slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + Slang::List<ComPtr<ISamplerState>> samplers; + Slang::List<ComPtr<IResourceView>> srvs; + ComPtr<IResourceView> uav; + ComPtr<ITextureResource> texture; + ComPtr<IBufferResource> buffer = createBuffer(device, 0); - return buffer; + { + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT(device->createBufferView(buffer, nullptr, viewDesc, uav.writeRef())); } - void samplerArrayTestImpl(IDevice* device, UnitTestContext* context) { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; + ITextureResource::Desc textureDesc = {}; + textureDesc.type = IResource::Type::Texture2D; + textureDesc.format = Format::R8G8B8A8_UNORM; + textureDesc.size.width = 2; + textureDesc.size.height = 2; + textureDesc.size.depth = 1; + textureDesc.numMipLevels = 2; + textureDesc.memoryType = MemoryType::DeviceLocal; + textureDesc.defaultState = ResourceState::ShaderResource; + textureDesc.allowedStates.add(ResourceState::CopyDestination); + uint32_t data[] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; + ITextureResource::SubresourceData subResourceData[2] = {{data, 8, 16}, {data, 8, 16}}; GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + device->createTextureResource(textureDesc, subResourceData, texture.writeRef())); + } + for (uint32_t i = 0; i < 32; i++) + { + ComPtr<IResourceView> srv; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::ShaderResource; + viewDesc.format = Format::R8G8B8A8_UNORM; + viewDesc.subresourceRange.layerCount = 1; + viewDesc.subresourceRange.mipLevelCount = 1; + GFX_CHECK_CALL_ABORT(device->createTextureView(texture, viewDesc, srv.writeRef())); + srvs.add(srv); + } - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "sampler-array", "computeMain", slangReflection)); + for (uint32_t i = 0; i < 32; i++) + { + ISamplerState::Desc desc = {}; + ComPtr<ISamplerState> sampler; + GFX_CHECK_CALL_ABORT(device->createSamplerState(desc, sampler.writeRef())); + samplers.add(sampler); + } - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + ComPtr<IShaderObject> rootObject; + device->createMutableRootShaderObject(shaderProgram, rootObject.writeRef()); - Slang::List<ComPtr<ISamplerState>> samplers; - Slang::List<ComPtr<IResourceView>> srvs; - ComPtr<IResourceView> uav; - ComPtr<ITextureResource> texture; - ComPtr<IBufferResource> buffer = createBuffer(device, 0); + ComPtr<IShaderObject> g; + device->createMutableShaderObject( + slangReflection->findTypeByName("S0"), + ShaderObjectContainerType::None, + g.writeRef()); - { - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(buffer, nullptr, viewDesc, uav.writeRef())); - } - { - ITextureResource::Desc textureDesc = {}; - textureDesc.type = IResource::Type::Texture2D; - textureDesc.format = Format::R8G8B8A8_UNORM; - textureDesc.size.width = 2; - textureDesc.size.height = 2; - textureDesc.size.depth = 1; - textureDesc.numMipLevels = 2; - textureDesc.memoryType = MemoryType::DeviceLocal; - textureDesc.defaultState = ResourceState::ShaderResource; - textureDesc.allowedStates.add(ResourceState::CopyDestination); - uint32_t data[] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; - ITextureResource::SubresourceData subResourceData[2] = {{data, 8, 16}, {data, 8, 16}}; - GFX_CHECK_CALL_ABORT( - device->createTextureResource(textureDesc, subResourceData, texture.writeRef())); - } - for (uint32_t i = 0; i < 32; i++) - { - ComPtr<IResourceView> srv; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::ShaderResource; - viewDesc.format = Format::R8G8B8A8_UNORM; - viewDesc.subresourceRange.layerCount = 1; - viewDesc.subresourceRange.mipLevelCount = 1; - GFX_CHECK_CALL_ABORT( - device->createTextureView(texture, viewDesc, srv.writeRef())); - srvs.add(srv); - } + ComPtr<IShaderObject> s1; + device->createMutableShaderObject( + slangReflection->findTypeByName("S1"), + ShaderObjectContainerType::None, + s1.writeRef()); + { + auto cursor = ShaderCursor(s1); for (uint32_t i = 0; i < 32; i++) { - ISamplerState::Desc desc = {}; - ComPtr<ISamplerState> sampler; - GFX_CHECK_CALL_ABORT(device->createSamplerState(desc, sampler.writeRef())); - samplers.add(sampler); + cursor["samplers"][i].setSampler(samplers[i]); + cursor["tex"][i].setResource(srvs[i]); } + cursor["data"].setData(1.0f); + } - ComPtr<IShaderObject> rootObject; - device->createMutableRootShaderObject(shaderProgram, rootObject.writeRef()); - - ComPtr<IShaderObject> g; - device->createMutableShaderObject( - slangReflection->findTypeByName("S0"), ShaderObjectContainerType::None, g.writeRef()); - - ComPtr<IShaderObject> s1; - device->createMutableShaderObject( - slangReflection->findTypeByName("S1"), ShaderObjectContainerType::None, s1.writeRef()); - - { - auto cursor = ShaderCursor(s1); - for (uint32_t i = 0; i < 32; i++) - { - cursor["samplers"][i].setSampler(samplers[i]); - cursor["tex"][i].setResource(srvs[i]); - } - cursor["data"].setData(1.0f); - } + { + auto cursor = ShaderCursor(g); + cursor["s"].setObject(s1); + cursor["data"].setData(2.0f); + } - { - auto cursor = ShaderCursor(g); - cursor["s"].setObject(s1); - cursor["data"].setData(2.0f); - } + { + auto cursor = ShaderCursor(rootObject); + cursor["g"].setObject(g); + cursor["buffer"].setResource(uav); + } - { - auto cursor = ShaderCursor(rootObject); - cursor["g"].setObject(g); - cursor["buffer"].setResource(uav); - } + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + auto commandBuffer = transientHeap->createCommandBuffer(); { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - { - auto encoder = commandBuffer->encodeComputeCommands(); - encoder->bindPipelineWithRootObject(pipelineState, rootObject); - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - } - - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); + auto encoder = commandBuffer->encodeComputeCommands(); + encoder->bindPipelineWithRootObject(pipelineState, rootObject); + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); } - compareComputeResult( - device, buffer, Slang::makeArray<float>(4.0f)); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(samplerArrayVulkan) - { - runTestImpl(samplerArrayTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } + compareComputeResult(device, buffer, Slang::makeArray<float>(4.0f)); +} + +SLANG_UNIT_TEST(samplerArrayVulkan) +{ + runTestImpl(samplerArrayTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/shader-cache-tests.cpp b/tools/gfx-unit-test/shader-cache-tests.cpp index 4477c4f56..8ee8d9015 100644 --- a/tools/gfx-unit-test/shader-cache-tests.cpp +++ b/tools/gfx-unit-test/shader-cache-tests.cpp @@ -1,44 +1,43 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" +#include "gfx-test-texture-util.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" -#include "source/core/slang-string-util.h" -#include "source/core/slang-io.h" #include "source/core/slang-file-system.h" +#include "source/core/slang-io.h" #include "source/core/slang-process.h" -#include "gfx-test-texture-util.h" +#include "source/core/slang-string-util.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; using namespace Slang; namespace gfx_test { - // Base class for shader cache tests. - // Slang currently does not allow reloading shaders from modified sources. - // Because of this, the tests recreate a GFX device for each test step, - // allowing to modify shader sources in between. - struct ShaderCacheTest - { - UnitTestContext* context; - Slang::RenderApiFlag::Enum api; +// Base class for shader cache tests. +// Slang currently does not allow reloading shaders from modified sources. +// Because of this, the tests recreate a GFX device for each test step, +// allowing to modify shader sources in between. +struct ShaderCacheTest +{ + UnitTestContext* context; + Slang::RenderApiFlag::Enum api; - String testDirectory; - String cacheDirectory; + String testDirectory; + String cacheDirectory; - ComPtr<ISlangMutableFileSystem> diskFileSystem; + ComPtr<ISlangMutableFileSystem> diskFileSystem; - IDevice::ShaderCacheDesc shaderCacheDesc = {}; + IDevice::ShaderCacheDesc shaderCacheDesc = {}; - ComPtr<IDevice> device; - ComPtr<IShaderCache> shaderCache; - ComPtr<IPipelineState> pipelineState; - ComPtr<IBufferResource> bufferResource; - ComPtr<IResourceView> bufferView; + ComPtr<IDevice> device; + ComPtr<IShaderCache> shaderCache; + ComPtr<IPipelineState> pipelineState; + ComPtr<IBufferResource> bufferResource; + ComPtr<IResourceView> bufferView; - String computeShaderA = String( - R"( + String computeShaderA = String( + R"( [shader("compute")] [numthreads(4, 1, 1)] void main( @@ -48,10 +47,10 @@ namespace gfx_test var input = buffer[sv_dispatchThreadID.x]; buffer[sv_dispatchThreadID.x] = input + 1.0f; } - )"); + )"); - String computeShaderB = String( - R"( + String computeShaderB = String( + R"( [shader("compute")] [numthreads(4, 1, 1)] void main( @@ -63,8 +62,8 @@ namespace gfx_test } )"); - String computeShaderC = String( - R"( + String computeShaderC = String( + R"( [shader("compute")] [numthreads(4, 1, 1)] void main( @@ -77,359 +76,383 @@ namespace gfx_test )"); - void removeDirectory(const String& directory) - { - auto osFileSystem = OSFileSystem::getMutableSingleton(); - - struct Context - { - ISlangMutableFileSystem *fileSystem; - const String& directory; - } context { osFileSystem, directory }; - - osFileSystem->enumeratePathContents( - directory.getBuffer(), - [](SlangPathType pathType, const char* fileName, void* userData) - { - struct Context* context = static_cast<Context *>(userData); - if (pathType == SlangPathType::SLANG_PATH_TYPE_FILE) - { - String path = Path::simplify(context->directory + "/" + fileName); - context->fileSystem->remove(path.getBuffer()); - } - }, - &context); - - osFileSystem->remove(directory.getBuffer()); - } - - void writeShader(const String& source, const String& fileName) - { - diskFileSystem->saveFile(fileName.getBuffer(), source.getBuffer(), source.getLength()); - } - - void init(UnitTestContext* context, Slang::RenderApiFlag::Enum api) - { - this->context = context; - this->api = api; - testDirectory = Path::simplify(Path::getParentDirectory(Path::getExecutablePath()) + "/shader-cache-test" + String(Process::getId())); - cacheDirectory = Path::simplify(testDirectory + "/cache" + String(Process::getId())); - - // Cleanup if there are stale files from a previously aborted test. - removeDirectory(cacheDirectory); - removeDirectory(testDirectory); - - Path::createDirectory(testDirectory); - diskFileSystem = new RelativeFileSystem(OSFileSystem::getMutableSingleton(), testDirectory); - shaderCacheDesc.shaderCachePath = cacheDirectory.getBuffer(); - } - - void cleanup() - { - removeDirectory(cacheDirectory); - removeDirectory(testDirectory); - } + void removeDirectory(const String& directory) + { + auto osFileSystem = OSFileSystem::getMutableSingleton(); - template<typename Func> - void runStep(Func func) + struct Context { - List<const char*> additionalSearchPaths; - additionalSearchPaths.add(testDirectory.getBuffer()); + ISlangMutableFileSystem* fileSystem; + const String& directory; + } context{osFileSystem, directory}; - runTestImpl( - [this, func] (IDevice* device, UnitTestContext* ctx) + osFileSystem->enumeratePathContents( + directory.getBuffer(), + [](SlangPathType pathType, const char* fileName, void* userData) + { + struct Context* context = static_cast<Context*>(userData); + if (pathType == SlangPathType::SLANG_PATH_TYPE_FILE) { - this->device = device; - SLANG_CHECK_ABORT(SLANG_SUCCEEDED( - device->queryInterface(SLANG_UUID_IShaderCache, (void**)this->shaderCache.writeRef()))); - func(); - this->device = nullptr; - this->shaderCache = nullptr; - }, - context, api, additionalSearchPaths, shaderCacheDesc); - } - - void createComputeResources() - { - const int numberCount = 4; - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - bufferResource.writeRef())); - - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(bufferResource, nullptr, viewDesc, bufferView.writeRef())); - } - - void freeComputeResources() - { - bufferResource = nullptr; - bufferView = nullptr; - pipelineState = nullptr; - } - - void createComputePipeline(const char* moduleName, const char* entryPointName) - { - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, moduleName, entryPointName, slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - } - - void createComputePipeline(Slang::String shaderSource) - { - ComPtr<IShaderProgram> shaderProgram; - GFX_CHECK_CALL_ABORT(loadComputeProgramFromSource(device, shaderProgram, shaderSource)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - } + String path = Path::simplify(context->directory + "/" + fileName); + context->fileSystem->remove(path.getBuffer()); + } + }, + &context); - void dispatchComputePipeline() - { - ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + osFileSystem->remove(directory.getBuffer()); + } - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); + void writeShader(const String& source, const String& fileName) + { + diskFileSystem->saveFile(fileName.getBuffer(), source.getBuffer(), source.getLength()); + } - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); + void init(UnitTestContext* context, Slang::RenderApiFlag::Enum api) + { + this->context = context; + this->api = api; + testDirectory = Path::simplify( + Path::getParentDirectory(Path::getExecutablePath()) + "/shader-cache-test" + + String(Process::getId())); + cacheDirectory = Path::simplify(testDirectory + "/cache" + String(Process::getId())); + + // Cleanup if there are stale files from a previously aborted test. + removeDirectory(cacheDirectory); + removeDirectory(testDirectory); + + Path::createDirectory(testDirectory); + diskFileSystem = new RelativeFileSystem(OSFileSystem::getMutableSingleton(), testDirectory); + shaderCacheDesc.shaderCachePath = cacheDirectory.getBuffer(); + } - auto rootObject = encoder->bindPipeline(pipelineState); + void cleanup() + { + removeDirectory(cacheDirectory); + removeDirectory(testDirectory); + } - // Bind buffer view to the entry point. - ShaderCursor entryPointCursor(rootObject->getEntryPoint(0)); - entryPointCursor.getPath("buffer").setResource(bufferView); + template<typename Func> + void runStep(Func func) + { + List<const char*> additionalSearchPaths; + additionalSearchPaths.add(testDirectory.getBuffer()); - encoder->dispatchCompute(4, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + runTestImpl( + [this, func](IDevice* device, UnitTestContext* ctx) + { + this->device = device; + SLANG_CHECK_ABORT(SLANG_SUCCEEDED(device->queryInterface( + SLANG_UUID_IShaderCache, + (void**)this->shaderCache.writeRef()))); + func(); + this->device = nullptr; + this->shaderCache = nullptr; + }, + context, + api, + additionalSearchPaths, + shaderCacheDesc); + } - bool checkOutput(const List<float>& expectedOutput) - { - ComPtr<ISlangBlob> bufferBlob; - device->readBufferResource(bufferResource, 0, 4 * sizeof(float), bufferBlob.writeRef()); - SLANG_CHECK_ABORT(bufferBlob && bufferBlob->getBufferSize() == expectedOutput.getCount() * sizeof(float)); - return ::memcmp(bufferBlob->getBufferPointer(), expectedOutput.getBuffer(), bufferBlob->getBufferSize()) == 0; - } + void createComputeResources() + { + const int numberCount = 4; + float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + GFX_CHECK_CALL_ABORT(device->createBufferResource( + bufferDesc, + (void*)initialData, + bufferResource.writeRef())); + + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(bufferResource, nullptr, viewDesc, bufferView.writeRef())); + } - bool runComputePipeline(const char* moduleName, const char* entryPointName, const List<float>& expectedOutput) - { - createComputeResources(); - createComputePipeline(moduleName, entryPointName); - dispatchComputePipeline(); - bool hasExpectedOutput = checkOutput(expectedOutput); - SLANG_CHECK(hasExpectedOutput); - freeComputeResources(); - return hasExpectedOutput; - } - - bool runComputePipeline(Slang::String shaderSource, const List<float>& expectedOutput) - { - createComputeResources(); - createComputePipeline(shaderSource); - dispatchComputePipeline(); - bool hasExpectedOutput = checkOutput(expectedOutput); - SLANG_CHECK(hasExpectedOutput); - freeComputeResources(); - return hasExpectedOutput; - } - - ShaderCacheStats getStats() - { - SLANG_ASSERT(shaderCache); - ShaderCacheStats stats; - shaderCache->getShaderCacheStats(&stats); - return stats; - } + void freeComputeResources() + { + bufferResource = nullptr; + bufferView = nullptr; + pipelineState = nullptr; + } - void run(UnitTestContext* context, Slang::RenderApiFlag::Enum api) - { - init(context, api); - runTests(); - cleanup(); - } + void createComputePipeline(const char* moduleName, const char* entryPointName) + { + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT( + loadComputeProgram(device, shaderProgram, moduleName, entryPointName, slangReflection)); - virtual void runTests() = 0; - }; + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + } - // Basic shader cache test using 3 different shader files stored on disk. - struct ShaderCacheSourceFile : ShaderCacheTest + void createComputePipeline(Slang::String shaderSource) { - void runTests() - { - // Write shader source files. - writeShader(computeShaderA, "shader-cache-tmp-a.slang"); - writeShader(computeShaderB, "shader-cache-tmp-b.slang"); - writeShader(computeShaderC, "shader-cache-tmp-c.slang"); - - // Cache is cold and we expect 3 misses. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-tmp-a", "main", { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-b", "main", { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-c", "main", { 3.f, 4.f, 5.f, 6.f })); - - SLANG_CHECK(getStats().missCount == 3); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 3); - } - ); + ComPtr<IShaderProgram> shaderProgram; + GFX_CHECK_CALL_ABORT(loadComputeProgramFromSource(device, shaderProgram, shaderSource)); - // Cache is hot and we expect 3 hits. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-tmp-a", "main", { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-b", "main", { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-c", "main", { 3.f, 4.f, 5.f, 6.f })); + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + } - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 3); - SLANG_CHECK(getStats().entryCount == 3); - } - ); + void dispatchComputePipeline() + { + ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - // Write shader source files, all rotated by one. - writeShader(computeShaderA, "shader-cache-tmp-b.slang"); - writeShader(computeShaderB, "shader-cache-tmp-c.slang"); - writeShader(computeShaderC, "shader-cache-tmp-a.slang"); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - // Cache is cold again and we expect 3 misses. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-tmp-b", "main", { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-c", "main", { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-a", "main", { 3.f, 4.f, 5.f, 6.f })); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - SLANG_CHECK(getStats().missCount == 3); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 6); - } - ); + auto rootObject = encoder->bindPipeline(pipelineState); - // Cache is hot again and we expect 3 hits. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-tmp-b", "main", { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-c", "main", { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-a", "main", { 3.f, 4.f, 5.f, 6.f })); + // Bind buffer view to the entry point. + ShaderCursor entryPointCursor(rootObject->getEntryPoint(0)); + entryPointCursor.getPath("buffer").setResource(bufferView); - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 3); - SLANG_CHECK(getStats().entryCount == 6); - } - ); - } - }; + encoder->dispatchCompute(4, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - // Test caching of shaders that are compiled from source strings instead of files. - struct ShaderCacheTestSourceString : ShaderCacheTest + bool checkOutput(const List<float>& expectedOutput) { - void runTests() - { - // Cache is cold and we expect 3 misses. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline(computeShaderA, { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline(computeShaderB, { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline(computeShaderC, { 3.f, 4.f, 5.f, 6.f })); + ComPtr<ISlangBlob> bufferBlob; + device->readBufferResource(bufferResource, 0, 4 * sizeof(float), bufferBlob.writeRef()); + SLANG_CHECK_ABORT( + bufferBlob && bufferBlob->getBufferSize() == expectedOutput.getCount() * sizeof(float)); + return ::memcmp( + bufferBlob->getBufferPointer(), + expectedOutput.getBuffer(), + bufferBlob->getBufferSize()) == 0; + } - SLANG_CHECK(getStats().missCount == 3); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 3); - } - ); + bool runComputePipeline( + const char* moduleName, + const char* entryPointName, + const List<float>& expectedOutput) + { + createComputeResources(); + createComputePipeline(moduleName, entryPointName); + dispatchComputePipeline(); + bool hasExpectedOutput = checkOutput(expectedOutput); + SLANG_CHECK(hasExpectedOutput); + freeComputeResources(); + return hasExpectedOutput; + } - // Cache is hot and we expect 3 hits. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline(computeShaderA, { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline(computeShaderB, { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline(computeShaderC, { 3.f, 4.f, 5.f, 6.f })); + bool runComputePipeline(Slang::String shaderSource, const List<float>& expectedOutput) + { + createComputeResources(); + createComputePipeline(shaderSource); + dispatchComputePipeline(); + bool hasExpectedOutput = checkOutput(expectedOutput); + SLANG_CHECK(hasExpectedOutput); + freeComputeResources(); + return hasExpectedOutput; + } - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 3); - SLANG_CHECK(getStats().entryCount == 3); - } - ); - } - }; + ShaderCacheStats getStats() + { + SLANG_ASSERT(shaderCache); + ShaderCacheStats stats; + shaderCache->getShaderCacheStats(&stats); + return stats; + } - // Test one shader file on disk with multiple entry points. - struct ShaderCacheTestEntryPoint : ShaderCacheTest + void run(UnitTestContext* context, Slang::RenderApiFlag::Enum api) { - void runTests() - { - // Cache is cold and we expect 3 misses, one for each entry point. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-multiple-entry-points", "computeA", { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline("shader-cache-multiple-entry-points", "computeB", { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline("shader-cache-multiple-entry-points", "computeC", { 3.f, 4.f, 5.f, 6.f })); + init(context, api); + runTests(); + cleanup(); + } - SLANG_CHECK(getStats().missCount == 3); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 3); - } - ); + virtual void runTests() = 0; +}; - // Cache is hot and we expect 3 hits. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-multiple-entry-points", "computeA", { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline("shader-cache-multiple-entry-points", "computeB", { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline("shader-cache-multiple-entry-points", "computeC", { 3.f, 4.f, 5.f, 6.f })); +// Basic shader cache test using 3 different shader files stored on disk. +struct ShaderCacheSourceFile : ShaderCacheTest +{ + void runTests() + { + // Write shader source files. + writeShader(computeShaderA, "shader-cache-tmp-a.slang"); + writeShader(computeShaderB, "shader-cache-tmp-b.slang"); + writeShader(computeShaderC, "shader-cache-tmp-c.slang"); + + // Cache is cold and we expect 3 misses. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline("shader-cache-tmp-a", "main", {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline("shader-cache-tmp-b", "main", {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK(runComputePipeline("shader-cache-tmp-c", "main", {3.f, 4.f, 5.f, 6.f})); + + SLANG_CHECK(getStats().missCount == 3); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 3); + }); + + // Cache is hot and we expect 3 hits. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline("shader-cache-tmp-a", "main", {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline("shader-cache-tmp-b", "main", {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK(runComputePipeline("shader-cache-tmp-c", "main", {3.f, 4.f, 5.f, 6.f})); + + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 3); + SLANG_CHECK(getStats().entryCount == 3); + }); + + // Write shader source files, all rotated by one. + writeShader(computeShaderA, "shader-cache-tmp-b.slang"); + writeShader(computeShaderB, "shader-cache-tmp-c.slang"); + writeShader(computeShaderC, "shader-cache-tmp-a.slang"); + + // Cache is cold again and we expect 3 misses. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline("shader-cache-tmp-b", "main", {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline("shader-cache-tmp-c", "main", {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK(runComputePipeline("shader-cache-tmp-a", "main", {3.f, 4.f, 5.f, 6.f})); + + SLANG_CHECK(getStats().missCount == 3); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 6); + }); + + // Cache is hot again and we expect 3 hits. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline("shader-cache-tmp-b", "main", {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline("shader-cache-tmp-c", "main", {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK(runComputePipeline("shader-cache-tmp-a", "main", {3.f, 4.f, 5.f, 6.f})); + + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 3); + SLANG_CHECK(getStats().entryCount == 6); + }); + } +}; - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 3); - SLANG_CHECK(getStats().entryCount == 3); - } - ); - } - }; +// Test caching of shaders that are compiled from source strings instead of files. +struct ShaderCacheTestSourceString : ShaderCacheTest +{ + void runTests() + { + // Cache is cold and we expect 3 misses. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline(computeShaderA, {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline(computeShaderB, {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK(runComputePipeline(computeShaderC, {3.f, 4.f, 5.f, 6.f})); + + SLANG_CHECK(getStats().missCount == 3); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 3); + }); + + // Cache is hot and we expect 3 hits. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline(computeShaderA, {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline(computeShaderB, {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK(runComputePipeline(computeShaderC, {3.f, 4.f, 5.f, 6.f})); + + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 3); + SLANG_CHECK(getStats().entryCount == 3); + }); + } +}; - // Test cache invalidation due to an import/include file being changed on disk. - struct ShaderCacheTestImportInclude : ShaderCacheTest +// Test one shader file on disk with multiple entry points. +struct ShaderCacheTestEntryPoint : ShaderCacheTest +{ + void runTests() { - String importedContentsA = String( - R"( + // Cache is cold and we expect 3 misses, one for each entry point. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline( + "shader-cache-multiple-entry-points", + "computeA", + {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline( + "shader-cache-multiple-entry-points", + "computeB", + {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK(runComputePipeline( + "shader-cache-multiple-entry-points", + "computeC", + {3.f, 4.f, 5.f, 6.f})); + + SLANG_CHECK(getStats().missCount == 3); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 3); + }); + + // Cache is hot and we expect 3 hits. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline( + "shader-cache-multiple-entry-points", + "computeA", + {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline( + "shader-cache-multiple-entry-points", + "computeB", + {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK(runComputePipeline( + "shader-cache-multiple-entry-points", + "computeC", + {3.f, 4.f, 5.f, 6.f})); + + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 3); + SLANG_CHECK(getStats().entryCount == 3); + }); + } +}; + +// Test cache invalidation due to an import/include file being changed on disk. +struct ShaderCacheTestImportInclude : ShaderCacheTest +{ + String importedContentsA = String( + R"( public void processElement(RWStructuredBuffer<float> buffer, uint index) { var input = buffer[index]; @@ -437,8 +460,8 @@ namespace gfx_test } )"); - String importedContentsB = String( - R"( + String importedContentsB = String( + R"( public void processElement(RWStructuredBuffer<float> buffer, uint index) { var input = buffer[index]; @@ -446,8 +469,8 @@ namespace gfx_test } )"); - String importFile = String( - R"( + String importFile = String( + R"( import shader_cache_tmp_imported; [shader("compute")] @@ -460,8 +483,8 @@ namespace gfx_test } )"); - String includeFile = String( - R"( + String includeFile = String( + R"( #include "shader-cache-tmp-imported.slang" [shader("compute")] @@ -473,627 +496,635 @@ namespace gfx_test processElement(buffer, sv_dispatchThreadID.x); })"); - void runTests() - { - // Write shader source files. - writeShader(importedContentsA, "shader-cache-tmp-imported.slang"); - writeShader(importFile, "shader-cache-tmp-import.slang"); - writeShader(includeFile, "shader-cache-tmp-include.slang"); - - // Cache is cold and we expect 2 misses. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-tmp-import", "main", { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-include", "main", { 1.f, 2.f, 3.f, 4.f })); - - SLANG_CHECK(getStats().missCount == 2); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 2); - } - ); - - // Cache is hot and we expect 2 hits. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-tmp-import", "main", { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-include", "main", { 1.f, 2.f, 3.f, 4.f })); - - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 2); - SLANG_CHECK(getStats().entryCount == 2); - } - ); - - // Change content of imported/included shader file. - writeShader(importedContentsB, "shader-cache-tmp-imported.slang"); - - // Cache is cold and we expect 2 misses. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-tmp-import", "main", { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-include", "main", { 2.f, 3.f, 4.f, 5.f })); - - SLANG_CHECK(getStats().missCount == 2); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 4); - } - ); - - // Cache is hot and we expect 2 hits. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("shader-cache-tmp-import", "main", { 2.f, 3.f, 4.f, 5.f })); - SLANG_CHECK(runComputePipeline("shader-cache-tmp-include", "main", { 2.f, 3.f, 4.f, 5.f })); - - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 2); - SLANG_CHECK(getStats().entryCount == 4); - } - ); - } - }; - - // One shader featuring multiple kinds of shader objects that can be bound. - struct ShaderCacheTestSpecialization : ShaderCacheTest + void runTests() { - slang::ProgramLayout* slangReflection; - - void createComputePipeline() - { - ComPtr<IShaderProgram> shaderProgram; - - GFX_CHECK_CALL_ABORT( - loadComputeProgram(device, shaderProgram, "shader-cache-specialization", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - } - - void dispatchComputePipeline(const char* transformerTypeName) - { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); + // Write shader source files. + writeShader(importedContentsA, "shader-cache-tmp-imported.slang"); + writeShader(importFile, "shader-cache-tmp-import.slang"); + writeShader(includeFile, "shader-cache-tmp-include.slang"); + + // Cache is cold and we expect 2 misses. + runStep( + [this]() + { + SLANG_CHECK( + runComputePipeline("shader-cache-tmp-import", "main", {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK( + runComputePipeline("shader-cache-tmp-include", "main", {1.f, 2.f, 3.f, 4.f})); + + SLANG_CHECK(getStats().missCount == 2); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 2); + }); + + // Cache is hot and we expect 2 hits. + runStep( + [this]() + { + SLANG_CHECK( + runComputePipeline("shader-cache-tmp-import", "main", {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK( + runComputePipeline("shader-cache-tmp-include", "main", {1.f, 2.f, 3.f, 4.f})); + + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 2); + SLANG_CHECK(getStats().entryCount == 2); + }); + + // Change content of imported/included shader file. + writeShader(importedContentsB, "shader-cache-tmp-imported.slang"); + + // Cache is cold and we expect 2 misses. + runStep( + [this]() + { + SLANG_CHECK( + runComputePipeline("shader-cache-tmp-import", "main", {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK( + runComputePipeline("shader-cache-tmp-include", "main", {2.f, 3.f, 4.f, 5.f})); + + SLANG_CHECK(getStats().missCount == 2); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 4); + }); + + // Cache is hot and we expect 2 hits. + runStep( + [this]() + { + SLANG_CHECK( + runComputePipeline("shader-cache-tmp-import", "main", {2.f, 3.f, 4.f, 5.f})); + SLANG_CHECK( + runComputePipeline("shader-cache-tmp-include", "main", {2.f, 3.f, 4.f, 5.f})); + + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 2); + SLANG_CHECK(getStats().entryCount == 4); + }); + } +}; - Slang::ComPtr<IShaderObject> transformer; - slang::TypeReflection* transformerType = slangReflection->findTypeByName(transformerTypeName); - GFX_CHECK_CALL_ABORT(device->createShaderObject( - transformerType, ShaderObjectContainerType::None, transformer.writeRef())); +// One shader featuring multiple kinds of shader objects that can be bound. +struct ShaderCacheTestSpecialization : ShaderCacheTest +{ + slang::ProgramLayout* slangReflection; - float c = 5.f; - ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + void createComputePipeline() + { + ComPtr<IShaderProgram> shaderProgram; + + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "shader-cache-specialization", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + } - ShaderCursor entryPointCursor(rootObject->getEntryPoint(0)); - entryPointCursor.getPath("buffer").setResource(bufferView); - entryPointCursor.getPath("transformer").setObject(transformer); + void dispatchComputePipeline(const char* transformerTypeName) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + Slang::ComPtr<IShaderObject> transformer; + slang::TypeReflection* transformerType = + slangReflection->findTypeByName(transformerTypeName); + GFX_CHECK_CALL_ABORT(device->createShaderObject( + transformerType, + ShaderObjectContainerType::None, + transformer.writeRef())); + + float c = 5.f; + ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + + ShaderCursor entryPointCursor(rootObject->getEntryPoint(0)); + entryPointCursor.getPath("buffer").setResource(bufferView); + entryPointCursor.getPath("transformer").setObject(transformer); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + bool runComputePipeline(const char* transformerTypeName, const List<float>& expectedOutput) + { + createComputeResources(); + createComputePipeline(); + dispatchComputePipeline(transformerTypeName); + bool hasExpectedOutput = checkOutput(expectedOutput); + SLANG_CHECK(hasExpectedOutput); + freeComputeResources(); + return hasExpectedOutput; + } - bool runComputePipeline(const char* transformerTypeName, const List<float>& expectedOutput) - { - createComputeResources(); - createComputePipeline(); - dispatchComputePipeline(transformerTypeName); - bool hasExpectedOutput = checkOutput(expectedOutput); - SLANG_CHECK(hasExpectedOutput); - freeComputeResources(); - return hasExpectedOutput; - } - - void runTests() - { - // Cache is cold and we expect 2 misses. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("AddTransformer", { 5.f, 6.f, 7.f, 8.f })); - SLANG_CHECK(runComputePipeline("MulTransformer", { 0.f, 5.f, 10.f, 15.f })); + void runTests() + { + // Cache is cold and we expect 2 misses. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline("AddTransformer", {5.f, 6.f, 7.f, 8.f})); + SLANG_CHECK(runComputePipeline("MulTransformer", {0.f, 5.f, 10.f, 15.f})); - SLANG_CHECK(getStats().missCount == 2); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 2); - } - ); + SLANG_CHECK(getStats().missCount == 2); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 2); + }); - // Cache is hot and we expect 2 hits. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline("AddTransformer", { 5.f, 6.f, 7.f, 8.f })); - SLANG_CHECK(runComputePipeline("MulTransformer", { 0.f, 5.f, 10.f, 15.f })); + // Cache is hot and we expect 2 hits. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline("AddTransformer", {5.f, 6.f, 7.f, 8.f})); + SLANG_CHECK(runComputePipeline("MulTransformer", {0.f, 5.f, 10.f, 15.f})); - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 2); - SLANG_CHECK(getStats().entryCount == 2); - } - ); - } - }; + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 2); + SLANG_CHECK(getStats().entryCount == 2); + }); + } +}; - struct ShaderCacheTestEviction : ShaderCacheTest +struct ShaderCacheTestEviction : ShaderCacheTest +{ + void runTests() { - void runTests() - { - shaderCacheDesc.maxEntryCount = 2; + shaderCacheDesc.maxEntryCount = 2; - // Load shader A & B. Cache is cold and we expect 2 misses. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline(computeShaderA, { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline(computeShaderB, { 2.f, 3.f, 4.f, 5.f })); - - SLANG_CHECK(getStats().missCount == 2); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 2); - } - ); - - // Load shader A & B. Cache is hot and we expect 2 hits. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline(computeShaderA, { 1.f, 2.f, 3.f, 4.f })); - SLANG_CHECK(runComputePipeline(computeShaderB, { 2.f, 3.f, 4.f, 5.f })); + // Load shader A & B. Cache is cold and we expect 2 misses. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline(computeShaderA, {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline(computeShaderB, {2.f, 3.f, 4.f, 5.f})); - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 2); - SLANG_CHECK(getStats().entryCount == 2); - } - ); + SLANG_CHECK(getStats().missCount == 2); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 2); + }); - // Load shader C. Cache is cold and we expect 1 miss. - // This will evict the least frequently used entry (shader A). - // We expect 2 entries in the cache (shader B & C). - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline(computeShaderC, { 3.f, 4.f, 5.f, 6.f })); + // Load shader A & B. Cache is hot and we expect 2 hits. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline(computeShaderA, {1.f, 2.f, 3.f, 4.f})); + SLANG_CHECK(runComputePipeline(computeShaderB, {2.f, 3.f, 4.f, 5.f})); + + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 2); + SLANG_CHECK(getStats().entryCount == 2); + }); + + // Load shader C. Cache is cold and we expect 1 miss. + // This will evict the least frequently used entry (shader A). + // We expect 2 entries in the cache (shader B & C). + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline(computeShaderC, {3.f, 4.f, 5.f, 6.f})); - SLANG_CHECK(getStats().missCount == 1); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 2); - } - ); + SLANG_CHECK(getStats().missCount == 1); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 2); + }); - // Load shader C. Cache is hot and we expect 1 hit. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline(computeShaderC, { 3.f, 4.f, 5.f, 6.f })); + // Load shader C. Cache is hot and we expect 1 hit. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline(computeShaderC, {3.f, 4.f, 5.f, 6.f})); - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 1); - SLANG_CHECK(getStats().entryCount == 2); - } - ); + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 1); + SLANG_CHECK(getStats().entryCount == 2); + }); - // Load shader B. Cache is hot and we expect 1 hit. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline(computeShaderB, { 2.f, 3.f, 4.f, 5.f })); + // Load shader B. Cache is hot and we expect 1 hit. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline(computeShaderB, {2.f, 3.f, 4.f, 5.f})); - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 1); - SLANG_CHECK(getStats().entryCount == 2); - } - ); + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 1); + SLANG_CHECK(getStats().entryCount == 2); + }); - // Load shader A. Cache is cold and we expect 1 miss. - runStep( - [this]() - { - SLANG_CHECK(runComputePipeline(computeShaderA, { 1.f, 2.f, 3.f, 4.f })); + // Load shader A. Cache is cold and we expect 1 miss. + runStep( + [this]() + { + SLANG_CHECK(runComputePipeline(computeShaderA, {1.f, 2.f, 3.f, 4.f})); - SLANG_CHECK(getStats().missCount == 1); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 2); - } - ); - } - }; + SLANG_CHECK(getStats().missCount == 1); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 2); + }); + } +}; - // Similar to ShaderCacheTestEntryPoint but with a source file containing a vertex and fragment shader. - struct ShaderCacheTestGraphics : ShaderCacheTest +// Similar to ShaderCacheTestEntryPoint but with a source file containing a vertex and fragment +// shader. +struct ShaderCacheTestGraphics : ShaderCacheTest +{ + struct Vertex { - struct Vertex - { - float position[3]; - }; - - static const int kWidth = 256; - static const int kHeight = 256; - static const Format format = Format::R32G32B32A32_FLOAT; - - ComPtr<IBufferResource> vertexBuffer; - ComPtr<ITextureResource> colorBuffer; - ComPtr<IInputLayout> inputLayout; - ComPtr<IFramebufferLayout> framebufferLayout; - ComPtr<IRenderPassLayout> renderPass; - ComPtr<IFramebuffer> framebuffer; - - ComPtr<IBufferResource> createVertexBuffer(IDevice* device) - { - const Vertex vertices[] = { - { 0, 0, 0.5 }, - { 1, 0, 0.5 }, - { 0, 1, 0.5 }, - }; - - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = sizeof(vertices); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; - ComPtr<IBufferResource> vertexBuffer = device->createBufferResource(vertexBufferDesc, vertices); - SLANG_CHECK_ABORT(vertexBuffer != nullptr); - return vertexBuffer; - } - - ComPtr<ITextureResource> createColorBuffer(IDevice* device) - { - gfx::ITextureResource::Desc colorBufferDesc; - colorBufferDesc.type = IResource::Type::Texture2D; - colorBufferDesc.size.width = kWidth; - colorBufferDesc.size.height = kHeight; - colorBufferDesc.size.depth = 1; - colorBufferDesc.numMipLevels = 1; - colorBufferDesc.format = format; - colorBufferDesc.defaultState = ResourceState::RenderTarget; - colorBufferDesc.allowedStates = { ResourceState::RenderTarget, ResourceState::CopySource }; - ComPtr<ITextureResource> colorBuffer = device->createTextureResource(colorBufferDesc, nullptr); - SLANG_CHECK_ABORT(colorBuffer != nullptr); - return colorBuffer; - } - - void createGraphicsResources() - { - VertexStreamDesc vertexStreams[] = { - { sizeof(Vertex), InputSlotClass::PerVertex, 0 }, - }; - - InputElementDesc inputElements[] = { - // Vertex buffer data - { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0 }, - }; - IInputLayout::Desc inputLayoutDesc = {}; - inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); - inputLayoutDesc.inputElements = inputElements; - inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); - inputLayoutDesc.vertexStreams = vertexStreams; - inputLayout = device->createInputLayout(inputLayoutDesc); - SLANG_CHECK_ABORT(inputLayout != nullptr); - - vertexBuffer = createVertexBuffer(device); - colorBuffer = createColorBuffer(device); - - IFramebufferLayout::TargetLayout targetLayout; - targetLayout.format = format; - targetLayout.sampleCount = 1; - - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &targetLayout; - framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc); - SLANG_CHECK_ABORT(framebufferLayout != nullptr); - - IRenderPassLayout::Desc renderPassDesc = {}; - renderPassDesc.framebufferLayout = framebufferLayout; - renderPassDesc.renderTargetCount = 1; - IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; - renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; - renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; - renderTargetAccess.initialState = ResourceState::RenderTarget; - renderTargetAccess.finalState = ResourceState::CopySource; - renderPassDesc.renderTargetAccess = &renderTargetAccess; - GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); - - gfx::IResourceView::Desc colorBufferViewDesc; - memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); - colorBufferViewDesc.format = format; - colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; - colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; - auto rtv = device->createTextureView(colorBuffer, colorBufferViewDesc); - - gfx::IFramebuffer::Desc framebufferDesc; - framebufferDesc.renderTargetCount = 1; - framebufferDesc.depthStencilView = nullptr; - framebufferDesc.renderTargetViews = rtv.readRef(); - framebufferDesc.layout = framebufferLayout; - GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); - } - - void freeGraphicsResources() - { - inputLayout = nullptr; - framebufferLayout = nullptr; - renderPass = nullptr; - framebuffer = nullptr; - vertexBuffer = nullptr; - colorBuffer = nullptr; - pipelineState = nullptr; - } - - void createGraphicsPipeline() - { - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT( - loadGraphicsProgram(device, shaderProgram, "shader-cache-graphics", "vertexMain", "fragmentMain", slangReflection)); - - GraphicsPipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - pipelineDesc.inputLayout = inputLayout; - pipelineDesc.framebufferLayout = framebufferLayout; - pipelineDesc.depthStencil.depthTestEnable = false; - pipelineDesc.depthStencil.depthWriteEnable = false; - GFX_CHECK_CALL_ABORT( - device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); - } - - void dispatchGraphicsPipeline() - { - ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - - auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); - auto rootObject = encoder->bindPipeline(pipelineState); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)kWidth; - viewport.extentY = (float)kHeight; - encoder->setViewportAndScissor(viewport); - - encoder->setVertexBuffer(0, vertexBuffer); - encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - - encoder->draw(3); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - void runGraphicsPipeline() - { - createGraphicsResources(); - createGraphicsPipeline(); - dispatchGraphicsPipeline(); - freeGraphicsResources(); - } - - void runTests() - { - // Cache is cold and we expect 2 misses (2 entry points). - runStep( - [this]() - { - runGraphicsPipeline(); - - SLANG_CHECK(getStats().missCount == 2); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 2); - } - ); - - // Cache is hot and we expect 2 hits. - runStep( - [this]() - { - runGraphicsPipeline(); - - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 2); - SLANG_CHECK(getStats().entryCount == 2); - } - ); - } + float position[3]; }; - // Similar to ShaderCacheTestGraphics but with two separate shader files for the vertex and fragment shaders. - struct ShaderCacheTestGraphicsSplit : ShaderCacheTestGraphics - { - void createGraphicsPipeline() - { - ComPtr<slang::ISession> slangSession; - GFX_CHECK_CALL_ABORT(device->getSlangSession(slangSession.writeRef())); - slang::IModule* vertexModule = slangSession->loadModule("shader-cache-graphics-vertex"); - SLANG_CHECK_ABORT(vertexModule); - slang::IModule* fragmentModule = slangSession->loadModule("shader-cache-graphics-fragment"); - SLANG_CHECK_ABORT(fragmentModule); - - ComPtr<slang::IEntryPoint> vertexEntryPoint; - GFX_CHECK_CALL_ABORT( - vertexModule->findEntryPointByName("main", vertexEntryPoint.writeRef())); - - ComPtr<slang::IEntryPoint> fragmentEntryPoint; - GFX_CHECK_CALL_ABORT( - fragmentModule->findEntryPointByName("main", fragmentEntryPoint.writeRef())); - - Slang::List<slang::IComponentType*> componentTypes; - componentTypes.add(vertexModule); - componentTypes.add(fragmentModule); - - Slang::ComPtr<slang::IComponentType> composedProgram; - GFX_CHECK_CALL_ABORT( - slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef())); - - slang::ProgramLayout* slangReflection = composedProgram->getLayout(); - - Slang::List<slang::IComponentType*> entryPoints; - entryPoints.add(vertexEntryPoint); - entryPoints.add(fragmentEntryPoint); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = composedProgram.get(); - programDesc.linkingStyle = gfx::IShaderProgram::LinkingStyle::SeparateEntryPointCompilation; - programDesc.entryPointCount = 2; - programDesc.slangEntryPoints = entryPoints.getBuffer(); - - ComPtr<IShaderProgram> shaderProgram = device->createProgram(programDesc); - - GraphicsPipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - pipelineDesc.inputLayout = inputLayout; - pipelineDesc.framebufferLayout = framebufferLayout; - pipelineDesc.depthStencil.depthTestEnable = false; - pipelineDesc.depthStencil.depthWriteEnable = false; - GFX_CHECK_CALL_ABORT( - device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); - } - - void runGraphicsPipeline() - { - createGraphicsResources(); - createGraphicsPipeline(); - dispatchGraphicsPipeline(); - freeGraphicsResources(); - } - - void runTests() - { - // Cache is cold and we expect 2 misses (2 entry points). - runStep( - [this]() - { - runGraphicsPipeline(); + static const int kWidth = 256; + static const int kHeight = 256; + static const Format format = Format::R32G32B32A32_FLOAT; - SLANG_CHECK(getStats().missCount == 2); - SLANG_CHECK(getStats().hitCount == 0); - SLANG_CHECK(getStats().entryCount == 2); - } - ); - - // Cache is hot and we expect 2 hits. - runStep( - [this]() - { - runGraphicsPipeline(); - - SLANG_CHECK(getStats().missCount == 0); - SLANG_CHECK(getStats().hitCount == 2); - SLANG_CHECK(getStats().entryCount == 2); - } - ); } - }; + ComPtr<IBufferResource> vertexBuffer; + ComPtr<ITextureResource> colorBuffer; + ComPtr<IInputLayout> inputLayout; + ComPtr<IFramebufferLayout> framebufferLayout; + ComPtr<IRenderPassLayout> renderPass; + ComPtr<IFramebuffer> framebuffer; - template<typename T> - void runTest(UnitTestContext* context, Slang::RenderApiFlag::Enum api) + ComPtr<IBufferResource> createVertexBuffer(IDevice* device) { - T test; - test.run(context, api); - } + const Vertex vertices[] = { + {0, 0, 0.5}, + {1, 0, 0.5}, + {0, 1, 0.5}, + }; - SLANG_UNIT_TEST(shaderCacheSourceFileD3D12) - { - runTest<ShaderCacheSourceFile>(unitTestContext, Slang::RenderApiFlag::D3D12); + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = sizeof(vertices); + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; + ComPtr<IBufferResource> vertexBuffer = + device->createBufferResource(vertexBufferDesc, vertices); + SLANG_CHECK_ABORT(vertexBuffer != nullptr); + return vertexBuffer; } - SLANG_UNIT_TEST(shaderCacheSourceFileVulkan) + ComPtr<ITextureResource> createColorBuffer(IDevice* device) { - runTest<ShaderCacheSourceFile>(unitTestContext, Slang::RenderApiFlag::Vulkan); + gfx::ITextureResource::Desc colorBufferDesc; + colorBufferDesc.type = IResource::Type::Texture2D; + colorBufferDesc.size.width = kWidth; + colorBufferDesc.size.height = kHeight; + colorBufferDesc.size.depth = 1; + colorBufferDesc.numMipLevels = 1; + colorBufferDesc.format = format; + colorBufferDesc.defaultState = ResourceState::RenderTarget; + colorBufferDesc.allowedStates = {ResourceState::RenderTarget, ResourceState::CopySource}; + ComPtr<ITextureResource> colorBuffer = + device->createTextureResource(colorBufferDesc, nullptr); + SLANG_CHECK_ABORT(colorBuffer != nullptr); + return colorBuffer; } - SLANG_UNIT_TEST(shaderCacheSourceStringD3D12) + void createGraphicsResources() { - runTest<ShaderCacheTestSourceString>(unitTestContext, Slang::RenderApiFlag::D3D12); - } + VertexStreamDesc vertexStreams[] = { + {sizeof(Vertex), InputSlotClass::PerVertex, 0}, + }; - SLANG_UNIT_TEST(shaderCacheSourceStringVulkan) - { - runTest<ShaderCacheTestSourceString>(unitTestContext, Slang::RenderApiFlag::Vulkan); + InputElementDesc inputElements[] = { + // Vertex buffer data + {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0}, + }; + IInputLayout::Desc inputLayoutDesc = {}; + inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); + inputLayoutDesc.inputElements = inputElements; + inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); + inputLayoutDesc.vertexStreams = vertexStreams; + inputLayout = device->createInputLayout(inputLayoutDesc); + SLANG_CHECK_ABORT(inputLayout != nullptr); + + vertexBuffer = createVertexBuffer(device); + colorBuffer = createColorBuffer(device); + + IFramebufferLayout::TargetLayout targetLayout; + targetLayout.format = format; + targetLayout.sampleCount = 1; + + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &targetLayout; + framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc); + SLANG_CHECK_ABORT(framebufferLayout != nullptr); + + IRenderPassLayout::Desc renderPassDesc = {}; + renderPassDesc.framebufferLayout = framebufferLayout; + renderPassDesc.renderTargetCount = 1; + IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; + renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; + renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; + renderTargetAccess.initialState = ResourceState::RenderTarget; + renderTargetAccess.finalState = ResourceState::CopySource; + renderPassDesc.renderTargetAccess = &renderTargetAccess; + GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = format; + colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; + auto rtv = device->createTextureView(colorBuffer, colorBufferViewDesc); + + gfx::IFramebuffer::Desc framebufferDesc; + framebufferDesc.renderTargetCount = 1; + framebufferDesc.depthStencilView = nullptr; + framebufferDesc.renderTargetViews = rtv.readRef(); + framebufferDesc.layout = framebufferLayout; + GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); } - SLANG_UNIT_TEST(shaderCacheEntryPointD3D12) + void freeGraphicsResources() { - runTest<ShaderCacheTestEntryPoint>(unitTestContext, Slang::RenderApiFlag::D3D12); + inputLayout = nullptr; + framebufferLayout = nullptr; + renderPass = nullptr; + framebuffer = nullptr; + vertexBuffer = nullptr; + colorBuffer = nullptr; + pipelineState = nullptr; } - SLANG_UNIT_TEST(shaderCacheEntryPointVulkan) + void createGraphicsPipeline() { - runTest<ShaderCacheTestEntryPoint>(unitTestContext, Slang::RenderApiFlag::Vulkan); + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadGraphicsProgram( + device, + shaderProgram, + "shader-cache-graphics", + "vertexMain", + "fragmentMain", + slangReflection)); + + GraphicsPipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + pipelineDesc.inputLayout = inputLayout; + pipelineDesc.framebufferLayout = framebufferLayout; + pipelineDesc.depthStencil.depthTestEnable = false; + pipelineDesc.depthStencil.depthWriteEnable = false; + GFX_CHECK_CALL_ABORT( + device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); } - SLANG_UNIT_TEST(shaderCacheImportIncludeD3D12) + void dispatchGraphicsPipeline() { - runTest<ShaderCacheTestImportInclude>(unitTestContext, Slang::RenderApiFlag::D3D12); + ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + auto commandBuffer = transientHeap->createCommandBuffer(); + + auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); + auto rootObject = encoder->bindPipeline(pipelineState); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)kWidth; + viewport.extentY = (float)kHeight; + encoder->setViewportAndScissor(viewport); + + encoder->setVertexBuffer(0, vertexBuffer); + encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + + encoder->draw(3); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - SLANG_UNIT_TEST(shaderCacheImportIncludeVulkan) + void runGraphicsPipeline() { - runTest<ShaderCacheTestImportInclude>(unitTestContext, Slang::RenderApiFlag::Vulkan); + createGraphicsResources(); + createGraphicsPipeline(); + dispatchGraphicsPipeline(); + freeGraphicsResources(); } - SLANG_UNIT_TEST(shaderCacheSpecializationD3D12) + void runTests() { - runTest<ShaderCacheTestSpecialization>(unitTestContext, Slang::RenderApiFlag::D3D12); - } + // Cache is cold and we expect 2 misses (2 entry points). + runStep( + [this]() + { + runGraphicsPipeline(); - SLANG_UNIT_TEST(shaderCacheSpecializationVulkan) - { - runTest<ShaderCacheTestSpecialization>(unitTestContext, Slang::RenderApiFlag::Vulkan); - } + SLANG_CHECK(getStats().missCount == 2); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 2); + }); - SLANG_UNIT_TEST(shaderCacheEvictionD3D12) - { - runTest<ShaderCacheTestEviction>(unitTestContext, Slang::RenderApiFlag::D3D12); - } + // Cache is hot and we expect 2 hits. + runStep( + [this]() + { + runGraphicsPipeline(); - SLANG_UNIT_TEST(shaderCacheEvictionVulkan) - { - runTest<ShaderCacheTestEviction>(unitTestContext, Slang::RenderApiFlag::Vulkan); + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 2); + SLANG_CHECK(getStats().entryCount == 2); + }); } +}; - SLANG_UNIT_TEST(shaderCacheGraphicsD3D12) +// Similar to ShaderCacheTestGraphics but with two separate shader files for the vertex and fragment +// shaders. +struct ShaderCacheTestGraphicsSplit : ShaderCacheTestGraphics +{ + void createGraphicsPipeline() { - runTest<ShaderCacheTestGraphics>(unitTestContext, Slang::RenderApiFlag::D3D12); + ComPtr<slang::ISession> slangSession; + GFX_CHECK_CALL_ABORT(device->getSlangSession(slangSession.writeRef())); + slang::IModule* vertexModule = slangSession->loadModule("shader-cache-graphics-vertex"); + SLANG_CHECK_ABORT(vertexModule); + slang::IModule* fragmentModule = slangSession->loadModule("shader-cache-graphics-fragment"); + SLANG_CHECK_ABORT(fragmentModule); + + ComPtr<slang::IEntryPoint> vertexEntryPoint; + GFX_CHECK_CALL_ABORT( + vertexModule->findEntryPointByName("main", vertexEntryPoint.writeRef())); + + ComPtr<slang::IEntryPoint> fragmentEntryPoint; + GFX_CHECK_CALL_ABORT( + fragmentModule->findEntryPointByName("main", fragmentEntryPoint.writeRef())); + + Slang::List<slang::IComponentType*> componentTypes; + componentTypes.add(vertexModule); + componentTypes.add(fragmentModule); + + Slang::ComPtr<slang::IComponentType> composedProgram; + GFX_CHECK_CALL_ABORT(slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef())); + + slang::ProgramLayout* slangReflection = composedProgram->getLayout(); + + Slang::List<slang::IComponentType*> entryPoints; + entryPoints.add(vertexEntryPoint); + entryPoints.add(fragmentEntryPoint); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = composedProgram.get(); + programDesc.linkingStyle = gfx::IShaderProgram::LinkingStyle::SeparateEntryPointCompilation; + programDesc.entryPointCount = 2; + programDesc.slangEntryPoints = entryPoints.getBuffer(); + + ComPtr<IShaderProgram> shaderProgram = device->createProgram(programDesc); + + GraphicsPipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + pipelineDesc.inputLayout = inputLayout; + pipelineDesc.framebufferLayout = framebufferLayout; + pipelineDesc.depthStencil.depthTestEnable = false; + pipelineDesc.depthStencil.depthWriteEnable = false; + GFX_CHECK_CALL_ABORT( + device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); } - SLANG_UNIT_TEST(shaderCacheGraphicsVulkan) + void runGraphicsPipeline() { - runTest<ShaderCacheTestGraphics>(unitTestContext, Slang::RenderApiFlag::Vulkan); + createGraphicsResources(); + createGraphicsPipeline(); + dispatchGraphicsPipeline(); + freeGraphicsResources(); } - SLANG_UNIT_TEST(shaderCacheGraphicsSplitD3D12) + void runTests() { - runTest<ShaderCacheTestGraphicsSplit>(unitTestContext, Slang::RenderApiFlag::D3D12); - } + // Cache is cold and we expect 2 misses (2 entry points). + runStep( + [this]() + { + runGraphicsPipeline(); - SLANG_UNIT_TEST(shaderCacheGraphicsSplitVulkan) - { - runTest<ShaderCacheTestGraphicsSplit>(unitTestContext, Slang::RenderApiFlag::Vulkan); + SLANG_CHECK(getStats().missCount == 2); + SLANG_CHECK(getStats().hitCount == 0); + SLANG_CHECK(getStats().entryCount == 2); + }); + + // Cache is hot and we expect 2 hits. + runStep( + [this]() + { + runGraphicsPipeline(); + + SLANG_CHECK(getStats().missCount == 0); + SLANG_CHECK(getStats().hitCount == 2); + SLANG_CHECK(getStats().entryCount == 2); + }); } +}; + +template<typename T> +void runTest(UnitTestContext* context, Slang::RenderApiFlag::Enum api) +{ + T test; + test.run(context, api); +} + +SLANG_UNIT_TEST(shaderCacheSourceFileD3D12) +{ + runTest<ShaderCacheSourceFile>(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(shaderCacheSourceFileVulkan) +{ + runTest<ShaderCacheSourceFile>(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(shaderCacheSourceStringD3D12) +{ + runTest<ShaderCacheTestSourceString>(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(shaderCacheSourceStringVulkan) +{ + runTest<ShaderCacheTestSourceString>(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(shaderCacheEntryPointD3D12) +{ + runTest<ShaderCacheTestEntryPoint>(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(shaderCacheEntryPointVulkan) +{ + runTest<ShaderCacheTestEntryPoint>(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(shaderCacheImportIncludeD3D12) +{ + runTest<ShaderCacheTestImportInclude>(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(shaderCacheImportIncludeVulkan) +{ + runTest<ShaderCacheTestImportInclude>(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(shaderCacheSpecializationD3D12) +{ + runTest<ShaderCacheTestSpecialization>(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(shaderCacheSpecializationVulkan) +{ + runTest<ShaderCacheTestSpecialization>(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(shaderCacheEvictionD3D12) +{ + runTest<ShaderCacheTestEviction>(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(shaderCacheEvictionVulkan) +{ + runTest<ShaderCacheTestEviction>(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(shaderCacheGraphicsD3D12) +{ + runTest<ShaderCacheTestGraphics>(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(shaderCacheGraphicsVulkan) +{ + runTest<ShaderCacheTestGraphics>(unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(shaderCacheGraphicsSplitD3D12) +{ + runTest<ShaderCacheTestGraphicsSplit>(unitTestContext, Slang::RenderApiFlag::D3D12); +} + +SLANG_UNIT_TEST(shaderCacheGraphicsSplitVulkan) +{ + runTest<ShaderCacheTestGraphicsSplit>(unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test diff --git a/tools/gfx-unit-test/shared-buffers-tests.cpp b/tools/gfx-unit-test/shared-buffers-tests.cpp index ccd223fc0..4355dda99 100644 --- a/tools/gfx-unit-test/shared-buffers-tests.cpp +++ b/tools/gfx-unit-test/shared-buffers-tests.cpp @@ -1,124 +1,128 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void sharedBufferTestImpl(IDevice* srcDevice, IDevice* dstDevice, UnitTestContext* context) +void sharedBufferTestImpl(IDevice* srcDevice, IDevice* dstDevice, UnitTestContext* context) +{ + // Create a shareable buffer using srcDevice, get its handle, then create a buffer using the + // handle using dstDevice. Read back the buffer and check that its contents are correct. + const int numberCount = 4; + float initialData[] = {0.0f, 1.0f, 2.0f, 3.0f}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + bufferDesc.isShared = true; + + ComPtr<IBufferResource> srcBuffer; + GFX_CHECK_CALL_ABORT( + srcDevice->createBufferResource(bufferDesc, (void*)initialData, srcBuffer.writeRef())); + + InteropHandle sharedHandle; + GFX_CHECK_CALL_ABORT(srcBuffer->getSharedHandle(&sharedHandle)); + ComPtr<IBufferResource> dstBuffer; + GFX_CHECK_CALL_ABORT( + dstDevice->createBufferFromSharedHandle(sharedHandle, bufferDesc, dstBuffer.writeRef())); + // Reading back the buffer from srcDevice to make sure it's been filled in before reading + // anything back from dstDevice + // TODO: Implement actual synchronization (and not this hacky solution) + compareComputeResult(srcDevice, srcBuffer, Slang::makeArray<float>(0.0f, 1.0f, 2.0f, 3.0f)); + + InteropHandle testHandle; + GFX_CHECK_CALL_ABORT(dstBuffer->getNativeResourceHandle(&testHandle)); + IBufferResource::Desc* testDesc = dstBuffer->getDesc(); + SLANG_CHECK(testDesc->elementSize == sizeof(float)); + SLANG_CHECK(testDesc->sizeInBytes == numberCount * sizeof(float)); + compareComputeResult(dstDevice, dstBuffer, Slang::makeArray<float>(0.0f, 1.0f, 2.0f, 3.0f)); + + // Check that dstBuffer can be successfully used in a compute dispatch using dstDevice. + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + dstDevice->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + dstDevice, + shaderProgram, + "compute-trivial", + "computeMain", + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + dstDevice->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + dstDevice->createBufferView(dstBuffer, nullptr, viewDesc, bufferView.writeRef())); + { - // Create a shareable buffer using srcDevice, get its handle, then create a buffer using the handle using - // dstDevice. Read back the buffer and check that its contents are correct. - const int numberCount = 4; - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - bufferDesc.isShared = true; - - ComPtr<IBufferResource> srcBuffer; - GFX_CHECK_CALL_ABORT(srcDevice->createBufferResource( - bufferDesc, - (void*)initialData, - srcBuffer.writeRef())); - - InteropHandle sharedHandle; - GFX_CHECK_CALL_ABORT(srcBuffer->getSharedHandle(&sharedHandle)); - ComPtr<IBufferResource> dstBuffer; - GFX_CHECK_CALL_ABORT(dstDevice->createBufferFromSharedHandle(sharedHandle, bufferDesc, dstBuffer.writeRef())); - // Reading back the buffer from srcDevice to make sure it's been filled in before reading anything back from dstDevice - // TODO: Implement actual synchronization (and not this hacky solution) - compareComputeResult(srcDevice, srcBuffer, Slang::makeArray<float>(0.0f, 1.0f, 2.0f, 3.0f)); - - InteropHandle testHandle; - GFX_CHECK_CALL_ABORT(dstBuffer->getNativeResourceHandle(&testHandle)); - IBufferResource::Desc* testDesc = dstBuffer->getDesc(); - SLANG_CHECK(testDesc->elementSize == sizeof(float)); - SLANG_CHECK(testDesc->sizeInBytes == numberCount * sizeof(float)); - compareComputeResult(dstDevice, dstBuffer, Slang::makeArray<float>(0.0f, 1.0f, 2.0f, 3.0f)); - - // Check that dstBuffer can be successfully used in a compute dispatch using dstDevice. - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - dstDevice->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(dstDevice, shaderProgram, "compute-trivial", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - dstDevice->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - dstDevice->createBufferView(dstBuffer, nullptr, viewDesc, bufferView.writeRef())); - - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = dstDevice->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor rootCursor(rootObject); - // Bind buffer view to the entry point. - rootCursor.getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - dstDevice, - dstBuffer, - Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = dstDevice->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor rootCursor(rootObject); + // Bind buffer view to the entry point. + rootCursor.getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } - void sharedBufferTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum srcApi, Slang::RenderApiFlag::Enum dstApi) + compareComputeResult(dstDevice, dstBuffer, Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); +} + +void sharedBufferTestAPI( + UnitTestContext* context, + Slang::RenderApiFlag::Enum srcApi, + Slang::RenderApiFlag::Enum dstApi) +{ + auto srcDevice = createTestingDevice(context, srcApi); + auto dstDevice = createTestingDevice(context, dstApi); + if (!srcDevice || !dstDevice) { - auto srcDevice = createTestingDevice(context, srcApi); - auto dstDevice = createTestingDevice(context, dstApi); - if (!srcDevice || !dstDevice) - { - SLANG_IGNORE_TEST; - } - - sharedBufferTestImpl(srcDevice, dstDevice, context); + SLANG_IGNORE_TEST; } + + sharedBufferTestImpl(srcDevice, dstDevice, context); +} #if SLANG_WIN64 - SLANG_UNIT_TEST(sharedBufferD3D12ToCUDA) - { - sharedBufferTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12, Slang::RenderApiFlag::CUDA); - } +SLANG_UNIT_TEST(sharedBufferD3D12ToCUDA) +{ + sharedBufferTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12, Slang::RenderApiFlag::CUDA); +} - SLANG_UNIT_TEST(sharedBufferVulkanToCUDA) - { - sharedBufferTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan, Slang::RenderApiFlag::CUDA); - } -#endif +SLANG_UNIT_TEST(sharedBufferVulkanToCUDA) +{ + sharedBufferTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan, Slang::RenderApiFlag::CUDA); } +#endif +} // namespace gfx_test diff --git a/tools/gfx-unit-test/shared-textures-tests.cpp b/tools/gfx-unit-test/shared-textures-tests.cpp index 4afa23546..ee8108c39 100644 --- a/tools/gfx-unit-test/shared-textures-tests.cpp +++ b/tools/gfx-unit-test/shared-textures-tests.cpp @@ -1,223 +1,261 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void setUpAndRunShader( - IDevice* device, - ComPtr<ITextureResource> tex, - ComPtr<IResourceView> texView, - ComPtr<IResourceView> bufferView, - const char* entryPoint, - ComPtr<ISamplerState> sampler = nullptr) +void setUpAndRunShader( + IDevice* device, + ComPtr<ITextureResource> tex, + ComPtr<IResourceView> texView, + ComPtr<IResourceView> bufferView, + const char* entryPoint, + ComPtr<ISamplerState> sampler = nullptr) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT( + loadComputeProgram(device, shaderProgram, "trivial-copy", entryPoint, slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "trivial-copy", entryPoint, slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - - auto& desc = *tex->getDesc(); - entryPointCursor["width"].setData(desc.size.width); - entryPointCursor["height"].setData(desc.size.height); - - // Bind texture view to the entry point - entryPointCursor["tex"].setResource(texView); - - if (sampler) entryPointCursor["sampler"].setSampler(sampler); - - // Bind buffer view to the entry point. - entryPointCursor["buffer"].setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - } + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - ComPtr<ITextureResource> createTexture(IDevice* device, ITextureResource::Extents extents, gfx::Format format, ITextureResource::SubresourceData* initialData) - { - ITextureResource::Desc texDesc = {}; - texDesc.type = IResource::Type::Texture2D; - texDesc.numMipLevels = 1; - texDesc.arraySize = 1; - texDesc.size = extents; - texDesc.defaultState = ResourceState::UnorderedAccess; - texDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - texDesc.format = format; - texDesc.isShared = true; - - ComPtr<ITextureResource> inTex; - GFX_CHECK_CALL_ABORT(device->createTextureResource( - texDesc, - initialData, - inTex.writeRef())); - return inTex; - } + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - ComPtr<IResourceView> createTexView(IDevice* device, ComPtr<ITextureResource> inTexture) - { - ComPtr<IResourceView> texView; - IResourceView::Desc texViewDesc = {}; - texViewDesc.type = IResourceView::Type::UnorderedAccess; - texViewDesc.format = inTexture->getDesc()->format; // TODO: Handle typeless formats - gfxIsTypelessFormat(format) ? convertTypelessFormat(format) : format; - GFX_CHECK_CALL_ABORT(device->createTextureView(inTexture, texViewDesc, texView.writeRef())); - return texView; - } + auto rootObject = encoder->bindPipeline(pipelineState); - template <typename T> - ComPtr<IBufferResource> createBuffer(IDevice* device, int size, void* initialData) - { - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = size * sizeof(T); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(T); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> outBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - initialData, - outBuffer.writeRef())); - return outBuffer; - } + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - ComPtr<IResourceView> createOutBufferView(IDevice* device, ComPtr<IBufferResource> outBuffer) - { - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(outBuffer, nullptr, viewDesc, bufferView.writeRef())); - return bufferView; + auto& desc = *tex->getDesc(); + entryPointCursor["width"].setData(desc.size.width); + entryPointCursor["height"].setData(desc.size.height); + + // Bind texture view to the entry point + entryPointCursor["tex"].setResource(texView); + + if (sampler) + entryPointCursor["sampler"].setSampler(sampler); + + // Bind buffer view to the entry point. + entryPointCursor["buffer"].setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } +} + +ComPtr<ITextureResource> createTexture( + IDevice* device, + ITextureResource::Extents extents, + gfx::Format format, + ITextureResource::SubresourceData* initialData) +{ + ITextureResource::Desc texDesc = {}; + texDesc.type = IResource::Type::Texture2D; + texDesc.numMipLevels = 1; + texDesc.arraySize = 1; + texDesc.size = extents; + texDesc.defaultState = ResourceState::UnorderedAccess; + texDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + texDesc.format = format; + texDesc.isShared = true; + + ComPtr<ITextureResource> inTex; + GFX_CHECK_CALL_ABORT(device->createTextureResource(texDesc, initialData, inTex.writeRef())); + return inTex; +} + +ComPtr<IResourceView> createTexView(IDevice* device, ComPtr<ITextureResource> inTexture) +{ + ComPtr<IResourceView> texView; + IResourceView::Desc texViewDesc = {}; + texViewDesc.type = IResourceView::Type::UnorderedAccess; + texViewDesc.format = + inTexture->getDesc()->format; // TODO: Handle typeless formats - gfxIsTypelessFormat(format) + // ? convertTypelessFormat(format) : format; + GFX_CHECK_CALL_ABORT(device->createTextureView(inTexture, texViewDesc, texView.writeRef())); + return texView; +} + +template<typename T> +ComPtr<IBufferResource> createBuffer(IDevice* device, int size, void* initialData) +{ + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = size * sizeof(T); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(T); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> outBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, initialData, outBuffer.writeRef())); + return outBuffer; +} + +ComPtr<IResourceView> createOutBufferView(IDevice* device, ComPtr<IBufferResource> outBuffer) +{ + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(outBuffer, nullptr, viewDesc, bufferView.writeRef())); + return bufferView; +} + +void sharedTextureTestImpl(IDevice* srcDevice, IDevice* dstDevice, UnitTestContext* context) +{ + ISamplerState::Desc samplerDesc; + auto sampler = dstDevice->createSamplerState(samplerDesc); + + float initFloatData[16] = {0.0f}; + auto floatResults = createBuffer<float>(dstDevice, 16, initFloatData); + auto floatBufferView = createOutBufferView(dstDevice, floatResults); + + uint32_t initUintData[16] = {0u}; + auto uintResults = createBuffer<uint32_t>(dstDevice, 16, initUintData); + auto uintBufferView = createOutBufferView(dstDevice, uintResults); + + int32_t initIntData[16] = {0}; + auto intResults = createBuffer<uint32_t>(dstDevice, 16, initIntData); + auto intBufferView = createOutBufferView(dstDevice, intResults); + + ITextureResource::Extents size = {}; + size.width = 2; + size.height = 2; + size.depth = 1; + + ITextureResource::Extents bcSize = {}; + bcSize.width = 4; + bcSize.height = 4; + bcSize.depth = 1; - void sharedTextureTestImpl(IDevice* srcDevice, IDevice* dstDevice, UnitTestContext* context) { - ISamplerState::Desc samplerDesc; - auto sampler = dstDevice->createSamplerState(samplerDesc); - - float initFloatData[16] = { 0.0f }; - auto floatResults = createBuffer<float>(dstDevice, 16, initFloatData); - auto floatBufferView = createOutBufferView(dstDevice, floatResults); - - uint32_t initUintData[16] = { 0u }; - auto uintResults = createBuffer<uint32_t>(dstDevice, 16, initUintData); - auto uintBufferView = createOutBufferView(dstDevice, uintResults); - - int32_t initIntData[16] = { 0 }; - auto intResults = createBuffer<uint32_t>(dstDevice, 16, initIntData); - auto intBufferView = createOutBufferView(dstDevice, intResults); - - ITextureResource::Extents size = {}; - size.width = 2; - size.height = 2; - size.depth = 1; - - ITextureResource::Extents bcSize = {}; - bcSize.width = 4; - bcSize.height = 4; - bcSize.depth = 1; - - { - float texData[] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f }; - ITextureResource::SubresourceData subData = { (void*)texData, 32, 0 }; - - // Create a shareable texture using srcDevice, get its handle, then create a texture using the handle using - // dstDevice. Read back the texture and check that its contents are correct. - auto srcTexture = createTexture(srcDevice, size, gfx::Format::R32G32B32A32_FLOAT, &subData); - - InteropHandle sharedHandle; - GFX_CHECK_CALL_ABORT(srcTexture->getSharedHandle(&sharedHandle)); - ComPtr<ITextureResource> dstTexture; - size_t sizeInBytes = 0; - size_t alignment = 0; - GFX_CHECK_CALL_ABORT(srcDevice->getTextureAllocationInfo(*(srcTexture->getDesc()), &sizeInBytes, &alignment)); - GFX_CHECK_CALL_ABORT(dstDevice->createTextureFromSharedHandle(sharedHandle, *(srcTexture->getDesc()), sizeInBytes, dstTexture.writeRef())); - // Reading back the buffer from srcDevice to make sure it's been filled in before reading anything back from dstDevice - // TODO: Implement actual synchronization (and not this hacky solution) - compareComputeResult( - dstDevice, - dstTexture, - ResourceState::ShaderResource, - texData, - 32, - 2); - - auto texView = createTexView(dstDevice, dstTexture); - setUpAndRunShader(dstDevice, dstTexture, texView, floatBufferView, "copyTexFloat4"); - compareComputeResult( - dstDevice, - floatResults, - Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f)); - } + float texData[] = { + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.5f, + 0.5f, + 0.5f, + 1.0f}; + ITextureResource::SubresourceData subData = {(void*)texData, 32, 0}; + + // Create a shareable texture using srcDevice, get its handle, then create a texture using + // the handle using dstDevice. Read back the texture and check that its contents are + // correct. + auto srcTexture = createTexture(srcDevice, size, gfx::Format::R32G32B32A32_FLOAT, &subData); + + InteropHandle sharedHandle; + GFX_CHECK_CALL_ABORT(srcTexture->getSharedHandle(&sharedHandle)); + ComPtr<ITextureResource> dstTexture; + size_t sizeInBytes = 0; + size_t alignment = 0; + GFX_CHECK_CALL_ABORT(srcDevice->getTextureAllocationInfo( + *(srcTexture->getDesc()), + &sizeInBytes, + &alignment)); + GFX_CHECK_CALL_ABORT(dstDevice->createTextureFromSharedHandle( + sharedHandle, + *(srcTexture->getDesc()), + sizeInBytes, + dstTexture.writeRef())); + // Reading back the buffer from srcDevice to make sure it's been filled in before reading + // anything back from dstDevice + // TODO: Implement actual synchronization (and not this hacky solution) + compareComputeResult(dstDevice, dstTexture, ResourceState::ShaderResource, texData, 32, 2); + + auto texView = createTexView(dstDevice, dstTexture); + setUpAndRunShader(dstDevice, dstTexture, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + dstDevice, + floatResults, + Slang::makeArray<float>( + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f, + 1.0f, + 0.5f, + 0.5f, + 0.5f, + 1.0f)); } +} - void sharedTextureTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum srcApi, Slang::RenderApiFlag::Enum dstApi) +void sharedTextureTestAPI( + UnitTestContext* context, + Slang::RenderApiFlag::Enum srcApi, + Slang::RenderApiFlag::Enum dstApi) +{ + auto srcDevice = createTestingDevice(context, srcApi); + auto dstDevice = createTestingDevice(context, dstApi); + if (!srcDevice || !dstDevice) { - auto srcDevice = createTestingDevice(context, srcApi); - auto dstDevice = createTestingDevice(context, dstApi); - if (!srcDevice || !dstDevice) - { - SLANG_IGNORE_TEST; - } - - sharedTextureTestImpl(srcDevice, dstDevice, context); + SLANG_IGNORE_TEST; } + + sharedTextureTestImpl(srcDevice, dstDevice, context); +} #if SLANG_WIN64 - SLANG_UNIT_TEST(sharedTextureD3D12ToCUDA) - { - sharedTextureTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12, Slang::RenderApiFlag::CUDA); - } +SLANG_UNIT_TEST(sharedTextureD3D12ToCUDA) +{ + sharedTextureTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12, Slang::RenderApiFlag::CUDA); +} - SLANG_UNIT_TEST(sharedTextureVulkanToCUDA) - { - sharedTextureTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan, Slang::RenderApiFlag::CUDA); - } -#endif +SLANG_UNIT_TEST(sharedTextureVulkanToCUDA) +{ + sharedTextureTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan, Slang::RenderApiFlag::CUDA); } +#endif +} // namespace gfx_test diff --git a/tools/gfx-unit-test/swap-chain-resize-test.cpp b/tools/gfx-unit-test/swap-chain-resize-test.cpp index 2be690077..269f08735 100644 --- a/tools/gfx-unit-test/swap-chain-resize-test.cpp +++ b/tools/gfx-unit-test/swap-chain-resize-test.cpp @@ -1,242 +1,249 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" +#include "slang-gfx.h" +#include "source/core/slang-basic.h" #include "tools/gfx-util/shader-cursor.h" #include "tools/platform/window.h" -#include "source/core/slang-basic.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; using namespace Slang; namespace gfx_test { - struct Vertex - { - float position[3]; - }; - - static const int kVertexCount = 3; - static const Vertex kVertexData[kVertexCount] = - { - // Triangle 1 - { 0, 0, 1 }, - { 4, 0, 1 }, - { 0, 4, 1 }, - }; - - struct SwapchainResizeTest - { - IDevice* device; - UnitTestContext* context; - - RefPtr<platform::Window> window; - ComPtr<ICommandQueue> queue; - ComPtr<ISwapchain> swapchain; +struct Vertex +{ + float position[3]; +}; + +static const int kVertexCount = 3; +static const Vertex kVertexData[kVertexCount] = { + // Triangle 1 + {0, 0, 1}, + {4, 0, 1}, + {0, 4, 1}, +}; + +struct SwapchainResizeTest +{ + IDevice* device; + UnitTestContext* context; - ComPtr<ITransientResourceHeap> transientHeap; - ComPtr<gfx::IFramebufferLayout> framebufferLayout; - ComPtr<IPipelineState> pipelineState; - ComPtr<IRenderPassLayout> renderPass; - List<ComPtr<IFramebuffer>> framebuffers; + RefPtr<platform::Window> window; + ComPtr<ICommandQueue> queue; + ComPtr<ISwapchain> swapchain; - ComPtr<IBufferResource> vertexBuffer; + ComPtr<ITransientResourceHeap> transientHeap; + ComPtr<gfx::IFramebufferLayout> framebufferLayout; + ComPtr<IPipelineState> pipelineState; + ComPtr<IRenderPassLayout> renderPass; + List<ComPtr<IFramebuffer>> framebuffers; - GfxCount width = 500; - GfxCount height = 500; - static const int kSwapchainImageCount = 2; - const Format desiredFormat = Format::R8G8B8A8_UNORM; + ComPtr<IBufferResource> vertexBuffer; - void init(IDevice* device, UnitTestContext* context) - { - this->device = device; - this->context = context; - } + GfxCount width = 500; + GfxCount height = 500; + static const int kSwapchainImageCount = 2; + const Format desiredFormat = Format::R8G8B8A8_UNORM; - void createSwapchainFramebuffers() - { - framebuffers.clear(); - for (GfxIndex i = 0; i < kSwapchainImageCount; ++i) - { - ComPtr<ITextureResource> colorBuffer; - swapchain->getImage(i, colorBuffer.writeRef()); - - gfx::IResourceView::Desc colorBufferViewDesc; - memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); - colorBufferViewDesc.format = swapchain->getDesc().format; - colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; - colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; - auto rtv = device->createTextureView(colorBuffer.get(), colorBufferViewDesc); - - gfx::IFramebuffer::Desc framebufferDesc; - framebufferDesc.renderTargetCount = 1; - framebufferDesc.depthStencilView = nullptr; - framebufferDesc.renderTargetViews = rtv.readRef(); - framebufferDesc.layout = framebufferLayout; - ComPtr<IFramebuffer> framebuffer; - GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); - - framebuffers.add(framebuffer); - } - } + void init(IDevice* device, UnitTestContext* context) + { + this->device = device; + this->context = context; + } - void createRequiredResources() + void createSwapchainFramebuffers() + { + framebuffers.clear(); + for (GfxIndex i = 0; i < kSwapchainImageCount; ++i) { - platform::Application::init(); - - platform::WindowDesc windowDesc; - windowDesc.title = ""; - windowDesc.width = width; - windowDesc.height = height; - windowDesc.style = platform::WindowStyle::Default; - window = platform::Application::createWindow(windowDesc); - - ICommandQueue::Desc queueDesc = {}; - queueDesc.type = ICommandQueue::QueueType::Graphics; - queue = device->createCommandQueue(queueDesc); - - ISwapchain::Desc swapchainDesc = {}; - swapchainDesc.format = desiredFormat; - swapchainDesc.width = width; - swapchainDesc.height = height; - swapchainDesc.imageCount = kSwapchainImageCount; - swapchainDesc.queue = queue; - WindowHandle windowHandle = window->getNativeHandle().convert<WindowHandle>(); - auto createSwapchainResult = device->createSwapchain(swapchainDesc, windowHandle, swapchain.writeRef()); - if (SLANG_FAILED(createSwapchainResult)) - { - SLANG_IGNORE_TEST; - } - - VertexStreamDesc vertexStreams[] = { - { sizeof(Vertex), InputSlotClass::PerVertex, 0 }, - }; - - InputElementDesc inputElements[] = { - // Vertex buffer data - { "POSITIONA", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0 }, - }; - IInputLayout::Desc inputLayoutDesc = {}; - inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); - inputLayoutDesc.inputElements = inputElements; - inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); - inputLayoutDesc.vertexStreams = vertexStreams; - auto inputLayout = device->createInputLayout(inputLayoutDesc); - SLANG_CHECK_ABORT(inputLayout != nullptr); - - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); - SLANG_CHECK_ABORT(vertexBuffer != nullptr); - - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096 * 1024; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadGraphicsProgram(device, shaderProgram, "swapchain-shader", "vertexMain", "fragmentMain", slangReflection)); - - IFramebufferLayout::TargetLayout targetLayout; - targetLayout.format = swapchain->getDesc().format; - targetLayout.sampleCount = 1; - - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &targetLayout; - framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc); - SLANG_CHECK_ABORT(framebufferLayout != nullptr); - - GraphicsPipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - pipelineDesc.inputLayout = inputLayout; - pipelineDesc.framebufferLayout = framebufferLayout; - pipelineDesc.depthStencil.depthTestEnable = false; - pipelineDesc.depthStencil.depthWriteEnable = false; + ComPtr<ITextureResource> colorBuffer; + swapchain->getImage(i, colorBuffer.writeRef()); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = swapchain->getDesc().format; + colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; + auto rtv = device->createTextureView(colorBuffer.get(), colorBufferViewDesc); + + gfx::IFramebuffer::Desc framebufferDesc; + framebufferDesc.renderTargetCount = 1; + framebufferDesc.depthStencilView = nullptr; + framebufferDesc.renderTargetViews = rtv.readRef(); + framebufferDesc.layout = framebufferLayout; + ComPtr<IFramebuffer> framebuffer; GFX_CHECK_CALL_ABORT( - device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); - - IRenderPassLayout::Desc renderPassDesc = {}; - renderPassDesc.framebufferLayout = framebufferLayout; - renderPassDesc.renderTargetCount = 1; - IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; - renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; - renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; - renderTargetAccess.initialState = ResourceState::Undefined; - renderTargetAccess.finalState = ResourceState::Present; - renderPassDesc.renderTargetAccess = &renderTargetAccess; - GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); - - createSwapchainFramebuffers(); - } + device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); - void renderFrame(GfxIndex framebufferIndex) - { - auto commandBuffer = transientHeap->createCommandBuffer(); - - auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffers[framebufferIndex]); - auto rootObject = encoder->bindPipeline(pipelineState); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)width; - viewport.extentY = (float)height; - encoder->setViewportAndScissor(viewport); - - encoder->setVertexBuffer(0, vertexBuffer); - encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - - swapchain->acquireNextImage(); - encoder->draw(kVertexCount); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - swapchain->present(); + framebuffers.add(framebuffer); } + } - void run() + void createRequiredResources() + { + platform::Application::init(); + + platform::WindowDesc windowDesc; + windowDesc.title = ""; + windowDesc.width = width; + windowDesc.height = height; + windowDesc.style = platform::WindowStyle::Default; + window = platform::Application::createWindow(windowDesc); + + ICommandQueue::Desc queueDesc = {}; + queueDesc.type = ICommandQueue::QueueType::Graphics; + queue = device->createCommandQueue(queueDesc); + + ISwapchain::Desc swapchainDesc = {}; + swapchainDesc.format = desiredFormat; + swapchainDesc.width = width; + swapchainDesc.height = height; + swapchainDesc.imageCount = kSwapchainImageCount; + swapchainDesc.queue = queue; + WindowHandle windowHandle = window->getNativeHandle().convert<WindowHandle>(); + auto createSwapchainResult = + device->createSwapchain(swapchainDesc, windowHandle, swapchain.writeRef()); + if (SLANG_FAILED(createSwapchainResult)) { - createRequiredResources(); - // Render for 5 frames then resize the swapchain and render for another 5 frames to ensure the - // swapchain remains usable after resizing. - for (GfxIndex i = 0; i < 5; ++i) - { - renderFrame(i % kSwapchainImageCount); - } - queue->waitOnHost(); - - framebuffers = decltype(framebuffers)(); - GFX_CHECK_CALL(swapchain->resize(700, 700)); - createSwapchainFramebuffers(); - width = 700; - height = 700; - - for (GfxIndex i = 0; i < 5; ++i) - { - renderFrame(i % kSwapchainImageCount); - } - queue->waitOnHost(); + SLANG_IGNORE_TEST; } - }; - void swapchainResizeTestImpl(IDevice* device, UnitTestContext* context) - { - SwapchainResizeTest t; - t.init(device, context); - t.run(); + VertexStreamDesc vertexStreams[] = { + {sizeof(Vertex), InputSlotClass::PerVertex, 0}, + }; + + InputElementDesc inputElements[] = { + // Vertex buffer data + {"POSITIONA", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0}, + }; + IInputLayout::Desc inputLayoutDesc = {}; + inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); + inputLayoutDesc.inputElements = inputElements; + inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); + inputLayoutDesc.vertexStreams = vertexStreams; + auto inputLayout = device->createInputLayout(inputLayoutDesc); + SLANG_CHECK_ABORT(inputLayout != nullptr); + + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); + SLANG_CHECK_ABORT(vertexBuffer != nullptr); + + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096 * 1024; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadGraphicsProgram( + device, + shaderProgram, + "swapchain-shader", + "vertexMain", + "fragmentMain", + slangReflection)); + + IFramebufferLayout::TargetLayout targetLayout; + targetLayout.format = swapchain->getDesc().format; + targetLayout.sampleCount = 1; + + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &targetLayout; + framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc); + SLANG_CHECK_ABORT(framebufferLayout != nullptr); + + GraphicsPipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + pipelineDesc.inputLayout = inputLayout; + pipelineDesc.framebufferLayout = framebufferLayout; + pipelineDesc.depthStencil.depthTestEnable = false; + pipelineDesc.depthStencil.depthWriteEnable = false; + GFX_CHECK_CALL_ABORT( + device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); + + IRenderPassLayout::Desc renderPassDesc = {}; + renderPassDesc.framebufferLayout = framebufferLayout; + renderPassDesc.renderTargetCount = 1; + IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; + renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; + renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; + renderTargetAccess.initialState = ResourceState::Undefined; + renderTargetAccess.finalState = ResourceState::Present; + renderPassDesc.renderTargetAccess = &renderTargetAccess; + GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); + + createSwapchainFramebuffers(); } - SLANG_UNIT_TEST(swapchainResizeD3D12) + void renderFrame(GfxIndex framebufferIndex) { - runTestImpl(swapchainResizeTestImpl, unitTestContext, RenderApiFlag::D3D12); + auto commandBuffer = transientHeap->createCommandBuffer(); + + auto encoder = + commandBuffer->encodeRenderCommands(renderPass, framebuffers[framebufferIndex]); + auto rootObject = encoder->bindPipeline(pipelineState); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)width; + viewport.extentY = (float)height; + encoder->setViewportAndScissor(viewport); + + encoder->setVertexBuffer(0, vertexBuffer); + encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + + swapchain->acquireNextImage(); + encoder->draw(kVertexCount); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + swapchain->present(); } - SLANG_UNIT_TEST(swapchainResizeVulkan) + void run() { - runTestImpl(swapchainResizeTestImpl, unitTestContext, RenderApiFlag::Vulkan); + createRequiredResources(); + // Render for 5 frames then resize the swapchain and render for another 5 frames to ensure + // the swapchain remains usable after resizing. + for (GfxIndex i = 0; i < 5; ++i) + { + renderFrame(i % kSwapchainImageCount); + } + queue->waitOnHost(); + + framebuffers = decltype(framebuffers)(); + GFX_CHECK_CALL(swapchain->resize(700, 700)); + createSwapchainFramebuffers(); + width = 700; + height = 700; + + for (GfxIndex i = 0; i < 5; ++i) + { + renderFrame(i % kSwapchainImageCount); + } + queue->waitOnHost(); } +}; + +void swapchainResizeTestImpl(IDevice* device, UnitTestContext* context) +{ + SwapchainResizeTest t; + t.init(device, context); + t.run(); +} +SLANG_UNIT_TEST(swapchainResizeD3D12) +{ + runTestImpl(swapchainResizeTestImpl, unitTestContext, RenderApiFlag::D3D12); } + +SLANG_UNIT_TEST(swapchainResizeVulkan) +{ + runTestImpl(swapchainResizeTestImpl, unitTestContext, RenderApiFlag::Vulkan); +} + +} // namespace gfx_test diff --git a/tools/gfx-unit-test/texture-types-tests.cpp b/tools/gfx-unit-test/texture-types-tests.cpp index 7f010e6fd..0aa082a1e 100644 --- a/tools/gfx-unit-test/texture-types-tests.cpp +++ b/tools/gfx-unit-test/texture-types-tests.cpp @@ -1,10 +1,9 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" -#include "gfx-test-util.h" #include "gfx-test-texture-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "gfx-test-util.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" #if SLANG_WINDOWS_FAMILY #include <d3d12.h> @@ -15,654 +14,688 @@ using namespace gfx; namespace gfx_test { - struct BaseTextureViewTest - { - IDevice* device; - UnitTestContext* context; +struct BaseTextureViewTest +{ + IDevice* device; + UnitTestContext* context; - IResourceView::Type viewType; - size_t alignedRowStride; + IResourceView::Type viewType; + size_t alignedRowStride; - RefPtr<TextureInfo> textureInfo; - RefPtr<ValidationTextureFormatBase> validationFormat; + RefPtr<TextureInfo> textureInfo; + RefPtr<ValidationTextureFormatBase> validationFormat; - ComPtr<ITextureResource> texture; - ComPtr<IResourceView> textureView; - ComPtr<IBufferResource> resultsBuffer; - ComPtr<IResourceView> bufferView; + ComPtr<ITextureResource> texture; + ComPtr<IResourceView> textureView; + ComPtr<IBufferResource> resultsBuffer; + ComPtr<IResourceView> bufferView; - ComPtr<ISamplerState> sampler; + ComPtr<ISamplerState> sampler; - const void* expectedTextureData; + const void* expectedTextureData; - void init( - IDevice* device, - UnitTestContext* context, - Format format, - RefPtr<ValidationTextureFormatBase> validationFormat, - IResourceView::Type viewType, - IResource::Type type) + void init( + IDevice* device, + UnitTestContext* context, + Format format, + RefPtr<ValidationTextureFormatBase> validationFormat, + IResourceView::Type viewType, + IResource::Type type) + { + this->device = device; + this->context = context; + this->validationFormat = validationFormat; + this->viewType = viewType; + + this->textureInfo = new TextureInfo(); + this->textureInfo->format = format; + this->textureInfo->textureType = type; + } + + ResourceState getDefaultResourceStateForViewType(IResourceView::Type type) + { + switch (type) { - this->device = device; - this->context = context; - this->validationFormat = validationFormat; - this->viewType = viewType; - - this->textureInfo = new TextureInfo(); - this->textureInfo->format = format; - this->textureInfo->textureType = type; + case IResourceView::Type::RenderTarget: return ResourceState::RenderTarget; + case IResourceView::Type::DepthStencil: return ResourceState::DepthWrite; + case IResourceView::Type::ShaderResource: return ResourceState::ShaderResource; + case IResourceView::Type::UnorderedAccess: return ResourceState::UnorderedAccess; + case IResourceView::Type::AccelerationStructure: + return ResourceState::AccelerationStructure; + default: return ResourceState::Undefined; } + } + + String getShaderEntryPoint() + { + String base = "resourceViewTest"; + String shape; + String view; - ResourceState getDefaultResourceStateForViewType(IResourceView::Type type) + switch (textureInfo->textureType) { - switch (type) - { - case IResourceView::Type::RenderTarget: - return ResourceState::RenderTarget; - case IResourceView::Type::DepthStencil: - return ResourceState::DepthWrite; - case IResourceView::Type::ShaderResource: - return ResourceState::ShaderResource; - case IResourceView::Type::UnorderedAccess: - return ResourceState::UnorderedAccess; - case IResourceView::Type::AccelerationStructure: - return ResourceState::AccelerationStructure; - default: - return ResourceState::Undefined; - } + case IResource::Type::Texture1D: shape = "1D"; break; + case IResource::Type::Texture2D: shape = "2D"; break; + case IResource::Type::Texture3D: shape = "3D"; break; + case IResource::Type::TextureCube: shape = "Cube"; break; + default: assert(!"Invalid texture shape"); SLANG_CHECK_ABORT(false); } - String getShaderEntryPoint() + switch (viewType) { - String base = "resourceViewTest"; - String shape; - String view; - - switch (textureInfo->textureType) - { - case IResource::Type::Texture1D: - shape = "1D"; - break; - case IResource::Type::Texture2D: - shape = "2D"; - break; - case IResource::Type::Texture3D: - shape = "3D"; - break; - case IResource::Type::TextureCube: - shape = "Cube"; - break; - default: - assert(!"Invalid texture shape"); - SLANG_CHECK_ABORT(false); - } - - switch (viewType) - { - case IResourceView::Type::RenderTarget: - view = "Render"; - break; - case IResourceView::Type::DepthStencil: - view = "Depth"; - break; - case IResourceView::Type::ShaderResource: - view = "Shader"; - break; - case IResourceView::Type::UnorderedAccess: - view = "Unordered"; - break; - case IResourceView::Type::AccelerationStructure: - view = "Accel"; - break; - default: - assert(!"Invalid resource view"); - SLANG_CHECK_ABORT(false); - } - - return base + shape + view; + case IResourceView::Type::RenderTarget: view = "Render"; break; + case IResourceView::Type::DepthStencil: view = "Depth"; break; + case IResourceView::Type::ShaderResource: view = "Shader"; break; + case IResourceView::Type::UnorderedAccess: view = "Unordered"; break; + case IResourceView::Type::AccelerationStructure: view = "Accel"; break; + default: assert(!"Invalid resource view"); SLANG_CHECK_ABORT(false); } - - }; + return base + shape + view; + } +}; - // used for shaderresource and unorderedaccess - struct ShaderAndUnorderedTests : BaseTextureViewTest +// used for shaderresource and unorderedaccess +struct ShaderAndUnorderedTests : BaseTextureViewTest +{ + void createRequiredResources() { - void createRequiredResources() - { - ITextureResource::Desc textureDesc = {}; - textureDesc.type = textureInfo->textureType; - textureDesc.numMipLevels = textureInfo->mipLevelCount; - textureDesc.arraySize = textureInfo->arrayLayerCount; - textureDesc.size = textureInfo->extents; - textureDesc.defaultState = getDefaultResourceStateForViewType(viewType); - textureDesc.allowedStates = ResourceStateSet( - textureDesc.defaultState, - ResourceState::CopySource, - ResourceState::CopyDestination); - textureDesc.format = textureInfo->format; - - GFX_CHECK_CALL_ABORT(device->createTextureResource( - textureDesc, - textureInfo->subresourceDatas.getBuffer(), - texture.writeRef())); - - IResourceView::Desc textureViewDesc = {}; - textureViewDesc.type = viewType; - textureViewDesc.format = textureDesc.format; // TODO: Handle typeless formats - gfxIsTypelessFormat(format) ? convertTypelessFormat(format) : format; - GFX_CHECK_CALL_ABORT(device->createTextureView(texture, textureViewDesc, textureView.writeRef())); - - auto texelSize = getTexelSize(textureInfo->format); - size_t alignment; - device->getTextureRowAlignment(&alignment); - alignedRowStride = (textureInfo->extents.width * texelSize + alignment - 1) & ~(alignment - 1); - IBufferResource::Desc bufferDesc = {}; - // All of the values read back from the shader will be uint32_t - bufferDesc.sizeInBytes = textureDesc.size.width * textureDesc.size.height * textureDesc.size.depth * texelSize * sizeof(uint32_t); - bufferDesc.format = Format::Unknown; - bufferDesc.elementSize = sizeof(uint32_t); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.allowedStates = ResourceStateSet( - bufferDesc.defaultState, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.memoryType = MemoryType::DeviceLocal; - - GFX_CHECK_CALL_ABORT(device->createBufferResource(bufferDesc, nullptr, resultsBuffer.writeRef())); - - IResourceView::Desc bufferViewDesc = {}; - bufferViewDesc.type = IResourceView::Type::UnorderedAccess; - bufferViewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT(device->createBufferView(resultsBuffer, nullptr, bufferViewDesc, bufferView.writeRef())); - } + ITextureResource::Desc textureDesc = {}; + textureDesc.type = textureInfo->textureType; + textureDesc.numMipLevels = textureInfo->mipLevelCount; + textureDesc.arraySize = textureInfo->arrayLayerCount; + textureDesc.size = textureInfo->extents; + textureDesc.defaultState = getDefaultResourceStateForViewType(viewType); + textureDesc.allowedStates = ResourceStateSet( + textureDesc.defaultState, + ResourceState::CopySource, + ResourceState::CopyDestination); + textureDesc.format = textureInfo->format; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + textureDesc, + textureInfo->subresourceDatas.getBuffer(), + texture.writeRef())); + + IResourceView::Desc textureViewDesc = {}; + textureViewDesc.type = viewType; + textureViewDesc.format = + textureDesc.format; // TODO: Handle typeless formats - gfxIsTypelessFormat(format) ? + // convertTypelessFormat(format) : format; + GFX_CHECK_CALL_ABORT( + device->createTextureView(texture, textureViewDesc, textureView.writeRef())); + + auto texelSize = getTexelSize(textureInfo->format); + size_t alignment; + device->getTextureRowAlignment(&alignment); + alignedRowStride = + (textureInfo->extents.width * texelSize + alignment - 1) & ~(alignment - 1); + IBufferResource::Desc bufferDesc = {}; + // All of the values read back from the shader will be uint32_t + bufferDesc.sizeInBytes = textureDesc.size.width * textureDesc.size.height * + textureDesc.size.depth * texelSize * sizeof(uint32_t); + bufferDesc.format = Format::Unknown; + bufferDesc.elementSize = sizeof(uint32_t); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.allowedStates = ResourceStateSet( + bufferDesc.defaultState, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.memoryType = MemoryType::DeviceLocal; + + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, nullptr, resultsBuffer.writeRef())); + + IResourceView::Desc bufferViewDesc = {}; + bufferViewDesc.type = IResourceView::Type::UnorderedAccess; + bufferViewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT(device->createBufferView( + resultsBuffer, + nullptr, + bufferViewDesc, + bufferView.writeRef())); + } - void submitShaderWork(const char* entryPoint) + void submitShaderWork(const char* entryPoint) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram( + device, + shaderProgram, + "trivial-copy-textures", + entryPoint, + slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "trivial-copy-textures", entryPoint, slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - auto rootObject = encoder->bindPipeline(pipelineState); + auto rootObject = encoder->bindPipeline(pipelineState); - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - auto width = textureInfo->extents.width; - auto height = textureInfo->extents.height; - auto depth = textureInfo->extents.depth; + auto width = textureInfo->extents.width; + auto height = textureInfo->extents.height; + auto depth = textureInfo->extents.depth; - entryPointCursor["width"].setData(width); - entryPointCursor["height"].setData(height); - entryPointCursor["depth"].setData(depth); + entryPointCursor["width"].setData(width); + entryPointCursor["height"].setData(height); + entryPointCursor["depth"].setData(depth); - // Bind texture view to the entry point - entryPointCursor["resourceView"].setResource(textureView); // TODO: Bind nullptr and make sure it doesn't splut - should be 0 everywhere - entryPointCursor["testResults"].setResource(bufferView); + // Bind texture view to the entry point + entryPointCursor["resourceView"].setResource( + textureView); // TODO: Bind nullptr and make sure it doesn't splut - should be 0 + // everywhere + entryPointCursor["testResults"].setResource(bufferView); - if (sampler) entryPointCursor["sampler"].setSampler(sampler); // TODO: Bind nullptr and make sure it doesn't splut + if (sampler) + entryPointCursor["sampler"].setSampler( + sampler); // TODO: Bind nullptr and make sure it doesn't splut - auto bufferElementCount = width * height * depth; - encoder->dispatchCompute(bufferElementCount, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } + auto bufferElementCount = width * height * depth; + encoder->dispatchCompute(bufferElementCount, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + } - void validateTextureValues(ValidationTextureData actual, ValidationTextureData original) + void validateTextureValues(ValidationTextureData actual, ValidationTextureData original) + { + // TODO: needs to be extended to cover mip levels and array layers + for (GfxIndex x = 0; x < actual.extents.width; ++x) { - // TODO: needs to be extended to cover mip levels and array layers - for (GfxIndex x = 0; x < actual.extents.width; ++x) + for (GfxIndex y = 0; y < actual.extents.height; ++y) { - for (GfxIndex y = 0; y < actual.extents.height; ++y) + for (GfxIndex z = 0; z < actual.extents.depth; ++z) { - for (GfxIndex z = 0; z < actual.extents.depth; ++z) + auto actualBlock = (uint8_t*)actual.getBlockAt(x, y, z); + for (Int i = 0; i < 4; ++i) { - auto actualBlock = (uint8_t*)actual.getBlockAt(x, y, z); - for (Int i = 0; i < 4; ++i) - { - SLANG_CHECK(actualBlock[i] == 1); - } + SLANG_CHECK(actualBlock[i] == 1); } } } } + } - void checkTestResults() + void checkTestResults() + { + // Shader resources are read-only, so we don't need to check that writes to the resource + // were correct. + if (viewType != IResourceView::Type::ShaderResource) { - // Shader resources are read-only, so we don't need to check that writes to the resource were correct. - if (viewType != IResourceView::Type::ShaderResource) - { - ComPtr<ISlangBlob> textureBlob; - size_t rowPitch; - size_t pixelSize; - GFX_CHECK_CALL_ABORT(device->readTextureResource(texture, ResourceState::CopySource, textureBlob.writeRef(), &rowPitch, &pixelSize)); - auto textureValues = (uint8_t*)textureBlob->getBufferPointer(); - - ValidationTextureData textureResults; - textureResults.extents = textureInfo->extents; - textureResults.textureData = textureValues; - textureResults.strides.x = (uint32_t)pixelSize; - textureResults.strides.y = (uint32_t)rowPitch; - textureResults.strides.z = textureResults.extents.height * textureResults.strides.y; - - ValidationTextureData originalData; - originalData.extents = textureInfo->extents; - originalData.textureData = textureInfo->subresourceDatas.getBuffer(); - originalData.strides.x = (uint32_t)pixelSize; - originalData.strides.y = textureInfo->extents.width * originalData.strides.x; - originalData.strides.z = textureInfo->extents.height * originalData.strides.y; - - validateTextureValues(textureResults, originalData); - } + ComPtr<ISlangBlob> textureBlob; + size_t rowPitch; + size_t pixelSize; + GFX_CHECK_CALL_ABORT(device->readTextureResource( + texture, + ResourceState::CopySource, + textureBlob.writeRef(), + &rowPitch, + &pixelSize)); + auto textureValues = (uint8_t*)textureBlob->getBufferPointer(); - ComPtr<ISlangBlob> bufferBlob; - GFX_CHECK_CALL_ABORT(device->readBufferResource(resultsBuffer, 0, resultsBuffer->getDesc()->sizeInBytes, bufferBlob.writeRef())); - auto results = (uint32_t*)bufferBlob->getBufferPointer(); + ValidationTextureData textureResults; + textureResults.extents = textureInfo->extents; + textureResults.textureData = textureValues; + textureResults.strides.x = (uint32_t)pixelSize; + textureResults.strides.y = (uint32_t)rowPitch; + textureResults.strides.z = textureResults.extents.height * textureResults.strides.y; - auto elementCount = textureInfo->extents.width * textureInfo->extents.height * textureInfo->extents.depth * 4; - auto castedTextureData = (uint8_t*)expectedTextureData; - for (Int i = 0; i < elementCount; ++i) - { - SLANG_CHECK(results[i] == castedTextureData[i]); - } + ValidationTextureData originalData; + originalData.extents = textureInfo->extents; + originalData.textureData = textureInfo->subresourceDatas.getBuffer(); + originalData.strides.x = (uint32_t)pixelSize; + originalData.strides.y = textureInfo->extents.width * originalData.strides.x; + originalData.strides.z = textureInfo->extents.height * originalData.strides.y; + + validateTextureValues(textureResults, originalData); } - void run() + ComPtr<ISlangBlob> bufferBlob; + GFX_CHECK_CALL_ABORT(device->readBufferResource( + resultsBuffer, + 0, + resultsBuffer->getDesc()->sizeInBytes, + bufferBlob.writeRef())); + auto results = (uint32_t*)bufferBlob->getBufferPointer(); + + auto elementCount = textureInfo->extents.width * textureInfo->extents.height * + textureInfo->extents.depth * 4; + auto castedTextureData = (uint8_t*)expectedTextureData; + for (Int i = 0; i < elementCount; ++i) { - // TODO: Should test with samplers -// ISamplerState::Desc samplerDesc; -// sampler = device->createSamplerState(samplerDesc); - - // TODO: Should test multiple mip levels and array layers - textureInfo->extents.width = 4; - textureInfo->extents.height = (textureInfo->textureType == IResource::Type::Texture1D) ? 1 : 4; - textureInfo->extents.depth = (textureInfo->textureType != IResource::Type::Texture3D) ? 1 : 2; - textureInfo->mipLevelCount = 1; - textureInfo->arrayLayerCount = 1; - generateTextureData(textureInfo, validationFormat); - - // We need to save the pointer to the original texture data for results checking because the texture will be - // overwritten during testing (if the texture can be written to). - expectedTextureData = textureInfo->subresourceDatas[getSubresourceIndex(0, 1, 0)].data; - - createRequiredResources(); - auto entryPointName = getShaderEntryPoint(); - //printf("%s\n", entryPointName.getBuffer()); - submitShaderWork(entryPointName.getBuffer()); - - checkTestResults(); + SLANG_CHECK(results[i] == castedTextureData[i]); } + } + + void run() + { + // TODO: Should test with samplers + // ISamplerState::Desc samplerDesc; + // sampler = device->createSamplerState(samplerDesc); + + // TODO: Should test multiple mip levels and array layers + textureInfo->extents.width = 4; + textureInfo->extents.height = + (textureInfo->textureType == IResource::Type::Texture1D) ? 1 : 4; + textureInfo->extents.depth = + (textureInfo->textureType != IResource::Type::Texture3D) ? 1 : 2; + textureInfo->mipLevelCount = 1; + textureInfo->arrayLayerCount = 1; + generateTextureData(textureInfo, validationFormat); + + // We need to save the pointer to the original texture data for results checking because the + // texture will be overwritten during testing (if the texture can be written to). + expectedTextureData = textureInfo->subresourceDatas[getSubresourceIndex(0, 1, 0)].data; + + createRequiredResources(); + auto entryPointName = getShaderEntryPoint(); + // printf("%s\n", entryPointName.getBuffer()); + submitShaderWork(entryPointName.getBuffer()); + + checkTestResults(); + } +}; + +// used for rendertarget and depthstencil +struct RenderTargetTests : BaseTextureViewTest +{ + struct Vertex + { + float position[3]; + float color[3]; }; - // used for rendertarget and depthstencil - struct RenderTargetTests : BaseTextureViewTest + const int kVertexCount = 12; + const Vertex kVertexData[12] = { + // Triangle 1 + {{0, 0, 0.5}, {1, 0, 0}}, + {{1, 1, 0.5}, {1, 0, 0}}, + {{-1, 1, 0.5}, {1, 0, 0}}, + + // Triangle 2 + {{-1, 1, 0.5}, {0, 1, 0}}, + {{0, 0, 0.5}, {0, 1, 0}}, + {{-1, -1, 0.5}, {0, 1, 0}}, + + // Triangle 3 + {{-1, -1, 0.5}, {0, 0, 1}}, + {{0, 0, 0.5}, {0, 0, 1}}, + {{1, -1, 0.5}, {0, 0, 1}}, + + // Triangle 4 + {{1, -1, 0.5}, {0, 0, 0}}, + {{0, 0, 0.5}, {0, 0, 0}}, + {{1, 1, 0.5}, {0, 0, 0}}, + }; + + int sampleCount = 1; + + ComPtr<ITransientResourceHeap> transientHeap; + ComPtr<IPipelineState> pipelineState; + ComPtr<IRenderPassLayout> renderPass; + ComPtr<IFramebuffer> framebuffer; + + ComPtr<ITextureResource> sampledTexture; + ComPtr<IBufferResource> vertexBuffer; + + void createRequiredResources() { - struct Vertex - { - float position[3]; - float color[3]; + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; + vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); + SLANG_CHECK_ABORT(vertexBuffer != nullptr); + + VertexStreamDesc vertexStreams[] = { + {sizeof(Vertex), InputSlotClass::PerVertex, 0}, }; - const int kVertexCount = 12; - const Vertex kVertexData[12] = - { - // Triangle 1 - { { 0, 0, 0.5 }, { 1, 0, 0 } }, - { { 1, 1, 0.5 }, { 1, 0, 0 } }, - { { -1, 1, 0.5 }, { 1, 0, 0 } }, - - // Triangle 2 - { { -1, 1, 0.5 }, { 0, 1, 0 } }, - { { 0, 0, 0.5 }, { 0, 1, 0 } }, - { { -1, -1, 0.5 }, { 0, 1, 0 } }, - - // Triangle 3 - { { -1, -1, 0.5 }, { 0, 0, 1 } }, - { { 0, 0, 0.5 }, { 0, 0, 1 } }, - { { 1, -1, 0.5 }, { 0, 0, 1 } }, - - // Triangle 4 - { { 1, -1, 0.5 }, { 0, 0, 0 } }, - { { 0, 0, 0.5 }, { 0, 0, 0 } }, - { { 1, 1, 0.5 }, { 0, 0, 0 } }, + InputElementDesc inputElements[] = { + // Vertex buffer data + {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0}, + {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color), 0}, }; - int sampleCount = 1; + ITextureResource::Desc sampledTexDesc = {}; + sampledTexDesc.type = textureInfo->textureType; + sampledTexDesc.numMipLevels = textureInfo->mipLevelCount; + sampledTexDesc.arraySize = textureInfo->arrayLayerCount; + sampledTexDesc.size = textureInfo->extents; + sampledTexDesc.defaultState = getDefaultResourceStateForViewType(viewType); + sampledTexDesc.allowedStates = ResourceStateSet( + sampledTexDesc.defaultState, + ResourceState::ResolveSource, + ResourceState::CopySource); + sampledTexDesc.format = textureInfo->format; + sampledTexDesc.sampleDesc.numSamples = sampleCount; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + sampledTexDesc, + textureInfo->subresourceDatas.getBuffer(), + sampledTexture.writeRef())); + + ITextureResource::Desc texDesc = {}; + texDesc.type = textureInfo->textureType; + texDesc.numMipLevels = textureInfo->mipLevelCount; + texDesc.arraySize = textureInfo->arrayLayerCount; + texDesc.size = textureInfo->extents; + texDesc.defaultState = ResourceState::ResolveDestination; + texDesc.allowedStates = + ResourceStateSet(ResourceState::ResolveDestination, ResourceState::CopySource); + texDesc.format = textureInfo->format; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + texDesc, + textureInfo->subresourceDatas.getBuffer(), + texture.writeRef())); + + IInputLayout::Desc inputLayoutDesc = {}; + inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); + inputLayoutDesc.inputElements = inputElements; + inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); + inputLayoutDesc.vertexStreams = vertexStreams; + auto inputLayout = device->createInputLayout(inputLayoutDesc); + SLANG_CHECK_ABORT(inputLayout != nullptr); + + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadGraphicsProgram( + device, + shaderProgram, + "trivial-copy-textures", + "vertexMain", + "fragmentMain", + slangReflection)); + + IFramebufferLayout::TargetLayout targetLayout; + targetLayout.format = textureInfo->format; + targetLayout.sampleCount = sampleCount; + + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &targetLayout; + ComPtr<gfx::IFramebufferLayout> framebufferLayout = + device->createFramebufferLayout(framebufferLayoutDesc); + SLANG_CHECK_ABORT(framebufferLayout != nullptr); + + GraphicsPipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + pipelineDesc.inputLayout = inputLayout; + pipelineDesc.framebufferLayout = framebufferLayout; + pipelineDesc.depthStencil.depthTestEnable = false; + pipelineDesc.depthStencil.depthWriteEnable = false; + GFX_CHECK_CALL_ABORT( + device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); + + IRenderPassLayout::Desc renderPassDesc = {}; + renderPassDesc.framebufferLayout = framebufferLayout; + renderPassDesc.renderTargetCount = 1; + IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; + renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; + renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; + renderTargetAccess.initialState = getDefaultResourceStateForViewType(viewType); + renderTargetAccess.finalState = ResourceState::ResolveSource; + renderPassDesc.renderTargetAccess = &renderTargetAccess; + GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = textureInfo->format; + colorBufferViewDesc.renderTarget.shape = textureInfo->textureType; // TODO: TextureCube? + colorBufferViewDesc.type = viewType; + auto rtv = device->createTextureView(sampledTexture, colorBufferViewDesc); + + gfx::IFramebuffer::Desc framebufferDesc; + framebufferDesc.renderTargetCount = 1; + framebufferDesc.depthStencilView = nullptr; + framebufferDesc.renderTargetViews = rtv.readRef(); + framebufferDesc.layout = framebufferLayout; + GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); + + auto texelSize = getTexelSize(textureInfo->format); + size_t alignment; + device->getTextureRowAlignment(&alignment); + alignedRowStride = + (textureInfo->extents.width * texelSize + alignment - 1) & ~(alignment - 1); + } + + void submitShaderWork(const char* entryPointName) + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto renderEncoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); + auto rootObject = renderEncoder->bindPipeline(pipelineState); - ComPtr<ITransientResourceHeap> transientHeap; - ComPtr<IPipelineState> pipelineState; - ComPtr<IRenderPassLayout> renderPass; - ComPtr<IFramebuffer> framebuffer; + gfx::Viewport viewport = {}; + viewport.maxZ = (float)textureInfo->extents.depth; + viewport.extentX = (float)textureInfo->extents.width; + viewport.extentY = (float)textureInfo->extents.height; + renderEncoder->setViewportAndScissor(viewport); - ComPtr<ITextureResource> sampledTexture; - ComPtr<IBufferResource> vertexBuffer; + renderEncoder->setVertexBuffer(0, vertexBuffer); + renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + renderEncoder->draw(kVertexCount, 0); + renderEncoder->endEncoding(); - void createRequiredResources() + auto resourceEncoder = commandBuffer->encodeResourceCommands(); + + if (sampleCount > 1) { - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; - vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); - SLANG_CHECK_ABORT(vertexBuffer != nullptr); - - VertexStreamDesc vertexStreams[] = { - { sizeof(Vertex), InputSlotClass::PerVertex, 0 }, - }; - - InputElementDesc inputElements[] = { - // Vertex buffer data - { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0 }, - { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color), 0 }, - }; - - ITextureResource::Desc sampledTexDesc = {}; - sampledTexDesc.type = textureInfo->textureType; - sampledTexDesc.numMipLevels = textureInfo->mipLevelCount; - sampledTexDesc.arraySize = textureInfo->arrayLayerCount; - sampledTexDesc.size = textureInfo->extents; - sampledTexDesc.defaultState = getDefaultResourceStateForViewType(viewType); - sampledTexDesc.allowedStates = ResourceStateSet( - sampledTexDesc.defaultState, + SubresourceRange msaaSubresource = {}; + msaaSubresource.aspectMask = TextureAspect::Color; + msaaSubresource.mipLevel = 0; + msaaSubresource.mipLevelCount = 1; + msaaSubresource.baseArrayLayer = 0; + msaaSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = TextureAspect::Color; + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + resourceEncoder->resolveResource( + sampledTexture, ResourceState::ResolveSource, - ResourceState::CopySource); - sampledTexDesc.format = textureInfo->format; - sampledTexDesc.sampleDesc.numSamples = sampleCount; - - GFX_CHECK_CALL_ABORT(device->createTextureResource( - sampledTexDesc, - textureInfo->subresourceDatas.getBuffer(), - sampledTexture.writeRef())); - - ITextureResource::Desc texDesc = {}; - texDesc.type = textureInfo->textureType; - texDesc.numMipLevels = textureInfo->mipLevelCount; - texDesc.arraySize = textureInfo->arrayLayerCount; - texDesc.size = textureInfo->extents; - texDesc.defaultState = ResourceState::ResolveDestination; - texDesc.allowedStates = ResourceStateSet( + msaaSubresource, + texture, + ResourceState::ResolveDestination, + dstSubresource); + resourceEncoder->textureBarrier( + texture, ResourceState::ResolveDestination, ResourceState::CopySource); - texDesc.format = textureInfo->format; - - GFX_CHECK_CALL_ABORT(device->createTextureResource( - texDesc, - textureInfo->subresourceDatas.getBuffer(), - texture.writeRef())); - - IInputLayout::Desc inputLayoutDesc = {}; - inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); - inputLayoutDesc.inputElements = inputElements; - inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); - inputLayoutDesc.vertexStreams = vertexStreams; - auto inputLayout = device->createInputLayout(inputLayoutDesc); - SLANG_CHECK_ABORT(inputLayout != nullptr); - - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadGraphicsProgram(device, shaderProgram, "trivial-copy-textures", "vertexMain", "fragmentMain", slangReflection)); - - IFramebufferLayout::TargetLayout targetLayout; - targetLayout.format = textureInfo->format; - targetLayout.sampleCount = sampleCount; - - IFramebufferLayout::Desc framebufferLayoutDesc; - framebufferLayoutDesc.renderTargetCount = 1; - framebufferLayoutDesc.renderTargets = &targetLayout; - ComPtr<gfx::IFramebufferLayout> framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc); - SLANG_CHECK_ABORT(framebufferLayout != nullptr); - - GraphicsPipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - pipelineDesc.inputLayout = inputLayout; - pipelineDesc.framebufferLayout = framebufferLayout; - pipelineDesc.depthStencil.depthTestEnable = false; - pipelineDesc.depthStencil.depthWriteEnable = false; - GFX_CHECK_CALL_ABORT( - device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); - - IRenderPassLayout::Desc renderPassDesc = {}; - renderPassDesc.framebufferLayout = framebufferLayout; - renderPassDesc.renderTargetCount = 1; - IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; - renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; - renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; - renderTargetAccess.initialState = getDefaultResourceStateForViewType(viewType); - renderTargetAccess.finalState = ResourceState::ResolveSource; - renderPassDesc.renderTargetAccess = &renderTargetAccess; - GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); - - gfx::IResourceView::Desc colorBufferViewDesc; - memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); - colorBufferViewDesc.format = textureInfo->format; - colorBufferViewDesc.renderTarget.shape = textureInfo->textureType; // TODO: TextureCube? - colorBufferViewDesc.type = viewType; - auto rtv = device->createTextureView(sampledTexture, colorBufferViewDesc); - - gfx::IFramebuffer::Desc framebufferDesc; - framebufferDesc.renderTargetCount = 1; - framebufferDesc.depthStencilView = nullptr; - framebufferDesc.renderTargetViews = rtv.readRef(); - framebufferDesc.layout = framebufferLayout; - GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); - - auto texelSize = getTexelSize(textureInfo->format); - size_t alignment; - device->getTextureRowAlignment(&alignment); - alignedRowStride = (textureInfo->extents.width * texelSize + alignment - 1) & ~(alignment - 1); } - - void submitShaderWork(const char* entryPointName) + else { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto renderEncoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); - auto rootObject = renderEncoder->bindPipeline(pipelineState); - - gfx::Viewport viewport = {}; - viewport.maxZ = (float)textureInfo->extents.depth; - viewport.extentX = (float)textureInfo->extents.width; - viewport.extentY = (float)textureInfo->extents.height; - renderEncoder->setViewportAndScissor(viewport); - - renderEncoder->setVertexBuffer(0, vertexBuffer); - renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - renderEncoder->draw(kVertexCount, 0); - renderEncoder->endEncoding(); - - auto resourceEncoder = commandBuffer->encodeResourceCommands(); - - if (sampleCount > 1) - { - SubresourceRange msaaSubresource = {}; - msaaSubresource.aspectMask = TextureAspect::Color; - msaaSubresource.mipLevel = 0; - msaaSubresource.mipLevelCount = 1; - msaaSubresource.baseArrayLayer = 0; - msaaSubresource.layerCount = 1; - - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = TextureAspect::Color; - dstSubresource.mipLevel = 0; - dstSubresource.mipLevelCount = 1; - dstSubresource.baseArrayLayer = 0; - dstSubresource.layerCount = 1; - - resourceEncoder->resolveResource(sampledTexture, ResourceState::ResolveSource, msaaSubresource, texture, ResourceState::ResolveDestination, dstSubresource); - resourceEncoder->textureBarrier(texture, ResourceState::ResolveDestination, ResourceState::CopySource); - } - else - { - resourceEncoder->textureBarrier(sampledTexture, ResourceState::ResolveSource, ResourceState::CopySource); - } - resourceEncoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); + resourceEncoder->textureBarrier( + sampledTexture, + ResourceState::ResolveSource, + ResourceState::CopySource); } + resourceEncoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } - // TODO: Should take a value indicating the slice that was rendered into - // TODO: Needs to handle either the correct slice or array layer (will not always check z) - void validateTextureValues(ValidationTextureData actual) + // TODO: Should take a value indicating the slice that was rendered into + // TODO: Needs to handle either the correct slice or array layer (will not always check z) + void validateTextureValues(ValidationTextureData actual) + { + for (GfxIndex x = 0; x < actual.extents.width; ++x) { - for (GfxIndex x = 0; x < actual.extents.width; ++x) + for (GfxIndex y = 0; y < actual.extents.height; ++y) { - for (GfxIndex y = 0; y < actual.extents.height; ++y) + for (GfxIndex z = 0; z < actual.extents.depth; ++z) { - for (GfxIndex z = 0; z < actual.extents.depth; ++z) + auto actualBlock = (float*)actual.getBlockAt(x, y, z); + for (Int i = 0; i < 4; ++i) { - auto actualBlock = (float*)actual.getBlockAt(x, y, z); - for (Int i = 0; i < 4; ++i) + if (z == 0) + { + // Slice being rendered into + SLANG_CHECK(actualBlock[i] == (float)i + 1); + } + else { - if (z == 0) - { - // Slice being rendered into - SLANG_CHECK(actualBlock[i] == (float)i + 1); - } - else - { - SLANG_CHECK(actualBlock[i] == 0.0f); - } + SLANG_CHECK(actualBlock[i] == 0.0f); } } } } } + } - void checkTestResults() + void checkTestResults() + { + ComPtr<ISlangBlob> textureBlob; + size_t rowPitch; + size_t pixelSize; + if (sampleCount > 1) { - ComPtr<ISlangBlob> textureBlob; - size_t rowPitch; - size_t pixelSize; - if (sampleCount > 1) - { - GFX_CHECK_CALL_ABORT(device->readTextureResource(texture, ResourceState::CopySource, textureBlob.writeRef(), &rowPitch, &pixelSize)); - } - else - { - GFX_CHECK_CALL_ABORT(device->readTextureResource(sampledTexture, ResourceState::CopySource, textureBlob.writeRef(), &rowPitch, &pixelSize)); - } - auto textureValues = (float*)textureBlob->getBufferPointer(); - - ValidationTextureData textureResults; - textureResults.extents = textureInfo->extents; - textureResults.textureData = textureValues; - textureResults.strides.x = (uint32_t)pixelSize; - textureResults.strides.y = (uint32_t)rowPitch; - textureResults.strides.z = textureResults.extents.height * textureResults.strides.y; - - validateTextureValues(textureResults); + GFX_CHECK_CALL_ABORT(device->readTextureResource( + texture, + ResourceState::CopySource, + textureBlob.writeRef(), + &rowPitch, + &pixelSize)); } - - void run() + else { - auto entryPointName = getShaderEntryPoint(); -// printf("%s\n", entryPointName.getBuffer()); - - // TODO: Sampler state and null state? -// ISamplerState::Desc samplerDesc; -// sampler = device->createSamplerState(samplerDesc); - - textureInfo->extents.width = 4; - textureInfo->extents.height = (textureInfo->textureType == IResource::Type::Texture1D) ? 1 : 4; - textureInfo->extents.depth = (textureInfo->textureType != IResource::Type::Texture3D) ? 1 : 2; - textureInfo->mipLevelCount = 1; - textureInfo->arrayLayerCount = 1; - generateTextureData(textureInfo, validationFormat); - - // We need to save the pointer to the original texture data for results checking because the texture will be - // overwritten during testing (if the texture can be written to). - expectedTextureData = textureInfo->subresourceDatas[getSubresourceIndex(0, 1, 0)].data; + GFX_CHECK_CALL_ABORT(device->readTextureResource( + sampledTexture, + ResourceState::CopySource, + textureBlob.writeRef(), + &rowPitch, + &pixelSize)); + } + auto textureValues = (float*)textureBlob->getBufferPointer(); - createRequiredResources(); - submitShaderWork(entryPointName.getBuffer()); + ValidationTextureData textureResults; + textureResults.extents = textureInfo->extents; + textureResults.textureData = textureValues; + textureResults.strides.x = (uint32_t)pixelSize; + textureResults.strides.y = (uint32_t)rowPitch; + textureResults.strides.z = textureResults.extents.height * textureResults.strides.y; - checkTestResults(); - } - }; + validateTextureValues(textureResults); + } - void shaderAndUnorderedTestImpl(IDevice* device, UnitTestContext* context) + void run() { - // TODO: Buffer and TextureCube - for (Int i = 2; i < (int32_t)IResource::Type::TextureCube; ++i) - { - for (Int j = 3; j < (int32_t)IResourceView::Type::AccelerationStructure; ++j) - { - auto shape = (IResource::Type)i; - auto view = (IResourceView::Type)j; - auto format = Format::R8G8B8A8_UINT; - auto validationFormat = getValidationTextureFormat(format); - if (!validationFormat) - SLANG_CHECK_ABORT(false); - - ShaderAndUnorderedTests test; - test.init(device, context, format, validationFormat, view, shape); - test.run(); - } - } + auto entryPointName = getShaderEntryPoint(); + // printf("%s\n", entryPointName.getBuffer()); + + // TODO: Sampler state and null state? + // ISamplerState::Desc samplerDesc; + // sampler = device->createSamplerState(samplerDesc); + + textureInfo->extents.width = 4; + textureInfo->extents.height = + (textureInfo->textureType == IResource::Type::Texture1D) ? 1 : 4; + textureInfo->extents.depth = + (textureInfo->textureType != IResource::Type::Texture3D) ? 1 : 2; + textureInfo->mipLevelCount = 1; + textureInfo->arrayLayerCount = 1; + generateTextureData(textureInfo, validationFormat); + + // We need to save the pointer to the original texture data for results checking because the + // texture will be overwritten during testing (if the texture can be written to). + expectedTextureData = textureInfo->subresourceDatas[getSubresourceIndex(0, 1, 0)].data; + + createRequiredResources(); + submitShaderWork(entryPointName.getBuffer()); + + checkTestResults(); } +}; - void renderTargetTestImpl(IDevice* device, UnitTestContext* context) +void shaderAndUnorderedTestImpl(IDevice* device, UnitTestContext* context) +{ + // TODO: Buffer and TextureCube + for (Int i = 2; i < (int32_t)IResource::Type::TextureCube; ++i) { - // TODO: Buffer and TextureCube - for (Int i = 2; i < (int32_t)IResource::Type::TextureCube; ++i) + for (Int j = 3; j < (int32_t)IResourceView::Type::AccelerationStructure; ++j) { auto shape = (IResource::Type)i; - auto view = IResourceView::Type::RenderTarget; - auto format = Format::R32G32B32A32_FLOAT; + auto view = (IResourceView::Type)j; + auto format = Format::R8G8B8A8_UINT; auto validationFormat = getValidationTextureFormat(format); if (!validationFormat) SLANG_CHECK_ABORT(false); - RenderTargetTests test; + ShaderAndUnorderedTests test; test.init(device, context, format, validationFormat, view, shape); test.run(); } } +} - SLANG_UNIT_TEST(shaderAndUnorderedAccessTests) +void renderTargetTestImpl(IDevice* device, UnitTestContext* context) +{ + // TODO: Buffer and TextureCube + for (Int i = 2; i < (int32_t)IResource::Type::TextureCube; ++i) { - runTestImpl(shaderAndUnorderedTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(shaderAndUnorderedTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + auto shape = (IResource::Type)i; + auto view = IResourceView::Type::RenderTarget; + auto format = Format::R32G32B32A32_FLOAT; + auto validationFormat = getValidationTextureFormat(format); + if (!validationFormat) + SLANG_CHECK_ABORT(false); + + RenderTargetTests test; + test.init(device, context, format, validationFormat, view, shape); + test.run(); } +} - SLANG_UNIT_TEST(renderTargetTests) - { - runTestImpl(renderTargetTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - runTestImpl(renderTargetTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); - } +SLANG_UNIT_TEST(shaderAndUnorderedAccessTests) +{ + runTestImpl(shaderAndUnorderedTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(shaderAndUnorderedTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +SLANG_UNIT_TEST(renderTargetTests) +{ + runTestImpl(renderTargetTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(renderTargetTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); } +} // namespace gfx_test // 1D + array + multisample, ditto for 2D, ditto for 3D -// one test with something bound, one test with nothing bound, one test with subset of layers (set values in SubresourceRange and assign in desc) +// one test with something bound, one test with nothing bound, one test with subset of layers (set +// values in SubresourceRange and assign in desc) diff --git a/tools/gfx-unit-test/uint16-structured-buffer.cpp b/tools/gfx-unit-test/uint16-structured-buffer.cpp index 8f2f2cb97..23fd70544 100644 --- a/tools/gfx-unit-test/uint16-structured-buffer.cpp +++ b/tools/gfx-unit-test/uint16-structured-buffer.cpp @@ -1,96 +1,91 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" #include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" +#include "slang-gfx.h" #include "source/core/slang-basic.h" +#include "tools/gfx-util/shader-cursor.h" +#include "tools/unit-test/slang-unit-test.h" using namespace gfx; namespace gfx_test { - void uint16BufferTestImpl(IDevice* device, UnitTestContext* context) +void uint16BufferTestImpl(IDevice* device, UnitTestContext* context) +{ + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT( + loadComputeProgram(device, shaderProgram, "uint16-buffer", "computeMain", slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + uint16_t initialData[] = {0, 1, 2, 3}; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(uint16_t); + bufferDesc.format = gfx::Format::Unknown; + // Note: we don't specify any element size here, and gfx should be able to derive the + // correct element size from the reflection infomation. + bufferDesc.elementSize = 0; + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + ComPtr<IBufferResource> numbersBuffer; + GFX_CHECK_CALL_ABORT( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); + + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT( + device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. { - Slang::ComPtr<ITransientResourceHeap> transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - GFX_CHECK_CALL_ABORT( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr<IShaderProgram> shaderProgram; - slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "uint16-buffer", "computeMain", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr<gfx::IPipelineState> pipelineState; - GFX_CHECK_CALL_ABORT( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - uint16_t initialData[] = { 0, 1, 2, 3 }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(uint16_t); - bufferDesc.format = gfx::Format::Unknown; - // Note: we don't specify any element size here, and gfx should be able to derive the - // correct element size from the reflection infomation. - bufferDesc.elementSize = 0; - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.memoryType = MemoryType::DeviceLocal; - - ComPtr<IBufferResource> numbersBuffer; - GFX_CHECK_CALL_ABORT(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr<IResourceView> bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - GFX_CHECK_CALL_ABORT( - device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - // Bind buffer view to the entry point. - ShaderCursor(rootObject).getPath("buffer").setResource(bufferView); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->waitOnHost(); - } - - compareComputeResult( - device, - numbersBuffer, - Slang::makeArray<uint16_t>(1, 2, 3, 4)); - } + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); - SLANG_UNIT_TEST(uint16BufferTestD3D12) - { - runTestImpl(uint16BufferTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); - } + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); - SLANG_UNIT_TEST(uint16BufferTestVulkan) - { - runTestImpl(uint16BufferTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + auto rootObject = encoder->bindPipeline(pipelineState); + + // Bind buffer view to the entry point. + ShaderCursor(rootObject).getPath("buffer").setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); } + compareComputeResult(device, numbersBuffer, Slang::makeArray<uint16_t>(1, 2, 3, 4)); +} + +SLANG_UNIT_TEST(uint16BufferTestD3D12) +{ + runTestImpl(uint16BufferTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12); } + +SLANG_UNIT_TEST(uint16BufferTestVulkan) +{ + runTestImpl(uint16BufferTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); +} + +} // namespace gfx_test |
