diff options
| author | Yong He <yonghe@outlook.com> | 2020-10-09 11:29:11 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-09 11:29:11 -0700 |
| commit | fab1c9f4c745ba84983c2448646376799d461e96 (patch) | |
| tree | 3176c03987417c01b7220aaf13c35b665813c876 | |
| parent | 11f331771a8d5d80bc1dd317dcad5eb815e9cb55 (diff) | |
Support CUDA bindless texture in dynamic dispatch code. (#1575)
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 10 | ||||
| -rw-r--r-- | source/slang/slang-ir-any-value-marshalling.cpp | 51 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 26 | ||||
| -rw-r--r-- | tests/compute/dynamic-dispatch-bindless-texture.slang | 40 | ||||
| -rw-r--r-- | tests/compute/dynamic-dispatch-bindless-texture.slang.expected.txt | 4 | ||||
| -rw-r--r-- | tools/render-test/cpu-compute-util.cpp | 150 | ||||
| -rw-r--r-- | tools/render-test/cpu-compute-util.h | 12 | ||||
| -rw-r--r-- | tools/render-test/cuda/cuda-compute-util.cpp | 134 | ||||
| -rw-r--r-- | tools/render-test/cuda/cuda-compute-util.h | 3 | ||||
| -rw-r--r-- | tools/render-test/render-test-main.cpp | 3 | ||||
| -rw-r--r-- | tools/render-test/shader-input-layout.cpp | 21 | ||||
| -rw-r--r-- | tools/render-test/shader-input-layout.h | 9 |
14 files changed, 424 insertions, 45 deletions
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index e0499319f..e27a5b972 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -2090,7 +2090,15 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO emitType(inst->getDataType()); emitArgs(inst); break; - + case kIROp_makeUInt64: + m_writer->emit("(("); + emitType(inst->getDataType()); + m_writer->emit("("); + emitOperand(inst->getOperand(1), getInfo(EmitOp::General)); + m_writer->emit(") << 32) + "); + emitOperand(inst->getOperand(0), getInfo(EmitOp::General)); + m_writer->emit(")"); + break; case kIROp_constructVectorFromScalar: { // Simple constructor call diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp index 0a988da1d..9322ed0eb 100644 --- a/source/slang/slang-ir-any-value-marshalling.cpp +++ b/source/slang/slang-ir-any-value-marshalling.cpp @@ -85,7 +85,8 @@ namespace Slang IRInst* anyValueVar; // Defines what to do with basic typed data elements. virtual void marshalBasicType(IRBuilder* builder, IRType* dataType, IRInst* concreteTypedVar) = 0; - + // Defines what to do with resource handle elements. + virtual void marshalResourceHandle(IRBuilder* builder, IRType* dataType, IRInst* concreteTypedVar) = 0; // Validates that the type fits in the given AnyValueSize. // After calling emitMarshallingCode, `fieldOffset` will be increased to the required `AnyValue` size. // If this is larger than the provided AnyValue size, report a dianogstic. We might want to front load @@ -188,6 +189,11 @@ namespace Slang break; } default: + if (as<IRTextureTypeBase>(dataType) || as<IRSamplerStateTypeBase>(dataType)) + { + context->marshalResourceHandle(builder, dataType, concreteTypedVar); + return; + } SLANG_UNIMPLEMENTED_X("Unimplemented type packing"); break; } @@ -243,6 +249,29 @@ namespace Slang SLANG_UNREACHABLE("unknown basic type"); } } + + virtual void marshalResourceHandle(IRBuilder* builder, IRType* dataType, IRInst* concreteVar) override + { + SLANG_UNUSED(dataType); + if (fieldOffset + 1 < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount())) + { + auto srcVal = builder->emitLoad(concreteVar); + auto uint64Val = builder->emitBitCast(builder->getUInt64Type(), srcVal); + auto lowBits = builder->emitConstructorInst(builder->getUIntType(), 1, &uint64Val); + auto shiftedBits = builder->emitShr( + builder->getUInt64Type(), + uint64Val, + builder->getIntValue(builder->getIntType(), 32)); + auto highBits = builder->emitBitCast(builder->getUIntType(), shiftedBits); + auto dstAddr1 = builder->emitFieldAddress( + uintPtrType, anyValueVar, anyValInfo->fieldKeys[fieldOffset]); + builder->emitStore(dstAddr1, lowBits); + auto dstAddr2 = builder->emitFieldAddress( + uintPtrType, anyValueVar, anyValInfo->fieldKeys[fieldOffset + 1]); + builder->emitStore(dstAddr2, highBits); + fieldOffset += 2; + } + } }; IRFunc* generatePackingFunc(IRType* type, IRAnyValueType* anyValueType) @@ -335,6 +364,26 @@ namespace Slang SLANG_UNREACHABLE("unknown basic type"); } } + + virtual void marshalResourceHandle( + IRBuilder* builder, IRType* dataType, IRInst* concreteVar) override + { + if (fieldOffset + 1 < static_cast<uint32_t>(anyValInfo->fieldKeys.getCount())) + { + auto srcAddr = builder->emitFieldAddress( + uintPtrType, anyValueVar, anyValInfo->fieldKeys[fieldOffset]); + auto lowBits = builder->emitLoad(srcAddr); + + auto srcAddr1 = builder->emitFieldAddress( + uintPtrType, anyValueVar, anyValInfo->fieldKeys[fieldOffset + 1]); + auto highBits = builder->emitLoad(srcAddr1); + + auto combinedBits = builder->emitMakeUInt64(lowBits, highBits); + combinedBits = builder->emitBitCast(dataType, combinedBits); + builder->emitStore(concreteVar, combinedBits); + fieldOffset += 2; + } + } }; IRFunc* generateUnpackingFunc(IRType* type, IRAnyValueType* anyValueType) diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index c7d223ab6..340f18c8c 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -234,6 +234,7 @@ INST(BindGlobalGenericParam, bind_global_generic_param, 2, 0) INST(Construct, construct, 0, 0) +INST(makeUInt64, makeUInt64, 2, 0) INST(makeVector, makeVector, 0, 0) INST(MakeMatrix, makeMatrix, 0, 0) INST(makeArray, makeArray, 0, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 658e50f28..af0f737ea 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -1779,6 +1779,7 @@ struct IRBuilder IRBasicType* getBoolType(); IRBasicType* getIntType(); IRBasicType* getUIntType(); + IRBasicType* getUInt64Type(); IRStringType* getStringType(); IRAssociatedType* getAssociatedType(ArrayView<IRInterfaceType*> constraintTypes); @@ -1942,6 +1943,8 @@ struct IRBuilder UInt argCount, IRInst* const* args); + IRInst* emitMakeUInt64(IRInst* low, IRInst* high); + // Creates an RTTI object. Result is of `IRRTTIType`. IRInst* emitMakeRTTIObject(IRInst* typeInst); @@ -2303,6 +2306,8 @@ struct IRBuilder IRInst* emitAdd(IRType* type, IRInst* left, IRInst* right); IRInst* emitMul(IRType* type, IRInst* left, IRInst* right); + IRInst* emitShr(IRType* type, IRInst* op0, IRInst* op1); + IRInst* emitShl(IRType* type, IRInst* op0, IRInst* op1); // // Decorations diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 3820119d2..6f0cc43e2 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -2230,6 +2230,11 @@ namespace Slang return (IRBasicType*)getType(kIROp_UIntType); } + IRBasicType* IRBuilder::getUInt64Type() + { + return (IRBasicType*)getType(kIROp_UInt64Type); + } + IRStringType* IRBuilder::getStringType() { return (IRStringType*)getType(kIROp_StringType); @@ -2750,6 +2755,12 @@ namespace Slang return inst; } + IRInst* IRBuilder::emitMakeUInt64(IRInst* low, IRInst* high) + { + IRInst* args[2] = {low, high}; + return emitIntrinsicInst(getUInt64Type(), kIROp_makeUInt64, 2, args); + } + IRInst* IRBuilder::emitMakeRTTIObject(IRInst* typeInst) { auto inst = createInst<IRRTTIObject>( @@ -3786,6 +3797,20 @@ namespace Slang return inst; } + IRInst* IRBuilder::emitShr(IRType* type, IRInst* left, IRInst* right) + { + auto inst = createInst<IRInst>(this, kIROp_Rsh, type, left, right); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitShl(IRType* type, IRInst* left, IRInst* right) + { + auto inst = createInst<IRInst>(this, kIROp_Lsh, type, left, right); + addInst(inst); + return inst; + } + IRInst* IRBuilder::emitGpuForeach(List<IRInst*> args) { auto inst = createInst<IRInst>( @@ -5300,6 +5325,7 @@ namespace Slang case kIROp_getAddr: case kIROp_GetValueFromExistentialBox: case kIROp_Construct: + case kIROp_makeUInt64: case kIROp_makeVector: case kIROp_MakeMatrix: case kIROp_makeArray: diff --git a/tests/compute/dynamic-dispatch-bindless-texture.slang b/tests/compute/dynamic-dispatch-bindless-texture.slang new file mode 100644 index 000000000..49265fac4 --- /dev/null +++ b/tests/compute/dynamic-dispatch-bindless-texture.slang @@ -0,0 +1,40 @@ +// Test using interface typed shader parameters with texture typed fields. +//TEST(compute):COMPARE_COMPUTE:-cpu +//TEST(compute):COMPARE_COMPUTE:-cuda + +[anyValueSize(8)] +interface IInterface +{ + float run(); +} + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=gOutputBuffer +RWStructuredBuffer<uint> gOutputBuffer; +//TEST_INPUT: Texture2D(size=8, content = one):name t2D,bindless +//TEST_INPUT:ubuffer(data=[rtti(MyImpl) witness(MyImpl, IInterface) handle(t2D) 0 0], stride=4):name=gCb +StructuredBuffer<IInterface> gCb; + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + let tid = dispatchThreadID.x; + + let inputVal : int = tid; + IInterface v0 = gCb.Load(0); + SamplerState sampler; + let outputVal = v0.run(); + gOutputBuffer[tid] = trunc(outputVal); +} + +//TEST_INPUT: globalExistentialType __Dynamic + +// Type must be marked `public` to ensure it is visible in the generated DLL. +public struct MyImpl : IInterface +{ + Texture2D tex; + SamplerState sampler; + float run() + { + return tex.Sample(sampler, float2(0.0, 0.0)).x; + } +}; diff --git a/tests/compute/dynamic-dispatch-bindless-texture.slang.expected.txt b/tests/compute/dynamic-dispatch-bindless-texture.slang.expected.txt new file mode 100644 index 000000000..98fb6a686 --- /dev/null +++ b/tests/compute/dynamic-dispatch-bindless-texture.slang.expected.txt @@ -0,0 +1,4 @@ +1 +1 +1 +1 diff --git a/tools/render-test/cpu-compute-util.cpp b/tools/render-test/cpu-compute-util.cpp index 2c9a9dc82..a861dadf3 100644 --- a/tools/render-test/cpu-compute-util.cpp +++ b/tools/render-test/cpu-compute-util.cpp @@ -222,13 +222,39 @@ struct FloatRWTexture : public CPUComputeUtil::Resource, public CPPPrelude::IRWT static int _calcDims(const InputTextureDesc& desc, slang::TypeLayoutReflection* typeLayout, CPPPrelude::TextureDimensions& outDims) { outDims.reset(); - - const auto kind = typeLayout->getKind(); - SLANG_ASSERT(kind == slang::TypeReflection::Kind::Resource); - - auto type = typeLayout->getType(); - auto shape = type->getResourceShape(); - + SlangResourceShape shape = SLANG_TEXTURE_2D; + if (typeLayout) + { + const auto kind = typeLayout->getKind(); + SLANG_ASSERT(kind == slang::TypeReflection::Kind::Resource); + auto type = typeLayout->getType(); + shape = type->getResourceShape(); + } + else + { + if (desc.isCube) + { + shape = SLANG_TEXTURE_CUBE; + } + else + { + switch (desc.dimension) + { + case 1: + shape = SLANG_TEXTURE_1D; + break; + case 2: + shape = SLANG_TEXTURE_2D; + break; + case 3: + shape = SLANG_TEXTURE_3D; + break; + default: + break; + } + } + } + outDims.shape = shape; const uint32_t size = uint32_t(desc.size); @@ -293,26 +319,56 @@ static CPUComputeUtil::Resource* _newReadTexture(int elemCount, const CPPPrelude static SlangResult _newTexture(const InputTextureDesc& desc, slang::TypeLayoutReflection* typeLayout, RefPtr<CPUComputeUtil::Resource>& outResource) { - const auto kind = typeLayout->getKind(); - SLANG_ASSERT(kind == slang::TypeReflection::Kind::Resource); + SlangResourceAccess access = SLANG_RESOURCE_ACCESS_READ; + SlangResourceShape shape = SLANG_TEXTURE_2D; + int elemCount = 1; + if (typeLayout) + { + const auto kind = typeLayout->getKind(); + SLANG_ASSERT(kind == slang::TypeReflection::Kind::Resource); - auto type = typeLayout->getType(); - auto shape = type->getResourceShape(); + auto type = typeLayout->getType(); + shape = type->getResourceShape(); - auto access = type->getResourceAccess(); + access = type->getResourceAccess(); + slang::TypeReflection* typeReflection = typeLayout->getResourceResultType(); + if (typeReflection->getKind() == slang::TypeReflection::Kind::Vector) + { + elemCount = int(typeReflection->getElementCount()); + } + } + else + { + if (desc.isCube) + { + shape = SLANG_TEXTURE_CUBE; + } + else + { + switch (desc.dimension) + { + case 1: + shape = SLANG_TEXTURE_1D; + break; + case 2: + shape = SLANG_TEXTURE_2D; + break; + case 3: + shape = SLANG_TEXTURE_3D; + break; + default: + break; + } + } + if (desc.isRWTexture) + access = SLANG_RESOURCE_ACCESS_READ_WRITE; + elemCount = 4; + } // TODO(JS): Currently we support only textures who's content is either // 0 or 1. This is because this is easy to implement. // Will need to do something better in the future.. - slang::TypeReflection* typeReflection = typeLayout->getResourceResultType(); - - int elemCount = 1; - if (typeReflection->getKind() == slang::TypeReflection::Kind::Vector) - { - elemCount = int(typeReflection->getElementCount()); - } - float initialValue = 0.0f; switch (desc.content) @@ -359,8 +415,9 @@ static SlangResult _newTexture(const InputTextureDesc& desc, slang::TypeLayoutRe return false; } -SlangResult CPUComputeUtil::populateRTTIEntries( +SlangResult CPUComputeUtil::fillRuntimeHandleInBuffers( ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, + Context& context, ISlangSharedLibrary* sharedLib) { Slang::ComPtr<slang::ISession> linkage; @@ -418,6 +475,32 @@ SlangResult CPUComputeUtil::populateRTTIEntries( return SLANG_FAIL; } } + for (auto& handle : entry.bindlessHandleEntry) + { + RefPtr<Resource> resource; + uint64_t handleValue = 0; + if (context.m_bindlessResources.TryGetValue(handle.name, resource)) + { + handleValue = (uint64_t)resource->getInterface(); + } + else + { + return SLANG_FAIL; + } + if (handle.offset >= 0 && + handle.offset + sizeof(uint64_t) <= + entry.bufferData.getCount() * sizeof(decltype(entry.bufferData[0]))) + { + memcpy( + ((char*)entry.bufferData.getBuffer()) + handle.offset, + &handleValue, + sizeof(handleValue)); + } + else + { + return SLANG_FAIL; + } + } } return SLANG_OK; } @@ -815,5 +898,30 @@ SlangResult CPUComputeUtil::populateRTTIEntries( return SLANG_OK; } +SlangResult renderer_test::CPUComputeUtil::createBindlessResources( + ShaderCompilerUtil::OutputAndLayout& outputAndLayout, Context& context) +{ + auto outStream = StdWriters::getOut(); + for (auto& entry : outputAndLayout.layout.entries) + { + if (!entry.isBindlessObject) + continue; + switch (entry.type) + { + case ShaderInputType::Texture: + { + RefPtr<Resource> resource; + _newTexture(entry.textureDesc, nullptr, resource); + context.m_bindlessResources.Add(entry.name, resource); + break; + } + default: + outStream.print("Unsupported bindless resource type.\n"); + return SLANG_FAIL; + } + } + return SLANG_OK; +} + } // renderer_test diff --git a/tools/render-test/cpu-compute-util.h b/tools/render-test/cpu-compute-util.h index 01b781ca7..56d510818 100644 --- a/tools/render-test/cpu-compute-util.h +++ b/tools/render-test/cpu-compute-util.h @@ -6,7 +6,7 @@ #include "bind-location.h" -#include "../../source/core/slang-smart-pointer.h" +#include "../../source/core/slang-basic.h" namespace renderer_test { @@ -34,6 +34,9 @@ struct CPUComputeUtil /// Buffers are held in same order as entries in layout (useful for dumping out bindings) List<BindSet::Value*> m_buffers; + + /// Bindless resource objects + Slang::OrderedDictionary<Slang::String, RefPtr<Resource>> m_bindlessResources; }; struct ExecuteInfo @@ -55,9 +58,12 @@ struct CPUComputeUtil /// Runs code across run styles and makes sure output buffers match static SlangResult checkStyleConsistency(ISlangSharedLibrary* sharedLib, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout); - /// Query and fill in the RTTI pointer values in data buffers. - static SlangResult populateRTTIEntries( + static SlangResult createBindlessResources(ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& context); + + /// Query and fill in the RTTI pointer and runtime resource handle values in data buffers. + static SlangResult fillRuntimeHandleInBuffers( ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, + Context& context, ISlangSharedLibrary* sharedLib); static SlangResult calcBindings(const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& outContext); diff --git a/tools/render-test/cuda/cuda-compute-util.cpp b/tools/render-test/cuda/cuda-compute-util.cpp index f9e67d3f0..73ad78f0b 100644 --- a/tools/render-test/cuda/cuda-compute-util.cpp +++ b/tools/render-test/cuda/cuda-compute-util.cpp @@ -178,6 +178,11 @@ public: return resource ? resource->m_cudaMemory : CUdeviceptr(); } + virtual uint64_t getBindlessHandle() override + { + return (uint64_t)m_cudaMemory; + } + CUdeviceptr m_cudaMemory = CUdeviceptr(); }; @@ -224,6 +229,11 @@ public: return resource ? resource->m_cudaSurfObj : CUsurfObject(0); } + virtual uint64_t getBindlessHandle() override + { + return (uint64_t)m_cudaTexObj; + } + // The texObject is for reading 'texture' like things. This is an opaque type, that's backed by a long long CUtexObject m_cudaTexObj = CUtexObject(); @@ -537,22 +547,48 @@ static bool _hasWriteAccess(SlangResourceAccess access) /* static */SlangResult CUDAComputeUtil::createTextureResource(const ShaderInputLayoutEntry& srcEntry, slang::TypeLayoutReflection* typeLayout, RefPtr<CUDAResource>& outResource) { - auto type = typeLayout->getType(); - auto shape = type->getResourceShape(); - - auto access = type->getResourceAccess(); + SlangResourceAccess access = SLANG_RESOURCE_ACCESS_READ; + SlangResourceShape baseShape = SLANG_TEXTURE_2D; + if (typeLayout) + { + auto type = typeLayout->getType(); + auto shape = type->getResourceShape(); + access = type->getResourceAccess(); - if (!(access == SLANG_RESOURCE_ACCESS_READ || - access == SLANG_RESOURCE_ACCESS_READ_WRITE)) + if (!(access == SLANG_RESOURCE_ACCESS_READ || access == SLANG_RESOURCE_ACCESS_READ_WRITE)) + { + SLANG_ASSERT(!"Only read or read write currently supported"); + return SLANG_FAIL; + } + baseShape = shape & SLANG_RESOURCE_BASE_SHAPE_MASK; + } + else { - SLANG_ASSERT(!"Only read or read write currently supported"); - return SLANG_FAIL; + if (srcEntry.textureDesc.isCube) + { + baseShape = SLANG_TEXTURE_CUBE; + } + else + { + switch (srcEntry.textureDesc.dimension) + { + case 1: + baseShape = SLANG_TEXTURE_1D; + break; + case 2: + baseShape = SLANG_TEXTURE_2D; + break; + case 3: + baseShape = SLANG_TEXTURE_3D; + break; + default: + break; + } + } + if (srcEntry.textureDesc.isRWTexture) + access = SLANG_RESOURCE_ACCESS_READ_WRITE; } - CUresourcetype resourceType = CU_RESOURCE_TYPE_ARRAY; - auto baseShape = shape & SLANG_RESOURCE_BASE_SHAPE_MASK; - - slang::TypeReflection* typeReflection = typeLayout->getResourceResultType(); InputTextureDesc textureDesc = srcEntry.textureDesc; @@ -1360,9 +1396,10 @@ static SlangResult _loadAndInvokeRayTracingProgram( } #endif - // Fill in RTTI pointers values in input buffers. -static SlangResult _populateRTTIEntries( + // Fill in runtime handles (e.g. RTTI pointers values and bindless resource handles) in input buffers. +static SlangResult _fillRuntimeHandlesInBuffers( const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, + CUDAComputeUtil::Context& context, ScopeCUDAModule& cudaModule) { Slang::ComPtr<slang::ISession> linkage; @@ -1432,6 +1469,59 @@ static SlangResult _populateRTTIEntries( return SLANG_FAIL; } } + + for (auto& handle : entry.bindlessHandleEntry) + { + RefPtr<CUDAResource> resource; + uint64_t handleValue = 0; + if (context.m_bindlessResources.TryGetValue(handle.name, resource)) + { + handleValue = resource->getBindlessHandle(); + } + else + { + return SLANG_FAIL; + } + if (handle.offset >= 0 && + handle.offset + sizeof(uint64_t) <= + entry.bufferData.getCount() * sizeof(decltype(entry.bufferData[0]))) + { + memcpy( + ((char*)entry.bufferData.getBuffer()) + handle.offset, + &handleValue, + sizeof(handleValue)); + } + else + { + return SLANG_FAIL; + } + } + } + return SLANG_OK; +} + +static SlangResult _createBindlessResources( + const ShaderCompilerUtil::OutputAndLayout& outputAndLayout, + CUDAComputeUtil::Context& outContext) +{ + auto outStream = StdWriters::getOut(); + for (auto& entry : outputAndLayout.layout.entries) + { + if (!entry.isBindlessObject) + continue; + switch (entry.type) + { + case ShaderInputType::Texture: + { + RefPtr<CUDAResource> resource; + CUDAComputeUtil::createTextureResource(entry, nullptr, resource); + outContext.m_bindlessResources.Add(entry.name, resource); + break; + } + default: + outStream.print("Unsupported bindless resource type.\n"); + return SLANG_FAIL; + } } return SLANG_OK; } @@ -1460,13 +1550,17 @@ static SlangResult _setUpArguments( auto outStream = StdWriters::getOut(); - // Fill in RTTI pointers in input buffers before copying it to GPU memory. + _createBindlessResources(outputAndLayout, outContext); + + // Fill in RTTI pointers and bindless handles in input buffers before copying + // it to GPU memory. // TODO: enable this for Optix path after it is refactored so that context // creation and module loading happens before _setUpArguments. if (outputAndLayout.output.desc.pipelineType == PipelineType::Compute) { - SLANG_RETURN_ON_FAIL(_populateRTTIEntries(outputAndLayout, cudaModule)); + SLANG_RETURN_ON_FAIL(_fillRuntimeHandlesInBuffers(outputAndLayout, outContext, cudaModule)); } + SLANG_RETURN_ON_FAIL(ShaderInputLayout::addBindSetValues(outputAndLayout.layout.entries, outputAndLayout.sourcePath, outStream, bindRoot)); ShaderInputLayout::getValueBuffers(outputAndLayout.layout.entries, bindSet, outContext.m_buffers); @@ -1772,9 +1866,15 @@ SlangResult _loadAndInvokeKernel( // Release all othe CUDA resource/allocations bindSet.releaseValueTargets(); + outContext.releaseBindlessResources(); return SLANG_OK; } -} // renderer_test +void CUDAComputeUtil::Context::releaseBindlessResources() +{ + m_bindlessResources = decltype(m_bindlessResources)(); +} + +} // namespace renderer_test diff --git a/tools/render-test/cuda/cuda-compute-util.h b/tools/render-test/cuda/cuda-compute-util.h index bc3d7d233..8bc7bd8d6 100644 --- a/tools/render-test/cuda/cuda-compute-util.h +++ b/tools/render-test/cuda/cuda-compute-util.h @@ -13,6 +13,7 @@ namespace renderer_test { class CUDAResource : public RefObject { public: + virtual uint64_t getBindlessHandle() = 0; }; struct CUDAComputeUtil @@ -44,6 +45,8 @@ struct CUDAComputeUtil CPULikeBindRoot m_bindRoot; /// Buffers are held in same order as entries in layout (useful for dumping out bindings) List<BindSet::Value*> m_buffers; + Slang::OrderedDictionary<Slang::String, RefPtr<CUDAResource>> m_bindlessResources; + void releaseBindlessResources(); }; static SlangResult parseFeature(const Slang::UnownedStringSlice& feature, bool& outResult); diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index 42d82edf6..85e038e5a 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -650,7 +650,8 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi // calculate binding CPUComputeUtil::Context context; - SLANG_RETURN_ON_FAIL(CPUComputeUtil::populateRTTIEntries(compilationAndLayout, sharedLibrary.get())); + SLANG_RETURN_ON_FAIL(CPUComputeUtil::createBindlessResources(compilationAndLayout, context)); + SLANG_RETURN_ON_FAIL(CPUComputeUtil::fillRuntimeHandleInBuffers(compilationAndLayout, context, sharedLibrary.get())); SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcBindings(compilationAndLayout, context)); // Get the execution info from the lib diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp index 40beffc05..6ded388e8 100644 --- a/tools/render-test/shader-input-layout.cpp +++ b/tools/render-test/shader-input-layout.cpp @@ -432,6 +432,20 @@ namespace renderer_test entry.bufferData.add(0); continue; } + else if (parser.LookAhead("handle")) + { + BindlessHandleDataEntry handleEntry; + parser.ReadToken(); + parser.Read("("); + handleEntry.name = parser.ReadWord(); + handleEntry.offset = offset; + parser.Read(")"); + offset += 8; + entry.bindlessHandleEntry.add(handleEntry); + entry.bufferData.add(0); + entry.bufferData.add(0); + continue; + } bool negate = false; if(parser.NextToken().Type == TokenType::OpSub) @@ -572,6 +586,11 @@ namespace renderer_test entry.name = builder; } + else if (parser.LookAhead("bindless")) + { + parser.ReadToken(); + entry.isBindlessObject = true; + } else { fprintf(stderr, "Invalid TEST_INPUT syntax '%s'\n", parser.NextToken().Content.getBuffer()); @@ -601,6 +620,8 @@ namespace renderer_test for (Index entryIndex = 0; entryIndex < entries.getCount(); ++entryIndex) { auto& entry = entries[entryIndex]; + if (entry.isBindlessObject) + continue; if (entry.name.getLength() == 0) { diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h index 4abbd6fb5..97796d7f6 100644 --- a/tools/render-test/shader-input-layout.h +++ b/tools/render-test/shader-input-layout.h @@ -75,19 +75,26 @@ struct RTTIDataEntry unsigned int offset; }; +struct BindlessHandleDataEntry +{ + unsigned int offset; + Slang::String name; +}; + class ShaderInputLayoutEntry { public: ShaderInputType type; Slang::List<unsigned int> bufferData; Slang::List<RTTIDataEntry> rttiEntries; + Slang::List<BindlessHandleDataEntry> bindlessHandleEntry; InputTextureDesc textureDesc; InputBufferDesc bufferDesc; InputSamplerDesc samplerDesc; ArrayDesc arrayDesc; bool isOutput = false; bool onlyCPULikeBinding = false; ///< If true, only use on targets that have 'uniform' or 'CPU like' binding, like CPU and CUDA - + bool isBindlessObject = false; ///< If true, this is a bindless object with no associated binding point in the shader. Slang::String name; ///< Optional name. Useful for binding through reflection. }; |
