diff options
| author | Kai Yao <kyao@nvidia.com> | 2021-10-08 14:51:14 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-08 14:51:14 -0700 |
| commit | 91e98efca508ea4455f415b9157452654476e1bc (patch) | |
| tree | 28c87d75bb4994826963ad6d448a654aba7e167c /tools | |
| parent | d541489efa698f726a1f450c0c400591835b3982 (diff) | |
Basic VK buffer barrier test (#1967)
* Allow specifying entry point name in gfx unit test util
* Add buffer barrier test
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/gfx-unit-test/buffer-barrier-test.cpp | 158 | ||||
| -rw-r--r-- | tools/gfx-unit-test/buffer-barrier-test.slang | 22 | ||||
| -rw-r--r-- | tools/gfx-unit-test/compute-smoke.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx-unit-test/existing-device-handle-test.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.cpp | 6 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.h | 3 |
6 files changed, 187 insertions, 6 deletions
diff --git a/tools/gfx-unit-test/buffer-barrier-test.cpp b/tools/gfx-unit-test/buffer-barrier-test.cpp new file mode 100644 index 000000000..4dd3aa9a8 --- /dev/null +++ b/tools/gfx-unit-test/buffer-barrier-test.cpp @@ -0,0 +1,158 @@ +#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 "source/core/slang-basic.h" + +using namespace gfx; + +namespace gfx_test +{ + 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; + }; + + 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.cpuAccessFlags = AccessFlag::Write | AccessFlag::Read; + 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, viewDesc, outBuffer.view.writeRef())); + } + + 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. + { + 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->wait(); + } + + 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_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); + } + + SLANG_UNIT_TEST(bufferBarrierVulkan) + { + barrierTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); + } + +} diff --git a/tools/gfx-unit-test/buffer-barrier-test.slang b/tools/gfx-unit-test/buffer-barrier-test.slang new file mode 100644 index 000000000..07c39e809 --- /dev/null +++ b/tools/gfx-unit-test/buffer-barrier-test.slang @@ -0,0 +1,22 @@ +// buffer-barrier-test.slang + +[shader("compute")] +[numthreads(4,1,1)] +void computeA( + uint3 sv_dispatchThreadID : SV_DispatchThreadID, + uniform StructuredBuffer<float> inBuffer, + uniform RWStructuredBuffer<float> outBuffer) +{ + outBuffer[sv_dispatchThreadID.x] = inBuffer[sv_dispatchThreadID.x]; +} + +[shader("compute")] +[numthreads(4,1,1)] +void computeB( + uint3 sv_dispatchThreadID : SV_DispatchThreadID, + uniform StructuredBuffer<float> inBuffer, + uniform RWStructuredBuffer<float> outBuffer) +{ + outBuffer[sv_dispatchThreadID.x] = inBuffer[sv_dispatchThreadID.x] + 10.0f; +} + diff --git a/tools/gfx-unit-test/compute-smoke.cpp b/tools/gfx-unit-test/compute-smoke.cpp index b8e027b65..9038cd5b6 100644 --- a/tools/gfx-unit-test/compute-smoke.cpp +++ b/tools/gfx-unit-test/compute-smoke.cpp @@ -19,7 +19,7 @@ namespace gfx_test ComPtr<IShaderProgram> shaderProgram; slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadShaderProgram(device, shaderProgram, "compute-smoke", slangReflection)); + GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "compute-smoke", "computeMain", slangReflection)); ComputePipelineStateDesc pipelineDesc = {}; pipelineDesc.program = shaderProgram.get(); diff --git a/tools/gfx-unit-test/existing-device-handle-test.cpp b/tools/gfx-unit-test/existing-device-handle-test.cpp index 2a4ffea26..047128bdd 100644 --- a/tools/gfx-unit-test/existing-device-handle-test.cpp +++ b/tools/gfx-unit-test/existing-device-handle-test.cpp @@ -19,7 +19,7 @@ namespace gfx_test ComPtr<IShaderProgram> shaderProgram; slang::ProgramLayout* slangReflection; - GFX_CHECK_CALL_ABORT(loadShaderProgram(device, shaderProgram, "compute-smoke", slangReflection)); + GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "compute-smoke", "computeMain", slangReflection)); ComputePipelineStateDesc pipelineDesc = {}; pipelineDesc.program = shaderProgram.get(); diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp index d01fcdca3..1b23047a1 100644 --- a/tools/gfx-unit-test/gfx-test-util.cpp +++ b/tools/gfx-unit-test/gfx-test-util.cpp @@ -15,10 +15,11 @@ namespace gfx_test } } - Slang::Result loadShaderProgram( + 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; @@ -29,10 +30,9 @@ namespace gfx_test if (!module) return SLANG_FAIL; - char const* computeEntryPointName = "computeMain"; ComPtr<slang::IEntryPoint> computeEntryPoint; SLANG_RETURN_ON_FAIL( - module->findEntryPointByName(computeEntryPointName, computeEntryPoint.writeRef())); + module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef())); Slang::List<slang::IComponentType*> componentTypes; componentTypes.add(module); diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h index b7e402abc..c7db19394 100644 --- a/tools/gfx-unit-test/gfx-test-util.h +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -9,10 +9,11 @@ namespace gfx_test void diagnoseIfNeeded(ISlangWriter* diagnosticWriter, slang::IBlob* diagnosticsBlob); /// Loads a compute shader module and produces a `gfx::IShaderProgram`. - Slang::Result loadShaderProgram( + Slang::Result loadComputeProgram( gfx::IDevice* device, Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram, const char* shaderModuleName, + const char* entryPointName, slang::ProgramLayout*& slangReflection); /// Reads back the content of `buffer` and compares it against `expectedResult`. |
