Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map SV_InstanceID to gl_InstanceIndex-gl_BaseInstance #6468

Merged
merged 7 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ jobs:
-expected-failure-list tests/expected-failure-record-replay-tests.txt
fi
- name: Run Slang examples
if: steps.filter.outputs.should-run == 'true' && matrix.platform != 'wasm'
if: steps.filter.outputs.should-run == 'true' && matrix.platform != 'wasm' && matrix.full-gpu-tests
run: |
.github/workflows/ci-examples.sh \
--bin-dir "$bin_dir" \
Expand Down
22 changes: 21 additions & 1 deletion source/slang/glsl.meta.slang
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,27 @@ public property uint3 gl_WorkGroupSize
// TODO: define overload for tessellation control stage.
public in int gl_InvocationID : SV_GSInstanceID;

public in int gl_InstanceIndex : SV_InstanceID;
internal in int __sv_InstanceIndex : SV_InstanceID;

// SPIRV InstanceIndex builtin for vertex shader
public property int gl_InstanceIndex
{
[require(vertex)]
get
{
__target_switch
{
default:
return __sv_InstanceIndex;
case glsl:
__intrinsic_asm "gl_InstanceIndex";
case spirv:
return spirv_asm {
result:$$int = OpLoad builtin(InstanceIndex:int);
};
}
}
}
public in bool gl_FrontFacing : SV_IsFrontFace;

// TODO: define overload for geometry stage.
Expand Down
2 changes: 2 additions & 0 deletions source/slang/slang-artifact-output-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "../core/slang-string-util.h"
#include "../core/slang-type-text-util.h"

#include <chrono>

Comment on lines +9 to +10
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this is needed to silence another related error in latest vs.

// Artifact
#include "../compiler-core/slang-artifact-desc-util.h"
#include "../compiler-core/slang-artifact-util.h"
Expand Down
22 changes: 22 additions & 0 deletions source/slang/slang-compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "slang-check-impl.h"
#include "slang-check.h"

#include <chrono>

// Artifact
#include "../compiler-core/slang-artifact-associated.h"
#include "../compiler-core/slang-artifact-container-util.h"
Expand Down Expand Up @@ -1835,6 +1837,26 @@ SlangResult CodeGenContext::_emitEntryPoints(ComPtr<IArtifact>& outArtifact)
return SLANG_FAIL;
}

// Helper class for recording compile time.
struct CompileTimerRAII
{
std::chrono::high_resolution_clock::time_point startTime;
Session* session;
CompileTimerRAII(Session* inSession)
{
startTime = std::chrono::high_resolution_clock::now();
session = inSession;
}
~CompileTimerRAII()
{
double elapsedTime = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now() - startTime)
.count() /
1e6;
session->addTotalCompileTime(elapsedTime);
}
};

// Do emit logic for a zero or more entry points
SlangResult CodeGenContext::emitEntryPoints(ComPtr<IArtifact>& outArtifact)
{
Expand Down
20 changes: 0 additions & 20 deletions source/slang/slang-compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3757,26 +3757,6 @@ SLANG_FORCE_INLINE SlangSourceLanguage asExternal(SourceLanguage sourceLanguage)
return (SlangSourceLanguage)sourceLanguage;
}

// Helper class for recording compile time.
struct CompileTimerRAII
{
std::chrono::high_resolution_clock::time_point startTime;
Session* session;
CompileTimerRAII(Session* inSession)
{
startTime = std::chrono::high_resolution_clock::now();
session = inSession;
}
~CompileTimerRAII()
{
double elapsedTime = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now() - startTime)
.count() /
1e6;
session->addTotalCompileTime(elapsedTime);
}
};

// helpers for error/warning reporting
enum class DiagnosticCategory
{
Expand Down
19 changes: 19 additions & 0 deletions source/slang/slang-emit-c-like.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,20 @@ IRNumThreadsDecoration* CLikeSourceEmitter::getComputeThreadGroupSize(
return decor;
}

String CLikeSourceEmitter::getTargetBuiltinVarName(IRInst* inst, IRTargetBuiltinVarName builtinName)
{
switch (builtinName)
{
case IRTargetBuiltinVarName::SpvInstanceIndex:
return "gl_InstanceIndex";
case IRTargetBuiltinVarName::SpvBaseInstance:
return "gl_BaseInstance";
}
if (auto linkage = inst->findDecoration<IRLinkageDecoration>())
return linkage->getMangledName();
return generateName(inst);
}

List<IRWitnessTableEntry*> CLikeSourceEmitter::getSortedWitnessTableEntries(
IRWitnessTable* witnessTable)
{
Expand Down Expand Up @@ -1208,6 +1222,11 @@ String CLikeSourceEmitter::generateName(IRInst* inst)
return externCppDecoration->getName();
}

if (auto builtinTargetVarDecoration = inst->findDecoration<IRTargetBuiltinVarDecoration>())
{
return getTargetBuiltinVarName(inst, builtinTargetVarDecoration->getBuiltinVarName());
}

// If we have a name hint on the instruction, then we will try to use that
// to provide the basis for the actual name in the output code.
if (auto nameHintDecoration = inst->findDecoration<IRNameHintDecoration>())
Expand Down
2 changes: 1 addition & 1 deletion source/slang/slang-emit-c-like.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,6 @@ class CLikeSourceEmitter : public SourceEmitterBase
Linkage* getLinkage() { return m_codeGenContext->getLinkage(); }
ComponentType* getProgram() { return m_codeGenContext->getProgram(); }
TargetProgram* getTargetProgram() { return m_codeGenContext->getTargetProgram(); }

//
// Types
//
Expand Down Expand Up @@ -519,6 +518,7 @@ class CLikeSourceEmitter : public SourceEmitterBase
protected:
virtual void emitGlobalParamDefaultVal(IRGlobalParam* inst) { SLANG_UNUSED(inst); }
virtual void emitPostDeclarationAttributesForType(IRInst* type) { SLANG_UNUSED(type); }
virtual String getTargetBuiltinVarName(IRInst* inst, IRTargetBuiltinVarName builtinName);
virtual bool doesTargetSupportPtrTypes() { return false; }
virtual bool isResourceTypeBindless(IRType* type)
{
Expand Down
6 changes: 6 additions & 0 deletions source/slang/slang-emit-glsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1791,6 +1791,12 @@ bool GLSLSourceEmitter::tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* v
}
}

if (varDecl->findDecoration<IRTargetBuiltinVarDecoration>())
{
// By default, we don't need to emit a definition for target builtin variables.
return true;
}

// Do the default thing
return false;
}
Expand Down
16 changes: 15 additions & 1 deletion source/slang/slang-emit-spirv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4417,8 +4417,11 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
continue;
}
}
paramsSet.add(spvGlobalInst);
referencedBuiltinIRVars.add(globalInst);
// Don't add duplicate vars to the interface list.
bool paramAdded = paramsSet.add(spvGlobalInst);
if (!paramAdded)
continue;

// Don't add a global param to the interface if it is a
// specialization constant.
Expand Down Expand Up @@ -5288,6 +5291,17 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
{
IRBuilder builder(m_irModule);
builder.setInsertBefore(inst);
if (auto builtinVarDecor = inst->findDecoration<IRTargetBuiltinVarDecoration>())
{
switch (builtinVarDecor->getBuiltinVarName())
{
case IRTargetBuiltinVarName::SpvInstanceIndex:
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInInstanceIndex, inst);
case IRTargetBuiltinVarName::SpvBaseInstance:
requireSPIRVCapability(SpvCapabilityDrawParameters);
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInBaseInstance, inst);
}
}
if (auto layout = getVarLayout(inst))
{
if (auto systemValueAttr = layout->findAttr<IRSystemValueSemanticAttr>())
Expand Down
80 changes: 77 additions & 3 deletions source/slang/slang-ir-glsl-legalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ struct GLSLSystemValueInfo

// The kind of the system value that requires special treatment.
GLSLSystemValueKind kind = GLSLSystemValueKind::General;

// The target builtin name.
IRTargetBuiltinVarName targetVarName = IRTargetBuiltinVarName::Unknown;
};

static void leafAddressesImpl(List<IRInst*>& ret, const ScalarizedVal& v)
Expand Down Expand Up @@ -283,6 +286,7 @@ struct GLSLLegalizationContext
DiagnosticSink* sink;
Stage stage;
IRFunc* entryPointFunc;
Dictionary<IRTargetBuiltinVarName, IRInst*> builtinVarMap;

/// This dictionary stores all bindings of 'VaryingIn/VaryingOut'. We assume 'space' is 0.
Dictionary<LayoutResourceKind, UIntSet> usedBindingIndex;
Expand Down Expand Up @@ -414,7 +418,7 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
char const* outerArrayName = nullptr;
int arrayIndex = -1;
GLSLSystemValueKind systemValueKind = GLSLSystemValueKind::General;

IRTargetBuiltinVarName targetVarName = IRTargetBuiltinVarName::Unknown;
auto semanticInst = varLayout->findSystemValueSemanticAttr();
if (!semanticInst)
return nullptr;
Expand Down Expand Up @@ -621,6 +625,9 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(

requiredType = builder->getBasicType(BaseType::Int);
name = "gl_InstanceIndex";
targetVarName = IRTargetBuiltinVarName::HlslInstanceID;
context->requireSPIRVVersion(SemanticVersion(1, 3));
context->requireGLSLExtension(toSlice("GL_ARB_shader_draw_parameters"));
}
else if (semanticName == "sv_isfrontface")
{
Expand Down Expand Up @@ -869,6 +876,7 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
name = "gl_BaseInstance";
}

inStorage->targetVarName = targetVarName;
if (name)
{
inStorage->name = name;
Expand Down Expand Up @@ -976,6 +984,12 @@ void createVarLayoutForLegalizedGlobalParam(
default:
break;
}

if (systemValueInfo->targetVarName != IRTargetBuiltinVarName::Unknown)
{
builder->addTargetBuiltinVarDecoration(globalParam, systemValueInfo->targetVarName);
context->builtinVarMap[systemValueInfo->targetVarName] = globalParam;
}
}
}

Expand Down Expand Up @@ -1261,8 +1275,8 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
auto systemSemantic = inVarLayout->findAttr<IRSystemValueSemanticAttr>();
// Validate the system value, convert to a regular parameter if this is not a valid system
// value for a given target.
if (systemSemantic && isSPIRV(codeGenContext->getTargetFormat()) &&
systemSemantic->getName().caseInsensitiveEquals(UnownedStringSlice("sv_instanceid")) &&
if (systemSemantic && systemValueInfo && isSPIRV(codeGenContext->getTargetFormat()) &&
systemValueInfo->targetVarName == IRTargetBuiltinVarName::HlslInstanceID &&
((stage == Stage::Fragment) ||
(stage == Stage::Vertex &&
inVarLayout->usesResourceKind(LayoutResourceKind::VaryingOutput))))
Expand All @@ -1287,6 +1301,7 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
newVarLayout->sourceLoc = inVarLayout->sourceLoc;

inVarLayout->replaceUsesWith(newVarLayout);
systemValueInfo->targetVarName = IRTargetBuiltinVarName::Unknown;
}
}

Expand Down Expand Up @@ -3746,6 +3761,60 @@ ScalarizedVal legalizeEntryPointReturnValueForGLSL(
return result;
}

void legalizeTargetBuiltinVar(GLSLLegalizationContext& context)
{
List<KeyValuePair<IRTargetBuiltinVarName, IRInst*>> workItems;
for (auto [builtinVarName, varInst] : context.builtinVarMap)
{
if (builtinVarName == IRTargetBuiltinVarName::HlslInstanceID)
{
workItems.add(KeyValuePair(builtinVarName, varInst));
}
}

auto getOrCreateBuiltinVar = [&](IRTargetBuiltinVarName name, IRType* type)
{
if (auto var = context.builtinVarMap.tryGetValue(name))
return *var;
IRBuilder builder(context.entryPointFunc);
builder.setInsertBefore(context.entryPointFunc);
IRInst* var = builder.createGlobalParam(type);
builder.addTargetBuiltinVarDecoration(var, name);
return var;
};
for (auto& kv : workItems)
{
auto builtinVarName = kv.key;
auto varInst = kv.value;

// Repalce SV_InstanceID with gl_InstanceIndex - gl_BaseInstance.
if (builtinVarName == IRTargetBuiltinVarName::HlslInstanceID)
{
auto instanceIndex = getOrCreateBuiltinVar(
IRTargetBuiltinVarName::SpvInstanceIndex,
varInst->getDataType());
auto baseInstance = getOrCreateBuiltinVar(
IRTargetBuiltinVarName::SpvBaseInstance,
varInst->getDataType());
traverseUses(
varInst,
[&](IRUse* use)
{
auto user = use->getUser();
if (user->getOp() == kIROp_Load)
{
IRBuilder builder(use->getUser());
builder.setInsertBefore(use->getUser());
auto sub = builder.emitSub(
tryGetPointedToType(&builder, varInst->getDataType()),
builder.emitLoad(instanceIndex),
builder.emitLoad(baseInstance));
user->replaceUsesWith(sub);
}
});
}
}
}

void legalizeEntryPointForGLSL(
Session* session,
Expand Down Expand Up @@ -3937,6 +4006,11 @@ void legalizeEntryPointForGLSL(
value.globalParam->setFullType(sizedArrayType);
}
}

// Some system value vars can't be mapped 1:1 to a GLSL/Vulkan builtin,
// for example, SV_InstanceID should map to gl_InstanceIndex - gl_BaseInstance,
// we will replace these builtins with additional compute logic here.
legalizeTargetBuiltinVar(context);
}

void decorateModuleWithSPIRVVersion(IRModule* module, SemanticVersion spirvVersion)
Expand Down
3 changes: 3 additions & 0 deletions source/slang/slang-ir-inst-defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,9 @@ INST_RANGE(BindingQuery, GetRegisterIndex, GetRegisterSpace)
INST(ExportDecoration, export, 1, 0)
INST_RANGE(LinkageDecoration, ImportDecoration, ExportDecoration)

/// Mark a global variable as a target builtin variable.
INST(TargetBuiltinVarDecoration, TargetBuiltinVar, 1, 0)

/// Marks an inst as coming from an `extern` symbol defined in the user code.
INST(UserExternDecoration, UserExtern, 0, 0)

Expand Down
Loading
Loading