diff options
| author | Theresa Foley <tfoleyNV@users.noreply.github.com> | 2021-06-25 15:50:29 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-06-25 15:50:29 -0700 |
| commit | 9dfaabe0fbcc9ac7314f84bde89c658b276298e3 (patch) | |
| tree | 8074c983b73860cac1ee7504f35b0f99aacb3dcd /source | |
| parent | 81c1692a63486578f25ecaed652eab0d370120ee (diff) | |
Fixes related to combined texture/sampler types (#1894)
* Fixes related to combined texture/sampler types
Work on #1891
Our intention has always been to support combined texture/sampler types in Slang, both targets like OpenGL where that is the only option available and for targets like Vulkan where it can be beneficial to performance. Because Slang's current users mostly focus on D3D12+Vulkan codebases, they strongly prefer separate textures and samplers, and the relevant support code in Slang has "bit-rotted" over many releases until the functionality that was there isn't useful any more.
This change significantly overhauls the implementation of combined texture/sampler types and adds a test that uses them in the hopes of avoiding future regressions.
The new combined texture/sampler types use the prefix `Sampler`, so where there is an existing standalone `Texture2D` type the equivalent combined texture/sampler type will be `Sampler2D`. The intention is that this naming mirrors the GLSL conventions (where the type is `sampler2d`) while following HLSL naming precedent (to the extent it exists).
The operations available on a `Sampler2D` are intended to be those that are available on a `Texture2D`, and it is just that in cases where the `Texture2D` operation would take a separate sampler argument:
Texture2D t = ...;
SamplerState s = ...;
float4 result = t.Sample(s, uv);
the equivalent `Sampler2D` operation just elides that argument:
Sampler2D s = ...;
float4 result = s.Sample(uv);
In terms of implementation, there are a lot of subtle details here:
* I've tried to use the same metaprogramming logic that generates all the stdlib declarations for `Texture*` to also generate `Sampler*` in the hopes that this helps keep them in sync.
* The big catch to the above is that it means that for certain operations the indidces of parameters depend on whether or not an explicit sampler parameter is used. Rather than try to tweak the indices in the stdlib generation logic (which is already complicated) I went and added Yet Another Hack to the logic that handles intrinsic definition strings. Basically, the special-case handling of `$p` has been modified so that it *also* applies a negative offset to future parameter references in the same intrinsic string.
* Trying to actually bring this up in our test framework revealed that the "flat" reflection API was seemingly not reflecting combined texture/sampler types correctly at all (it was reflecting them as just plain textures). Other than that issue, the Vulkan path seems to work fine with combined texture/samplers.
* I also had to add logic to the `TEST_INPUT` parsing to re-introduce handling of the combined types (that was something I consciously left out to reduce the amount of code in the earlier refactor there). Luckily, the architecture is such that a combined texture/sampler can leverage most of the existing logic for the separate cases.
* fixup: reveiw feedback
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/core.meta.slang | 146 | ||||
| -rw-r--r-- | source/slang/slang-intrinsic-expand.cpp | 87 | ||||
| -rw-r--r-- | source/slang/slang-intrinsic-expand.h | 20 | ||||
| -rw-r--r-- | source/slang/slang-reflection-api.cpp | 7 |
4 files changed, 134 insertions, 126 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 761316d86..d1dc25cc7 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -574,14 +574,14 @@ struct SamplerComparisonState ${{{{ static const struct { - char const* name; + char const* shapeName; TextureFlavor::Shape baseShape; int coordCount; } kBaseTextureTypes[] = { - { "Texture1D", TextureFlavor::Shape::Shape1D, 1 }, - { "Texture2D", TextureFlavor::Shape::Shape2D, 2 }, - { "Texture3D", TextureFlavor::Shape::Shape3D, 3 }, - { "TextureCube", TextureFlavor::Shape::ShapeCube, 3 }, + { "1D", TextureFlavor::Shape::Shape1D, 1 }, + { "2D", TextureFlavor::Shape::Shape2D, 2 }, + { "3D", TextureFlavor::Shape::Shape3D, 3 }, + { "Cube", TextureFlavor::Shape::ShapeCube,3 }, }; static const int kBaseTextureTypeCount = sizeof(kBaseTextureTypes) / sizeof(kBaseTextureTypes[0]); @@ -596,79 +596,21 @@ static const struct { }; static const int kBaseTextureAccessLevelCount = sizeof(kBaseTextureAccessLevels) / sizeof(kBaseTextureAccessLevels[0]); -// Declare the GLSL types here for compatibility... -// -// TODO: The stdlib should include a module that declares the GLSL types, to keep -// them separate... -for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) +static const struct TextureTypePrefixInfo { - char const* name = kBaseTextureTypes[tt].name; - TextureFlavor::Shape baseShape = kBaseTextureTypes[tt].baseShape; - - for (int isArray = 0; isArray < 2; ++isArray) - { - // Arrays of 3D textures aren't allowed - if (isArray && baseShape == TextureFlavor::Shape::Shape3D) continue; - - for (int isMultisample = 0; isMultisample < 2; ++isMultisample) - { - for (int accessLevel = 0; accessLevel < kBaseTextureAccessLevelCount; ++accessLevel) - { - auto access = kBaseTextureAccessLevels[accessLevel].access; - - // No such thing as RWTextureCube - if (access == SLANG_RESOURCE_ACCESS_READ_WRITE && baseShape == TextureFlavor::Shape::ShapeCube) - { - continue; - } - - // TODO: any constraints to enforce on what gets to be multisampled? - - unsigned flavor = baseShape; - if (isArray) flavor |= TextureFlavor::ArrayFlag; - if (isMultisample) flavor |= TextureFlavor::MultisampleFlag; - // if (isShadow) flavor |= TextureFlavor::ShadowFlag; - - flavor |= (access << 8); - - // emit a generic signature - // TODO: allow for multisample count to come in as well... - sb << "__generic<T = float4> "; - - sb << "__magic_type(TextureSampler," << int(flavor) << ")\n"; - sb << "__intrinsic_type(" << (kIROp_TextureSamplerType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n"; - sb << "struct Sampler"; - sb << kBaseTextureAccessLevels[accessLevel].name; - sb << name; - if (isMultisample) sb << "MS"; - if (isArray) sb << "Array"; - // if (isShadow) sb << "Shadow"; - sb << "\n{\n"; - sb << "__specialized_for_target(glsl)\n"; - sb << "__init("; - sb << kBaseTextureAccessLevels[accessLevel].name; - sb << name; - if (isMultisample) sb << "MS"; - if (isArray) sb << "Array"; - sb << "<T> t, "; - sb << "SamplerState s);\n"; - sb << "};\n"; - - sb << "__specialized_for_target(glsl)\n"; - sb << "T texture<T>(Sampler"; - sb << kBaseTextureAccessLevels[accessLevel].name; - sb << name; - if (isMultisample) sb << "MS"; - if (isArray) sb << "Array"; - sb << "<T> t, float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n"; - } - } - } -} + char const* name; + bool combined; +} kTexturePrefixes[] = +{ + { "Texture", false }, + { "Sampler", true }, +}; +for(auto& prefixInfo : kTexturePrefixes) for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) { - char const* name = kBaseTextureTypes[tt].name; + char const* baseName = prefixInfo.name; + char const* baseShapeName = kBaseTextureTypes[tt].shapeName; TextureFlavor::Shape baseShape = kBaseTextureTypes[tt].baseShape; for (int isArray = 0; isArray < 2; ++isArray) @@ -701,22 +643,33 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) // TODO: allow for multisample count to come in as well... sb << "__generic<T = float4> "; - sb << "__magic_type(Texture," << int(flavor) << ")\n"; - sb << "__intrinsic_type(" << (kIROp_TextureType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n"; + if(prefixInfo.combined) + { + sb << "__magic_type(TextureSampler," << int(flavor) << ")\n"; + sb << "__intrinsic_type(" << (kIROp_TextureSamplerType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n"; + } + else + { + sb << "__magic_type(Texture," << int(flavor) << ")\n"; + sb << "__intrinsic_type(" << (kIROp_TextureType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n"; + } sb << "struct "; sb << kBaseTextureAccessLevels[accessLevel].name; - sb << name; + sb << baseName; + sb << baseShapeName; if (isMultisample) sb << "MS"; if (isArray) sb << "Array"; // if (isShadow) sb << "Shadow"; sb << "\n{"; + char const* samplerStateParam = prefixInfo.combined ? "" : "SamplerState s, "; + if( !isMultisample ) { - sb << "float CalculateLevelOfDetail(SamplerState s, "; + sb << "float CalculateLevelOfDetail(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n"; - sb << "float CalculateLevelOfDetailUnclamped(SamplerState s, "; + sb << "float CalculateLevelOfDetailUnclamped(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n"; } @@ -1235,18 +1188,18 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } } - sb << "T Sample(SamplerState s, "; + sb << "T Sample(" << samplerStateParam;; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n"; if( baseShape != TextureFlavor::Shape::ShapeCube ) { sb << "__target_intrinsic(glsl, \"$ctextureOffset($p, $2, $3)$z\")\n"; - sb << "T Sample(SamplerState s, "; + sb << "T Sample(" << samplerStateParam;; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; } - sb << "T Sample(SamplerState s, "; + sb << "T Sample(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; if( baseShape != TextureFlavor::Shape::ShapeCube ) { @@ -1254,7 +1207,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } sb << "float clamp);\n"; - sb << "T Sample(SamplerState s, "; + sb << "T Sample(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; if( baseShape != TextureFlavor::Shape::ShapeCube ) { @@ -1264,13 +1217,13 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) // `SampleBias()` sb << "__target_intrinsic(glsl, \"$ctexture($p, $2, $3)$z\")\n"; - sb << "T SampleBias(SamplerState s, "; + sb << "T SampleBias(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, float bias);\n"; if( baseShape != TextureFlavor::Shape::ShapeCube ) { sb << "__target_intrinsic(glsl, \"$ctextureOffset($p, $2, $3, $4)$z\")\n"; - sb << "T SampleBias(SamplerState s, "; + sb << "T SampleBias(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, float bias, "; sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; } @@ -1355,7 +1308,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) // the dimension. On CUDA there is texNDGrad, but it always just takes ddx, ddy. // I could just assume 0 for elements not supplied, and ignore z. For now will just leave sb << "__target_intrinsic(glsl, \"$ctextureGrad($p, $2, $3, $4)$z\")\n"; - sb << "T SampleGrad(SamplerState s, "; + sb << "T SampleGrad(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradY"; @@ -1364,7 +1317,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) if( baseShape != TextureFlavor::Shape::ShapeCube ) { sb << "__target_intrinsic(glsl, \"$ctextureGradOffset($p, $2, $3, $4, $5)$z\")\n"; - sb << "T SampleGrad(SamplerState s, "; + sb << "T SampleGrad(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradY, "; @@ -1372,7 +1325,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__glsl_extension(GL_ARB_sparse_texture_clamp)"; sb << "__target_intrinsic(glsl, \"$ctextureGradOffsetClampARB($p, $2, $3, $4, $5, $6)$z\")\n"; - sb << "T SampleGrad(SamplerState s, "; + sb << "T SampleGrad(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradY, "; @@ -1428,14 +1381,14 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } } - sb << "T SampleLevel(SamplerState s, "; + sb << "T SampleLevel(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float level);\n"; if( baseShape != TextureFlavor::Shape::ShapeCube ) { sb << "__target_intrinsic(glsl, \"$ctextureLodOffset($p, $2, $3, $4)$z\")\n"; - sb << "T SampleLevel(SamplerState s, "; + sb << "T SampleLevel(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float level, "; sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; @@ -1474,7 +1427,8 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) EMIT_LINE_DIRECTIVE(); sb << cc.genericPrefix << " __extension "; sb << kBaseTextureAccessLevels[accessLevel].name; - sb << name; + sb << baseName; + sb << baseShapeName; if (isArray) sb << "Array"; sb << "<" << cc.elementType << " >"; sb << "\n{\n"; @@ -1513,24 +1467,24 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) // "It is based on the base type of DataType except when readMode is equal to cudaReadModeNormalizedFloat (see Texture Reference API), in which case it is always float4." sb << "__target_intrinsic(cuda, \"tex2Dgather<$T0>($0, ($2).x, ($2).y, " << componentIndex << ")\")\n"; } - sb << outputType << " Gather" << componentName << "(SamplerState s, "; + sb << outputType << " Gather" << componentName << "(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n"; EMIT_LINE_DIRECTIVE(); sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $2, $3, " << componentIndex << ")\")\n"; - sb << outputType << " Gather" << componentName << "(SamplerState s, "; + sb << outputType << " Gather" << componentName << "(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; EMIT_LINE_DIRECTIVE(); - sb << outputType << " Gather" << componentName << "(SamplerState s, "; + sb << outputType << " Gather" << componentName << "(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset, "; sb << "out uint status);\n"; EMIT_LINE_DIRECTIVE(); sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $2, int" << kBaseTextureTypes[tt].coordCount << "[]($3, $4, $5, $6), " << componentIndex << ")\")\n"; - sb << outputType << " Gather" << componentName << "(SamplerState s, "; + sb << outputType << " Gather" << componentName << "(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset1, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset2, "; @@ -1538,7 +1492,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "int" << kBaseTextureTypes[tt].coordCount << " offset4);\n"; EMIT_LINE_DIRECTIVE(); - sb << outputType << " Gather" << componentName << "(SamplerState s, "; + sb << outputType << " Gather" << componentName << "(" << samplerStateParam; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset1, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset2, "; diff --git a/source/slang/slang-intrinsic-expand.cpp b/source/slang/slang-intrinsic-expand.cpp index 045b7e6c5..b494e71e1 100644 --- a/source/slang/slang-intrinsic-expand.cpp +++ b/source/slang/slang-intrinsic-expand.cpp @@ -228,7 +228,7 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) case '5': case '6': case '7': case '8': case '9': { // Simple case: emit one of the direct arguments to the call - Index argIndex = d - '0'; + Index argIndex = d - '0' + m_argIndexOffset; SLANG_RELEASE_ASSERT((0 <= argIndex) && (argIndex < m_argCount)); m_writer->emit("("); m_emitter->emitOperand(m_args[argIndex].get(), getInfo(EmitOp::General)); @@ -241,7 +241,7 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) // Get the type/value at the index of the specialization of this generic SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9'); - Index argIndex = (*cursor++) - '0'; + Index argIndex = (*cursor++) - '0' + m_argIndexOffset; IRSpecialize* specialize = as<IRSpecialize>(m_callInst->getCallee()); SLANG_ASSERT(specialize); @@ -269,7 +269,7 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) // Get the the 'element' type for the type of the param at the index { SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9'); - Index argIndex = (*cursor++) - '0'; + Index argIndex = (*cursor++) - '0' + m_argIndexOffset; SLANG_RELEASE_ASSERT(m_argCount > argIndex); IRType* type = m_args[argIndex].get()->getDataType(); @@ -285,7 +285,7 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) // Get the scalar type of a generic at specified index { SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9'); - Index argIndex = (*cursor++) - '0'; + Index argIndex = (*cursor++) - '0' + m_argIndexOffset; SLANG_RELEASE_ASSERT(m_argCount > argIndex); IRType* type = m_args[argIndex].get()->getDataType(); @@ -318,15 +318,37 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) // If we are calling a D3D texturing operation in the form t.Foo(s, ...), // then this form will pair up the t and s arguments as needed for a GLSL // texturing operation. - SLANG_RELEASE_ASSERT(m_argCount >= 2); + SLANG_RELEASE_ASSERT(m_argCount >= 1); auto textureArg = m_args[0].get(); - auto samplerArg = m_args[1].get(); - if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) + if (auto baseTextureSamplerType = as<IRTextureSamplerType>(textureArg->getDataType())) { - m_emitter->emitTextureOrTextureSamplerType(baseTextureType, "sampler"); + // If the base object (first argument) has a combined texture-sampler type, + // then we can simply use that argument as-is. + // + m_emitter->emitOperand(textureArg, getInfo(EmitOp::General)); + + // HACK: Because the target intrinsic strings are using indices based on the + // parameter list with the `SamplerState` parameter in place, seeing this opcode + // and this type tells us that we are about to have an off-by-one sort of + // situation. We quietly patch it up by offseting the index-based access for + // all the other operands. + // + m_argIndexOffset -= 1; + } + else if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) + { + // If the base object (first argument) has a texture type, then we expect + // the next argument to be a sampler to pair with it. + // + SLANG_RELEASE_ASSERT(m_argCount >= 2); + auto samplerArg = m_args[1].get(); + // We will emit GLSL code to construct the corresponding combined texture/sampler + // type from the separate pieces. + // + m_emitter->emitTextureOrTextureSamplerType(baseTextureType, "sampler"); if (auto samplerType = as<IRSamplerStateTypeBase>(samplerArg->getDataType())) { if (as<IRSamplerComparisonStateType>(samplerType)) @@ -462,32 +484,41 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) SLANG_RELEASE_ASSERT(m_argCount >= 1); auto textureArg = m_args[0].get(); + IRType* elementType = nullptr; + if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) { - auto elementType = baseTextureType->getElementType(); - if (auto basicType = as<IRBasicType>(elementType)) - { - // A scalar result is expected - m_writer->emit(".x"); - } - else if (auto vectorType = as<IRVectorType>(elementType)) - { - // A vector result is expected - auto elementCount = getIntVal(vectorType->getElementCount()); + elementType = baseTextureType->getElementType(); + } + else if(auto baseTextureSamplerType = as<IRTextureSamplerType>(textureArg->getDataType())) + { + elementType = baseTextureSamplerType->getElementType(); + } + else + { + SLANG_UNEXPECTED("bad format in intrinsic definition"); + } - if (elementCount < 4) - { - char const* swiz[] = { "", ".x", ".xy", ".xyz", "" }; - m_writer->emit(swiz[elementCount]); - } - } - else + SLANG_ASSERT(elementType); + if (auto basicType = as<IRBasicType>(elementType)) + { + // A scalar result is expected + m_writer->emit(".x"); + } + else if (auto vectorType = as<IRVectorType>(elementType)) + { + // A vector result is expected + auto elementCount = getIntVal(vectorType->getElementCount()); + + if (elementCount < 4) { - // What other cases are possible? + char const* swiz[] = { "", ".x", ".xy", ".xyz", "" }; + m_writer->emit(swiz[elementCount]); } } else { + // What other cases are possible? SLANG_UNEXPECTED("bad format in intrinsic definition"); } } @@ -499,7 +530,7 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) // we can use it in the constructed expression. SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9'); - Index argIndex = (*cursor++) - '0'; + Index argIndex = (*cursor++) - '0' + m_argIndexOffset; SLANG_RELEASE_ASSERT(m_argCount > argIndex); auto vectorArg = m_args[argIndex].get(); @@ -522,7 +553,7 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor) // (this is the inverse of `$z`). // SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9'); - Index argIndex = (*cursor++) - '0'; + Index argIndex = (*cursor++) - '0' + m_argIndexOffset; SLANG_RELEASE_ASSERT(m_argCount > argIndex); auto arg = m_args[argIndex].get(); diff --git a/source/slang/slang-intrinsic-expand.h b/source/slang/slang-intrinsic-expand.h index b52e3e8f5..cf072e3f4 100644 --- a/source/slang/slang-intrinsic-expand.h +++ b/source/slang/slang-intrinsic-expand.h @@ -29,6 +29,26 @@ protected: Int m_argCount = 0; Index m_openParenCount = 0; CLikeSourceEmitter* m_emitter; + + // An arbitrary offset to apply to argument indices. + // + // Note: This is a bit of a gross hack to allow the definitions + // of the texture-sampling operations to be easier to share + // between combined and non-combined cases. + // + // TODO: It would be great to slowly migrate away from needing + // so much complicated logic here, but if we decide to keep this + // general approach it would be great to move some of the processing + // to the front-end and allow things like: + // + // __target_intrinsic(hlsl, "specialOp($a - $b)") + // int SomeCoolFunction(int a, int b); + // + // That is, we could try to allow direct by-name references to parameters + // in the intrinsic strings as they appear in the front-end, and then remap + // those to be index-based as part of translation to the IR. + // + Index m_argIndexOffset = 0; }; } diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp index 00ecfdbc1..17ceb6842 100644 --- a/source/slang/slang-reflection-api.cpp +++ b/source/slang/slang-reflection-api.cpp @@ -1231,7 +1231,11 @@ namespace Slang SlangBindingType _calcResourceBindingType( Type* type) { - if( auto resourceType = as<ResourceType>(type) ) + if(auto combinedTextureSamplerType = as<TextureSamplerType>(type)) + { + return SLANG_BINDING_TYPE_COMBINED_TEXTURE_SAMPLER; + } + else if( auto resourceType = as<ResourceType>(type) ) { auto shape = resourceType->getBaseShape(); @@ -1246,7 +1250,6 @@ namespace Slang case SLANG_TEXTURE_BUFFER: return SLANG_BINDING_TYPE_TYPED_BUFFER | mutableFlag; } - } else if( auto structuredBufferType = as<HLSLStructuredBufferTypeBase>(type) ) { |
