summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2020-10-09 11:29:11 -0700
committerGitHub <noreply@github.com>2020-10-09 11:29:11 -0700
commitfab1c9f4c745ba84983c2448646376799d461e96 (patch)
tree3176c03987417c01b7220aaf13c35b665813c876
parent11f331771a8d5d80bc1dd317dcad5eb815e9cb55 (diff)
Support CUDA bindless texture in dynamic dispatch code. (#1575)
-rw-r--r--source/slang/slang-emit-c-like.cpp10
-rw-r--r--source/slang/slang-ir-any-value-marshalling.cpp51
-rw-r--r--source/slang/slang-ir-inst-defs.h1
-rw-r--r--source/slang/slang-ir-insts.h5
-rw-r--r--source/slang/slang-ir.cpp26
-rw-r--r--tests/compute/dynamic-dispatch-bindless-texture.slang40
-rw-r--r--tests/compute/dynamic-dispatch-bindless-texture.slang.expected.txt4
-rw-r--r--tools/render-test/cpu-compute-util.cpp150
-rw-r--r--tools/render-test/cpu-compute-util.h12
-rw-r--r--tools/render-test/cuda/cuda-compute-util.cpp134
-rw-r--r--tools/render-test/cuda/cuda-compute-util.h3
-rw-r--r--tools/render-test/render-test-main.cpp3
-rw-r--r--tools/render-test/shader-input-layout.cpp21
-rw-r--r--tools/render-test/shader-input-layout.h9
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.
};