diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/hlsl.meta.slang | 54 | ||||
| -rw-r--r-- | source/slang/slang-capabilities.capdef | 7 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-emit-metal.cpp | 53 | ||||
| -rw-r--r-- | source/slang/slang-emit-metal.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-emit-spirv.cpp | 87 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts-stable-names.lua | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.lua | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 2 |
9 files changed, 190 insertions, 20 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 35d210da6..bf5039905 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -17181,7 +17181,7 @@ ${{{{ // If a 'Texture[index]' is referred to by a '__ref', call 'kIROp_ImageSubscript(index)'. // This allows call's to stay aware that the input is from a 'Texture'. __intrinsic_op($(kIROp_ImageSubscript)) - [nonmutating] + [constref] ref; ${{{{ } // access != SLANG_RESOURCE_ACCESS_READ @@ -22921,14 +22921,51 @@ struct DescriptorHandle<T:IOpaqueDescriptor> : IComparable __intrinsic_op($(kIROp_CastUInt2ToDescriptorHandle)) __init(uint2 handleValue); + /// Constructor for uint64_t handles [ForceInline] - bool equals(DescriptorHandle<T> other) { return all(__vectorEql((uint2)this, (uint2)other)); } + [require(spvBindlessTextureNV)] + __intrinsic_op($(kIROp_CastUInt64ToDescriptorHandle)) + __init(uint64_t handleValue); [ForceInline] - bool lessThan(DescriptorHandle<T> other) { let vthis = ((uint2)this); let vother = (uint2)other; return vthis.x < vother.x || (vthis.x == vother.x && vthis.y < vother.y); } + bool equals(DescriptorHandle<T> other) + { + __target_switch + { + case spvBindlessTextureNV: + return (uint64_t)this == (uint64_t)other; + default: + return all(__vectorEql((uint2)this, (uint2)other)); + } + } [ForceInline] - bool lessThanOrEquals(DescriptorHandle<T> other) { let vthis = ((uint2)this); let vother = (uint2)other; return vthis.x < vother.x || (vthis.x == vother.x && vthis.y <= vother.y); } + bool lessThan(DescriptorHandle<T> other) + { + __target_switch + { + case spvBindlessTextureNV: + return (uint64_t)this < (uint64_t)other; + default: + let vthis = ((uint2)this); + let vother = (uint2)other; + return vthis.x < vother.x || (vthis.x == vother.x && vthis.y < vother.y); + } + } + + [ForceInline] + bool lessThanOrEquals(DescriptorHandle<T> other) + { + __target_switch + { + case spvBindlessTextureNV: + return (uint64_t)this <= (uint64_t)other; + default: + let vthis = ((uint2)this); + let vother = (uint2)other; + return vthis.x < vother.x || (vthis.x == vother.x && vthis.y <= vother.y); + } + } } extension uint2 @@ -22940,6 +22977,13 @@ extension uint2 __init<T:IOpaqueDescriptor>(DescriptorHandle<T> bindless); } +extension uint64_t +{ + __intrinsic_op($(kIROp_CastDescriptorHandleToUInt64)) + [require(spvBindlessTextureNV)] + __init<T:IOpaqueDescriptor>(DescriptorHandle<T> bindless); +} + __generic<T:IOpaqueDescriptor> [ForceInline] __prefix T operator*(DescriptorHandle<T> value) @@ -23015,6 +23059,8 @@ T defaultGetDescriptorFromHandle<T:IOpaqueDescriptor>(DescriptorHandle<T> handle return __makeCombinedTextureSamplerFromHandle<T>((uint2)handleValue); else return __loadResourceDescriptorFromHeap<T>(((uint2)handleValue).x); + case spvBindlessTextureNV: + return __castDescriptorHandleToResource<T>(handleValue); case spirv: case glsl: diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef index ff9697f7d..a747e701c 100644 --- a/source/slang/slang-capabilities.capdef +++ b/source/slang/slang-capabilities.capdef @@ -601,6 +601,9 @@ def SPV_NV_tensor_addressing : _spirv_1_6; /// [EXT] def SPV_NV_cooperative_matrix2 : SPV_NV_tensor_addressing + SPV_KHR_cooperative_matrix; +/// Represents the SPIR-V extension for SPV_NV_bindless_texture. +/// [EXT] +def SPV_NV_bindless_texture: _spirv_1_0; // SPIRV Capabilities. @@ -812,6 +815,10 @@ def spvVulkanMemoryModelKHR : SPV_KHR_vulkan_memory_model; /// [EXT] def spvVulkanMemoryModelDeviceScopeKHR : SPV_KHR_vulkan_memory_model; +/// Represents the SPIR-V capability for the bindless texture. +/// [EXT] +def spvBindlessTextureNV : SPV_NV_bindless_texture; + // The following capabilities all pertain to how ray tracing shaders are translated // to GLSL, where there are two different extensions that can provide the core // functionality of `TraceRay` and the related operations. diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index af4345942..08caedb94 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -2543,6 +2543,8 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO case kIROp_CastDescriptorHandleToUInt2: case kIROp_CastUInt2ToDescriptorHandle: case kIROp_CastDescriptorHandleToResource: + case kIROp_CastUInt64ToDescriptorHandle: + case kIROp_CastDescriptorHandleToUInt64: emitOperand(inst->getOperand(0), outerPrec); break; // Binary ops diff --git a/source/slang/slang-emit-metal.cpp b/source/slang/slang-emit-metal.cpp index b19e85044..71de65ee7 100644 --- a/source/slang/slang-emit-metal.cpp +++ b/source/slang/slang-emit-metal.cpp @@ -290,9 +290,35 @@ static IRImageSubscript* isTextureAccess(IRInst* inst) return as<IRImageSubscript>(getRootAddr(inst->getOperand(0))); } +void MetalSourceEmitter::emitImageOperandWithAccessor(IRInst* imageOperand) +{ + emitOperand(imageOperand, getInfo(EmitOp::Postfix)); + + // Check if the image operand is a pointer type + if (as<IRPtrTypeBase>(imageOperand->getDataType())) + { + m_writer->emit("->"); + } + else + { + m_writer->emit("."); + } +} + void MetalSourceEmitter::emitAtomicImageCoord(IRImageSubscript* inst) { - auto resourceType = as<IRResourceTypeBase>(inst->getImage()->getDataType()); + auto imageDataType = inst->getImage()->getDataType(); + auto resourceType = as<IRResourceTypeBase>(imageDataType); + + // If the image data type is a pointer, get the value type + if (!resourceType) + { + if (auto ptrType = as<IRPtrTypeBase>(imageDataType)) + { + resourceType = as<IRResourceTypeBase>(ptrType->getValueType()); + } + } + if (auto textureType = as<IRTextureType>(resourceType)) { if (as<IRVectorType>(textureType->getElementType())) @@ -303,7 +329,7 @@ void MetalSourceEmitter::emitAtomicImageCoord(IRImageSubscript* inst) "atomic operation on non-scalar texture"); } } - bool isArray = getIntVal(resourceType->getIsArrayInst()) != 0; + bool isArray = resourceType && getIntVal(resourceType->getIsArrayInst()) != 0; if (isArray) { emitOperand(inst->getCoord(), getInfo(EmitOp::Postfix)); @@ -375,8 +401,7 @@ bool MetalSourceEmitter::tryEmitInstStmtImpl(IRInst* inst) bool isImageOp = false; if (auto imageSubscript = isTextureAccess(inst)) { - emitOperand(imageSubscript->getImage(), getInfo(EmitOp::Postfix)); - m_writer->emit("."); + emitImageOperandWithAccessor(imageSubscript->getImage()); m_writer->emit(imageFunc); m_writer->emit("("); emitAtomicImageCoord(imageSubscript); @@ -439,8 +464,8 @@ bool MetalSourceEmitter::tryEmitInstStmtImpl(IRInst* inst) bool isImageOp = false; if (auto imageSubscript = isTextureAccess(inst)) { - emitOperand(imageSubscript->getImage(), getInfo(EmitOp::Postfix)); - m_writer->emit(".atomic_load("); + emitImageOperandWithAccessor(imageSubscript->getImage()); + m_writer->emit("atomic_load("); emitAtomicImageCoord(imageSubscript); isImageOp = true; } @@ -465,8 +490,8 @@ bool MetalSourceEmitter::tryEmitInstStmtImpl(IRInst* inst) bool isImageOp = false; if (auto imageSubscript = isTextureAccess(inst)) { - emitOperand(imageSubscript->getImage(), getInfo(EmitOp::Postfix)); - m_writer->emit(".atomic_store("); + emitImageOperandWithAccessor(imageSubscript->getImage()); + m_writer->emit("atomic_store("); emitAtomicImageCoord(imageSubscript); isImageOp = true; } @@ -515,8 +540,8 @@ bool MetalSourceEmitter::tryEmitInstStmtImpl(IRInst* inst) m_writer->emit(";\n"); if (imageSubscript) { - emitOperand(imageSubscript->getImage(), getInfo(EmitOp::Postfix)); - m_writer->emit(".atomic_compare_exchange_weak("); + emitImageOperandWithAccessor(imageSubscript->getImage()); + m_writer->emit("atomic_compare_exchange_weak("); emitAtomicImageCoord(imageSubscript); } else @@ -588,8 +613,8 @@ bool MetalSourceEmitter::tryEmitInstStmtImpl(IRInst* inst) bool isImageOp = false; if (auto imageSubscript = isTextureAccess(inst)) { - emitOperand(imageSubscript->getImage(), getInfo(EmitOp::Postfix)); - m_writer->emit(".atomic_fetch_add("); + emitImageOperandWithAccessor(imageSubscript->getImage()); + m_writer->emit("atomic_fetch_add("); emitAtomicImageCoord(imageSubscript); isImageOp = true; } @@ -616,8 +641,8 @@ bool MetalSourceEmitter::tryEmitInstStmtImpl(IRInst* inst) bool isImageOp = false; if (auto imageSubscript = isTextureAccess(inst)) { - emitOperand(imageSubscript->getImage(), getInfo(EmitOp::Postfix)); - m_writer->emit(".atomic_fetch_sub("); + emitImageOperandWithAccessor(imageSubscript->getImage()); + m_writer->emit("atomic_fetch_sub("); emitAtomicImageCoord(imageSubscript); isImageOp = true; } diff --git a/source/slang/slang-emit-metal.h b/source/slang/slang-emit-metal.h index eb63bd22e..e331234f7 100644 --- a/source/slang/slang-emit-metal.h +++ b/source/slang/slang-emit-metal.h @@ -97,6 +97,7 @@ protected: bool _emitUserSemantic(UnownedStringSlice semanticName, IRIntegerValue semanticIndex); bool maybeEmitSystemSemantic(IRInst* inst); + void emitImageOperandWithAccessor(IRInst* imageOperand); void emitAtomicImageCoord(IRImageSubscript* subscript); void emitAtomicDestOperand(IRInst* operand); void emitAtomicSrcOperand(bool isImage, IRInst* operand); diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 18c54587a..7b1bd66d8 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -1500,12 +1500,30 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex m_addressingMode, m_memoryModel); + // Emit OpSamplerImageAddressingModeNV if bindless texture capability is enabled + auto targetCaps = m_targetProgram->getTargetReq()->getTargetCaps(); + + if (targetCaps.implies(CapabilityAtom::spvBindlessTextureNV)) + { + requireSPIRVCapability((SpvCapability)SpvCapabilityBindlessTextureNV); + requireSPIRVCapability(SpvCapabilityInt64); // Required for 64-bit addressing mode + ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_bindless_texture")); + + emitInstCustomOperandFunc( + getSection(SpvLogicalSectionID::MemoryModel), + nullptr, + SpvOpSamplerImageAddressingModeNV, + [&]() + { + emitOperand(SpvWord(64)); // 64-bit addressing mode + }); + } + if (m_memoryModel == SpvMemoryModelVulkan) { requireSPIRVCapability(SpvCapabilityVulkanMemoryModel); ensureExtensionDeclaration(UnownedStringSlice("SPV_KHR_vulkan_memory_model")); - auto targetCaps = m_targetProgram->getTargetReq()->getTargetCaps(); if (targetCaps.implies(CapabilityAtom::spvVulkanMemoryModelDeviceScopeKHR)) { requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope); @@ -2129,7 +2147,25 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex { IRBuilder builder(inst); builder.setInsertBefore(inst); - return emitOpTypeVector(inst, builder.getUIntType(), SpvLiteralInteger::from32(2)); + auto targetCaps = m_targetProgram->getTargetReq()->getTargetCaps(); + + if (targetCaps.implies(CapabilityAtom::spvBindlessTextureNV)) + { + // For spvBindlessTextureNV, DescriptorHandleType should be a uint64_t + // (OpTypeInt 64 0) + return emitOpTypeInt( + inst, + SpvLiteralInteger::from32(64), + SpvLiteralInteger::from32(0)); + } + else + { + // For other targets, use uint2 (OpTypeVector of 2 uint32) + return emitOpTypeVector( + inst, + builder.getUIntType(), + SpvLiteralInteger::from32(2)); + } } case kIROp_SubpassInputType: return ensureSubpassInputType(inst, cast<IRSubpassInputType>(inst)); @@ -4154,12 +4190,59 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex case kIROp_CastDescriptorHandleToUInt2: case kIROp_CastUInt2ToDescriptorHandle: case kIROp_GlobalValueRef: + case kIROp_CastUInt64ToDescriptorHandle: + case kIROp_CastDescriptorHandleToUInt64: { auto inner = ensureInst(inst->getOperand(0)); registerInst(inst, inner); result = inner; break; } + case kIROp_CastDescriptorHandleToResource: + // Convert DescriptorHandle (uint64_t handle) to appropriate resource type + { + auto targetCaps = m_targetProgram->getTargetReq()->getTargetCaps(); + + if (targetCaps.implies(CapabilityAtom::spvBindlessTextureNV)) + { + requireSPIRVCapability((SpvCapability)SpvCapabilityBindlessTextureNV); + ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_bindless_texture")); + + auto operand = ensureInst(inst->getOperand(0)); + SpvOp conversionOp = SpvOpConvertUToSampledImageNV; + IRType* resultType = inst->getDataType(); + + switch (resultType->getOp()) + { + case kIROp_TextureType: + conversionOp = SpvOpConvertUToSampledImageNV; + result = emitInst( + parent, + inst, + conversionOp, + inst->getDataType(), + kResultID, + operand); + break; + case kIROp_SamplerStateType: + conversionOp = SpvOpConvertUToSamplerNV; + result = emitInst( + parent, + inst, + conversionOp, + inst->getDataType(), + kResultID, + operand); + break; + default: + // Unsupported result type for descriptor-to-resource conversion + SLANG_UNEXPECTED( + "Unsupported result type for CastDescriptorHandleToResource"); + break; + } + } + break; + } case kIROp_GetVulkanRayTracingPayloadLocation: { IRInst* location = getVulkanPayloadLocation(inst->getOperand(0)); diff --git a/source/slang/slang-ir-insts-stable-names.lua b/source/slang/slang-ir-insts-stable-names.lua index 589c4b130..b2c216bb4 100644 --- a/source/slang/slang-ir-insts-stable-names.lua +++ b/source/slang/slang-ir-insts-stable-names.lua @@ -670,4 +670,6 @@ return { ["SPIRVAsmOperand.__imageType"] = 666, ["SPIRVAsmOperand.__sampledImageType"] = 667, ["Type.CLayout"] = 668, + ["CastUInt64ToDescriptorHandle"] = 669, + ["CastDescriptorHandleToUInt64"] = 670, } diff --git a/source/slang/slang-ir-insts.lua b/source/slang/slang-ir-insts.lua index 6487f36d0..0ad02b87c 100644 --- a/source/slang/slang-ir-insts.lua +++ b/source/slang/slang-ir-insts.lua @@ -1891,6 +1891,8 @@ local insts = { { EnumCast = { min_operands = 1 } }, { CastUInt2ToDescriptorHandle = { min_operands = 1 } }, { CastDescriptorHandleToUInt2 = { min_operands = 1 } }, + { CastUInt64ToDescriptorHandle = { min_operands = 1 } }, + { CastDescriptorHandleToUInt64 = { min_operands = 1 } }, -- Represents a no-op cast to convert a resource pointer to a resource on targets where the resource handles are -- already concrete types. { CastDescriptorHandleToResource = { min_operands = 1 } }, diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index a61859a5e..e9d1a1199 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -8709,6 +8709,8 @@ bool IRInst::mightHaveSideEffects(SideEffectAnalysisOptions options) case kIROp_EnumCast: case kIROp_CastUInt2ToDescriptorHandle: case kIROp_CastDescriptorHandleToUInt2: + case kIROp_CastUInt64ToDescriptorHandle: + case kIROp_CastDescriptorHandleToUInt64: case kIROp_CastDescriptorHandleToResource: case kIROp_GetDynamicResourceHeap: case kIROp_CastDynamicResource: |
