diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-02-07 13:41:43 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-02-07 13:41:43 -0800 |
| commit | 1fbc73d96fbc0a199d823dfb38fc8f02bf7ada0a (patch) | |
| tree | b4d894f1179a66219631539a95e422ba62988b04 | |
| parent | 662f43fff6721c6cd013a8f1b2639c2e29fe6be3 (diff) | |
Support __target_intrinsic modifiers in IR codegen (#401)
The standard library already has a bunch of these decorations, since they were added to support Slang->Vulkan codegen on the AST-to-AST path. This change makes the IR code generator able to exploit the modifiers so that we pick up a bunch of Vulkan support "for free" in the short term.
The basic change is in `lower-to-ir.cpp` where we copy over any `TargetIntrinsicModifier`s to become `IRTargetIntrinsicDecoration`s with the same information. We then need a bit of logic in `ir.cpp` to make sure we clone them as needed.
The core work of using the modifiers is in `emit.cpp`, where I basically just copy-pasted the existing logic that applied in the AST path (all the AST-related code there is dead, and we should clean it up soon).
The big change that comes with this logic is that when dealing with a member function, the numbering of the argument used in the intrinsic definition string changes, so that `$0` refers to the base object (whereas before the base object was looked up via the base expression of a `MemberExpr` used for the function). This requires a bunch of the definitions in the library to be updated; hopefully I caught them all.
For kicks, I've re-enabled a cross-compilation test just to confirm that we are generating valid SPIR-V for code that performs texture-fetch operations. I don't expect us to keep that test enabled as-is in the long term, though, because it would be much better to instead use render-test to do the same thing. Alas, beefing up the Vulkan support in render-test is an outstanding work item, and I didn't want to pollute this change with more work along those lines.
| -rw-r--r-- | source/slang/core.meta.slang | 50 | ||||
| -rw-r--r-- | source/slang/core.meta.slang.h | 50 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 247 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 4 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang.h | 4 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 17 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 9 | ||||
| -rw-r--r-- | source/slang/ir.h | 1 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 18 | ||||
| -rw-r--r-- | tests/bindings/glsl-parameter-blocks.slang | 2 | ||||
| -rw-r--r-- | tests/bindings/glsl-parameter-blocks.slang.glsl | 37 |
11 files changed, 346 insertions, 93 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 2285b16ab..13b41bce6 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -461,7 +461,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__glsl_version(450)\n"; sb << "__target_intrinsic(glsl, \"("; - int aa = 0; + int aa = 1; String lodStr = "0"; if (includeMipInfo) { @@ -582,11 +582,11 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) if (isMultisample) { - sb << "__target_intrinsic(glsl, \"texelFetch($$P, $0, $1)\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($$P, $1, $3)\")\n"; } else { - sb << "__target_intrinsic(glsl, \"texelFetch($$P, ($0)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($0)." << kGLSLLoadLODSwizzle[loadCoordCount] << ")\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($$P, ($1)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($1)." << kGLSLLoadLODSwizzle[loadCoordCount] << ")\")\n"; } sb << "T Load("; sb << "int" << loadCoordCount << " location"; @@ -602,7 +602,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } else { - sb << "__target_intrinsic(glsl, \"texelFetch($$P, ($0)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($0)." << kGLSLLoadLODSwizzle[loadCoordCount] << ", $1)\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($$P, ($1)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($1)." << kGLSLLoadLODSwizzle[loadCoordCount] << ", $2)\")\n"; } sb << "T Load("; sb << "int" << loadCoordCount << " location"; @@ -643,7 +643,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) { // `Sample()` -// sb << "__target_intrinsic(glsl, \"texture($$p, $1)\")\n"; + sb << "__target_intrinsic(glsl, \"texture($$p, $2)\")\n"; // TODO: only enable if IR is being used? // sb << "__intrinsic_op(sample)\n"; @@ -651,21 +651,9 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "T Sample(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n"; - // Specialized definition for GLSL - sb << "__specialized_for_target(glsl)\n"; - sb << "T Sample(SamplerState s, "; - sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location) {\n"; - sb << " return texture<T>(Sampler"; - sb << kBaseTextureAccessLevels[accessLevel].name; - sb << name; - if (isMultisample) sb << "MS"; - if (isArray) sb << "Array"; - sb << "<T>(this, s), location);\n"; - sb << "}\n"; - if( baseShape != TextureType::ShapeCube ) { - sb << "__target_intrinsic(glsl, \"textureOffset($$p, $1, $2)\")\n"; + sb << "__target_intrinsic(glsl, \"textureOffset($$p, $2, $3)\")\n"; sb << "T Sample(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; @@ -689,13 +677,13 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) // `SampleBias()` - sb << "__target_intrinsic(glsl, \"texture($$p, $1, $2)\")\n"; + sb << "__target_intrinsic(glsl, \"texture($$p, $2, $3)\")\n"; sb << "T SampleBias(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, float bias);\n"; if( baseShape != TextureType::ShapeCube ) { - sb << "__target_intrinsic(glsl, \"textureOffset($$p, $1, $2, $3)\")\n"; + sb << "__target_intrinsic(glsl, \"textureOffset($$p, $2, $3, $4)\")\n"; sb << "T SampleBias(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, float bias, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; @@ -718,12 +706,12 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__target_intrinsic(glsl, \"textureLod($$p, "; - sb << "vec" << extCoordCount << "($1,"; + sb << "vec" << extCoordCount << "($2,"; for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii) { sb << " 0.0,"; } - sb << "$2)"; + sb << "$3)"; sb << ", 0.0)\")\n"; } @@ -736,12 +724,12 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__target_intrinsic(glsl, \"textureGrad($$p, "; - sb << "vec" << extCoordCount << "($1,"; + sb << "vec" << extCoordCount << "($2,"; for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii) { sb << " 0.0,"; } - sb << "$2)"; + sb << "$3)"; // Construct gradients sb << ", vec" << baseCoordCount << "(0.0)"; @@ -774,7 +762,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } - sb << "__target_intrinsic(glsl, \"textureGrad($$p, $1, $2, $3)\")\n"; + sb << "__target_intrinsic(glsl, \"textureGrad($$p, $2, $3, $4)\")\n"; // sb << "__intrinsic_op(sampleGrad)\n"; sb << "T SampleGrad(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; @@ -784,7 +772,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) if( baseShape != TextureType::ShapeCube ) { - sb << "__target_intrinsic(glsl, \"textureGradOffset($$p, $1, $2, $3, $4)\")\n"; + sb << "__target_intrinsic(glsl, \"textureGradOffset($$p, $2, $3, $4, $5)\")\n"; // sb << "__intrinsic_op(sampleGrad)\n"; sb << "T SampleGrad(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; @@ -795,14 +783,14 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) // `SampleLevel` - sb << "__target_intrinsic(glsl, \"textureLod($$p, $1, $2)\")\n"; + sb << "__target_intrinsic(glsl, \"textureLod($$p, $2, $3)\")\n"; sb << "T SampleLevel(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float level);\n"; if( baseShape != TextureType::ShapeCube ) { - sb << "__target_intrinsic(glsl, \"textureLodOffset($$p, $1, $2, $3)\")\n"; + sb << "__target_intrinsic(glsl, \"textureLodOffset($$p, $2, $3, $4)\")\n"; sb << "T SampleLevel(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float level, "; @@ -869,12 +857,12 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) EMIT_LINE_DIRECTIVE(); - sb << "__target_intrinsic(glsl, \"textureGather($$p, $1, " << componentIndex << ")\")\n"; + sb << "__target_intrinsic(glsl, \"textureGather($$p, $2, " << componentIndex << ")\")\n"; sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n"; EMIT_LINE_DIRECTIVE(); - sb << "__target_intrinsic(glsl, \"textureGatherOffset($$p, $1, $2, " << componentIndex << ")\")\n"; + sb << "__target_intrinsic(glsl, \"textureGatherOffset($$p, $2, $3, " << componentIndex << ")\")\n"; sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; @@ -886,7 +874,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "out uint status);\n"; EMIT_LINE_DIRECTIVE(); - sb << "__target_intrinsic(glsl, \"textureGatherOffsets($$p, $1, int" << kBaseTextureTypes[tt].coordCount << "[]($2, $3, $4, $5), " << componentIndex << ")\")\n"; + sb << "__target_intrinsic(glsl, \"textureGatherOffsets($$p, $2, int" << kBaseTextureTypes[tt].coordCount << "[]($3, $4, $5, $6), " << componentIndex << ")\")\n"; sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset1, "; diff --git a/source/slang/core.meta.slang.h b/source/slang/core.meta.slang.h index 53e1f202e..84a1abbf0 100644 --- a/source/slang/core.meta.slang.h +++ b/source/slang/core.meta.slang.h @@ -464,7 +464,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__glsl_version(450)\n"; sb << "__target_intrinsic(glsl, \"("; - int aa = 0; + int aa = 1; String lodStr = "0"; if (includeMipInfo) { @@ -585,11 +585,11 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) if (isMultisample) { - sb << "__target_intrinsic(glsl, \"texelFetch($P, $0, $1)\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($P, $1, $3)\")\n"; } else { - sb << "__target_intrinsic(glsl, \"texelFetch($P, ($0)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($0)." << kGLSLLoadLODSwizzle[loadCoordCount] << ")\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($P, ($1)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($1)." << kGLSLLoadLODSwizzle[loadCoordCount] << ")\")\n"; } sb << "T Load("; sb << "int" << loadCoordCount << " location"; @@ -605,7 +605,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } else { - sb << "__target_intrinsic(glsl, \"texelFetch($P, ($0)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($0)." << kGLSLLoadLODSwizzle[loadCoordCount] << ", $1)\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($P, ($1)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($1)." << kGLSLLoadLODSwizzle[loadCoordCount] << ", $2)\")\n"; } sb << "T Load("; sb << "int" << loadCoordCount << " location"; @@ -646,7 +646,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) { // `Sample()` -// sb << "__target_intrinsic(glsl, \"texture($p, $1)\")\n"; + sb << "__target_intrinsic(glsl, \"texture($p, $2)\")\n"; // TODO: only enable if IR is being used? // sb << "__intrinsic_op(sample)\n"; @@ -654,21 +654,9 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "T Sample(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n"; - // Specialized definition for GLSL - sb << "__specialized_for_target(glsl)\n"; - sb << "T Sample(SamplerState s, "; - sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location) {\n"; - sb << " return texture<T>(Sampler"; - sb << kBaseTextureAccessLevels[accessLevel].name; - sb << name; - if (isMultisample) sb << "MS"; - if (isArray) sb << "Array"; - sb << "<T>(this, s), location);\n"; - sb << "}\n"; - if( baseShape != TextureType::ShapeCube ) { - sb << "__target_intrinsic(glsl, \"textureOffset($p, $1, $2)\")\n"; + sb << "__target_intrinsic(glsl, \"textureOffset($p, $2, $3)\")\n"; sb << "T Sample(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; @@ -692,13 +680,13 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) // `SampleBias()` - sb << "__target_intrinsic(glsl, \"texture($p, $1, $2)\")\n"; + sb << "__target_intrinsic(glsl, \"texture($p, $2, $3)\")\n"; sb << "T SampleBias(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, float bias);\n"; if( baseShape != TextureType::ShapeCube ) { - sb << "__target_intrinsic(glsl, \"textureOffset($p, $1, $2, $3)\")\n"; + sb << "__target_intrinsic(glsl, \"textureOffset($p, $2, $3, $4)\")\n"; sb << "T SampleBias(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, float bias, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; @@ -721,12 +709,12 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__target_intrinsic(glsl, \"textureLod($p, "; - sb << "vec" << extCoordCount << "($1,"; + sb << "vec" << extCoordCount << "($2,"; for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii) { sb << " 0.0,"; } - sb << "$2)"; + sb << "$3)"; sb << ", 0.0)\")\n"; } @@ -739,12 +727,12 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__target_intrinsic(glsl, \"textureGrad($p, "; - sb << "vec" << extCoordCount << "($1,"; + sb << "vec" << extCoordCount << "($2,"; for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii) { sb << " 0.0,"; } - sb << "$2)"; + sb << "$3)"; // Construct gradients sb << ", vec" << baseCoordCount << "(0.0)"; @@ -777,7 +765,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } - sb << "__target_intrinsic(glsl, \"textureGrad($p, $1, $2, $3)\")\n"; + sb << "__target_intrinsic(glsl, \"textureGrad($p, $2, $3, $4)\")\n"; // sb << "__intrinsic_op(sampleGrad)\n"; sb << "T SampleGrad(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; @@ -787,7 +775,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) if( baseShape != TextureType::ShapeCube ) { - sb << "__target_intrinsic(glsl, \"textureGradOffset($p, $1, $2, $3, $4)\")\n"; + sb << "__target_intrinsic(glsl, \"textureGradOffset($p, $2, $3, $4, $5)\")\n"; // sb << "__intrinsic_op(sampleGrad)\n"; sb << "T SampleGrad(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; @@ -798,14 +786,14 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) // `SampleLevel` - sb << "__target_intrinsic(glsl, \"textureLod($p, $1, $2)\")\n"; + sb << "__target_intrinsic(glsl, \"textureLod($p, $2, $3)\")\n"; sb << "T SampleLevel(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float level);\n"; if( baseShape != TextureType::ShapeCube ) { - sb << "__target_intrinsic(glsl, \"textureLodOffset($p, $1, $2, $3)\")\n"; + sb << "__target_intrinsic(glsl, \"textureLodOffset($p, $2, $3, $4)\")\n"; sb << "T SampleLevel(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float level, "; @@ -872,12 +860,12 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) EMIT_LINE_DIRECTIVE(); - sb << "__target_intrinsic(glsl, \"textureGather($p, $1, " << componentIndex << ")\")\n"; + sb << "__target_intrinsic(glsl, \"textureGather($p, $2, " << componentIndex << ")\")\n"; sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n"; EMIT_LINE_DIRECTIVE(); - sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $1, $2, " << componentIndex << ")\")\n"; + sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $2, $3, " << componentIndex << ")\")\n"; sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; @@ -889,7 +877,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "out uint status);\n"; EMIT_LINE_DIRECTIVE(); - sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $1, int" << kBaseTextureTypes[tt].coordCount << "[]($2, $3, $4, $5), " << componentIndex << ")\")\n"; + sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $2, int" << kBaseTextureTypes[tt].coordCount << "[]($3, $4, $5, $6), " << componentIndex << ")\")\n"; sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " location, "; sb << "int" << kBaseTextureTypes[tt].coordCount << " offset1, "; diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 1ef42bdf0..f9f24fcf6 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -1559,6 +1559,20 @@ struct EmitVisitor emitUnaryExprImpl(outerPrec, prec, preOp, postOp, expr, true); } + bool isTargetIntrinsicModifierApplicable( + String const& targetName) + { + switch(context->shared->target) + { + default: + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled code generation target"); + return false; + + case CodeGenTarget::GLSL: return targetName == "glsl"; + case CodeGenTarget::HLSL: return targetName == "hlsl"; + } + } + // Determine if a target intrinsic modifer is applicable to the target // we are currently emitting code for. bool isTargetIntrinsicModifierApplicable( @@ -1575,17 +1589,23 @@ struct EmitVisitor // we expect. auto const& targetName = targetToken.Content; - switch(context->shared->target) - { - default: - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled code generation target"); - return false; + return isTargetIntrinsicModifierApplicable(targetName); + } - case CodeGenTarget::GLSL: return targetName == "glsl"; - case CodeGenTarget::HLSL: return targetName == "hlsl"; - } + bool isTargetIntrinsicModifierApplicable( + IRTargetIntrinsicDecoration* decoration) + { + auto targetName = decoration->targetName; + + // If no target name was specified, then the modifier implicitly + // applies to all targets. + if(targetName.Length() == 0) + return true; + + return isTargetIntrinsicModifierApplicable(targetName); } + // Find an intrinsic modifier appropriate to the current compilation target. // // If there are multiple such modifiers, this should return the best one. @@ -5414,6 +5434,205 @@ emitDeclImpl(decl, nullptr); } }; + IRTargetIntrinsicDecoration* findTargetIntrinsicDecoration( + EmitContext* /* ctx */, + IRFunc* func) + { + for (auto dd = func->firstDecoration; dd; dd = dd->next) + { + if (dd->op != kIRDecorationOp_TargetIntrinsic) + continue; + + auto targetIntrinsic = (IRTargetIntrinsicDecoration*)dd; + if (isTargetIntrinsicModifierApplicable(targetIntrinsic)) + return targetIntrinsic; + } + + return nullptr; + } + + void emitTargetIntrinsicCallExpr( + EmitContext* ctx, + IRCall* inst, + IRFunc* /* func */, + IRTargetIntrinsicDecoration* targetIntrinsic) + { + IRUse* args = inst->getArgs(); + UInt argCount = inst->getArgCount(); + + // First operand was the function to be called + args++; + argCount--; + + auto name = targetIntrinsic->definition; + + + if(name.IndexOf('$') == -1) + { + // Simple case: it is just an ordinary name, so we call it like a builtin. + + emit(name); + Emit("("); + for (UInt aa = 0; aa < argCount; ++aa) + { + if (aa != 0) Emit(", "); + emitIROperand(ctx, args[aa].usedValue); + } + Emit(")"); + return; + } + else + { + // General case: we are going to emit some more complex text. + + Emit("("); + + char const* cursor = name.begin(); + char const* end = name.end(); + while(cursor != end) + { + char c = *cursor++; + if( c != '$' ) + { + // Not an escape sequence + emitRawTextSpan(&c, &c+1); + continue; + } + + SLANG_RELEASE_ASSERT(cursor != end); + + char d = *cursor++; + + switch (d) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + // Simple case: emit one of the direct arguments to the call + UInt argIndex = d - '0'; + SLANG_RELEASE_ASSERT((0 <= argIndex) && (argIndex < argCount)); + Emit("("); + emitIROperand(ctx, args[argIndex].usedValue); + Emit(")"); + } + break; + + case 'p': + { + // 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(argCount >= 2); + + auto textureArg = args[0].usedValue; + auto samplerArg = args[1].usedValue; + + if (auto baseTextureType = textureArg->type->As<TextureType>()) + { + emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler"); + + if (auto samplerType = samplerArg->type->As<SamplerStateType>()) + { + if (samplerType->flavor == SamplerStateType::Flavor::SamplerComparisonState) + { + Emit("Shadow"); + } + } + + Emit("("); + emitIROperand(ctx, textureArg); + Emit(","); + emitIROperand(ctx, samplerArg); + Emit(")"); + } + else + { + SLANG_UNEXPECTED("bad format in intrinsic definition"); + } + } + break; + + case 'P': + { + // Okay, we need a collosal hack to deal with the fact that GLSL `texelFetch()` + // for Vulkan seems to be completely broken by design. It's signature wants + // a `sampler2D` for consistency with its peers, but the actual SPIR-V operation + // ignores the sampler paart of it, and just used the `texture2D` part. + // + // The HLSL equivalent (e.g., `Texture2D.Load()`) doesn't provide a sampler + // argument, so we seemingly need to conjure one out of thin air. :( + // + // We are going to hack this *hard* for now. + + auto textureArg = args[0].usedValue; + if (auto baseTextureType = textureArg->type->As<TextureType>()) + { + emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler"); + Emit("("); + emitIROperand(ctx, textureArg); + Emit(","); + Emit("SLANG_hack_samplerForTexelFetch"); + context->shared->needHackSamplerForTexelFetch = true; + Emit(")"); + } + else + { + SLANG_UNEXPECTED("bad format in intrinsic definition"); + } + } + break; + + case 'z': + { + // If we are calling a D3D texturing operation in the form t.Foo(s, ...), + // where `t` is a `Texture*<T>`, then this is the step where we try to + // properly swizzle the output of the equivalent GLSL call into the right + // shape. + SLANG_RELEASE_ASSERT(argCount >= 1); + + auto textureArg = args[0].usedValue; + if (auto baseTextureType = textureArg->type->As<TextureType>()) + { + auto elementType = baseTextureType->elementType; + if (auto basicType = elementType->As<BasicExpressionType>()) + { + // A scalar result is expected + Emit(".x"); + } + else if (auto vectorType = elementType->As<VectorExpressionType>()) + { + // A vector result is expected + auto elementCount = GetIntVal(vectorType->elementCount); + + if (elementCount < 4) + { + char const* swiz[] = { "", ".x", ".xy", ".xyz", "" }; + Emit(swiz[elementCount]); + } + } + else + { + // What other cases are possible? + } + } + else + { + SLANG_UNEXPECTED("bad format in intrinsic definition"); + } + } + break; + + + default: + SLANG_UNEXPECTED("bad format in intrinsic definition"); + break; + } + } + + Emit(")"); + } + } + void emitIntrinsicCallExpr( EmitContext* ctx, IRCall* inst, @@ -5426,6 +5645,18 @@ emitDeclImpl(decl, nullptr); UInt argCount = operandCount - 1; UInt operandIndex = 1; + + // + if (auto targetIntrinsicDecoration = findTargetIntrinsicDecoration(ctx, func)) + { + emitTargetIntrinsicCallExpr( + ctx, + inst, + func, + targetIntrinsicDecoration); + return; + } + // Our current strategy for dealing with intrinsic // calls is to "un-mangle" the mangled name, in // order to figure out what the user was originally diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 2027a2a0b..7c5f26ed7 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -1072,12 +1072,12 @@ for (int aa = 0; aa < kBaseBufferAccessLevelCount; ++aa) sb << "void GetDimensions(out uint dim);\n"; - sb << "__target_intrinsic(glsl, \"texelFetch($$P, $0)$$z\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($$P, $1)$$z\")\n"; sb << "T Load(int location);\n"; sb << "T Load(int location, out uint status);\n"; - sb << "__target_intrinsic(glsl, \"texelFetch($$P, int($0))$$z\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($$P, int($1))$$z\")\n"; sb << "__subscript(uint index) -> T"; if (kBaseBufferAccessLevels[aa].access != SLANG_RESOURCE_ACCESS_READ) diff --git a/source/slang/hlsl.meta.slang.h b/source/slang/hlsl.meta.slang.h index 982f887b0..2f42e9382 100644 --- a/source/slang/hlsl.meta.slang.h +++ b/source/slang/hlsl.meta.slang.h @@ -1075,12 +1075,12 @@ for (int aa = 0; aa < kBaseBufferAccessLevelCount; ++aa) sb << "void GetDimensions(out uint dim);\n"; - sb << "__target_intrinsic(glsl, \"texelFetch($P, $0)$z\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($P, $1)$z\")\n"; sb << "T Load(int location);\n"; sb << "T Load(int location, out uint status);\n"; - sb << "__target_intrinsic(glsl, \"texelFetch($P, int($0))$z\")\n"; + sb << "__target_intrinsic(glsl, \"texelFetch($P, int($1))$z\")\n"; sb << "__subscript(uint index) -> T"; if (kBaseBufferAccessLevels[aa].access != SLANG_RESOURCE_ACCESS_READ) diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index dedc906d0..46a804a1c 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -47,14 +47,25 @@ struct IRLoopControlDecoration : IRDecoration IRLoopControl mode; }; -struct IRTargetDecoration : IRDecoration -{ - enum { kDecorationOp = kIRDecorationOp_Target }; +struct IRTargetSpecificDecoration : IRDecoration +{ // TODO: have a more structured representation of target specifiers String targetName; }; +struct IRTargetDecoration : IRTargetSpecificDecoration +{ + enum { kDecorationOp = kIRDecorationOp_Target }; +}; + +struct IRTargetIntrinsicDecoration : IRTargetSpecificDecoration +{ + enum { kDecorationOp = kIRDecorationOp_TargetIntrinsic }; + + String definition; +}; + // // An IR node to represent a reference to an AST-level diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index b965f908c..77aac3f5a 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -3226,6 +3226,15 @@ namespace Slang } break; + case kIRDecorationOp_TargetIntrinsic: + { + auto originalDecoration = (IRTargetIntrinsicDecoration*)dd; + auto newDecoration = context->builder->addDecoration<IRTargetIntrinsicDecoration>(clonedValue); + newDecoration->targetName = originalDecoration->targetName; + newDecoration->definition = originalDecoration->definition; + } + break; + default: // Don't clone any decorations we don't understand. break; diff --git a/source/slang/ir.h b/source/slang/ir.h index fe6fab5f6..1b4529a3c 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -106,6 +106,7 @@ enum IRDecorationOp : uint16_t kIRDecorationOp_Layout, kIRDecorationOp_LoopControl, kIRDecorationOp_Target, + kIRDecorationOp_TargetIntrinsic, }; // A "decoration" that gets applied to an instruction. diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 4eb762333..bde50aa89 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -3757,6 +3757,24 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> decoration->targetName = targetMod->targetToken.Content; } + // If this declaration was marked as having a target-specific lowering + // for a particular target, then handle that here. + for (auto targetMod : decl->GetModifiersOfType<TargetIntrinsicModifier>()) + { + auto decoration = getBuilder()->addDecoration<IRTargetIntrinsicDecoration>(irFunc); + decoration->targetName = targetMod->targetToken.Content; + + auto definitionToken = targetMod->definitionToken; + if (definitionToken.type == TokenType::StringLiteral) + { + decoration->definition = getStringLiteralTokenValue(definitionToken); + } + else + { + decoration->definition = definitionToken.Content; + } + } + // For convenience, ensure that any additional global // values that were emitted while outputting the function // body appear before the function itself in the list diff --git a/tests/bindings/glsl-parameter-blocks.slang b/tests/bindings/glsl-parameter-blocks.slang index 64e302d90..48eacbb0f 100644 --- a/tests/bindings/glsl-parameter-blocks.slang +++ b/tests/bindings/glsl-parameter-blocks.slang @@ -1,5 +1,5 @@ #version 450 core -//TEST_DISABLED:CROSS_COMPILE: -profile ps_5_0 -entry main -target spirv-assembly +//TEST:CROSS_COMPILE: -profile ps_5_0 -entry main -target spirv-assembly // Note: disabled because the translation of `Texture2D.Sample()` // requires handling of local variables with resource types in the IR. diff --git a/tests/bindings/glsl-parameter-blocks.slang.glsl b/tests/bindings/glsl-parameter-blocks.slang.glsl index 9956800f1..e34101983 100644 --- a/tests/bindings/glsl-parameter-blocks.slang.glsl +++ b/tests/bindings/glsl-parameter-blocks.slang.glsl @@ -1,37 +1,44 @@ //TEST_IGNORE_FILE: #version 450 core -struct Test +struct _ST04Test { vec4 a; }; layout(binding = 0, set = 1) -uniform gTest_S1 +uniform _S1 { - Test gTest; + _ST04Test _SV05gTestL0; }; layout(binding = 1, set = 1) -uniform texture2D gTest_t; +uniform texture2D _SV05gTestL1; layout(binding = 2, set = 1) -uniform sampler gTest_s; - -vec4 main_(vec2 uv) -{ - return gTest.a + texture(sampler2D(gTest_t, gTest_s), uv); -} +uniform sampler _SV05gTestL2; layout(location = 0) -in vec2 SLANG_in_uv; +in vec2 _S3; layout(location = 0) -out vec4 SLANG_out_main_result; +out vec4 _S2; void main() { - vec2 uv = SLANG_in_uv; - vec4 main_result = main_(uv); - SLANG_out_main_result = main_result; + vec2 _S4 = _S3; + + vec2 _S5 = _S4; + + vec4 _S6 = _SV05gTestL0.a; + + vec2 _S7 = _S5; + + + vec4 _S8 = texture(sampler2D(_SV05gTestL1, _SV05gTestL2), _S7); + + vec4 _S9 = _S6 + _S8; + _S2 = _S9; + + return; } |
