[spirv] Support several SV semantics in VS and PS (#534)

Includes: SV_Position, SV_Target, SV_VertexID, SV_InstanceID,
and SV_Depth.

Also use existing DXIL classes for stage variables. There already
exist classes for semantics and SigPoints. Reuse them to create a
StageVar class for holding information about stage variables.
This commit is contained in:
Lei Zhang 2017-08-09 01:20:00 -04:00 коммит произвёл David Peixotto
Родитель b5043877bc
Коммит d153fe8e96
15 изменённых файлов: 332 добавлений и 114 удалений

Просмотреть файл

@ -9,23 +9,22 @@
#include "DeclResultIdMapper.h"
#include "dxc/HLSL/DxilConstants.h"
#include "dxc/HLSL/DxilTypeSystem.h"
#include "clang/AST/HlslTypes.h"
#include "llvm/ADT/StringSwitch.h"
namespace clang {
namespace spirv {
void DeclResultIdMapper::createStageVarFromFnReturn(
bool DeclResultIdMapper::createStageVarFromFnReturn(
const FunctionDecl *funcDecl) {
// SemanticDecl for the return value is attached to the FunctionDecl.
createStageVariables(funcDecl, false);
return createStageVariables(funcDecl, true);
}
void DeclResultIdMapper::createStageVarFromFnParam(
bool DeclResultIdMapper::createStageVarFromFnParam(
const ParmVarDecl *paramDecl) {
// TODO: We cannot treat all parameters as stage inputs because of
// out/input modifiers.
createStageVariables(paramDecl, true);
return createStageVariables(paramDecl, false);
}
void DeclResultIdMapper::registerDeclResultId(const NamedDecl *symbol,
@ -34,7 +33,10 @@ void DeclResultIdMapper::registerDeclResultId(const NamedDecl *symbol,
}
bool DeclResultIdMapper::isStageVariable(uint32_t varId) const {
return stageVars.count(varId) != 0;
for (const auto &var : stageVars)
if (var.getSpirvId() == varId)
return true;
return false;
}
uint32_t DeclResultIdMapper::getDeclResultId(const NamedDecl *decl) const {
@ -76,19 +78,12 @@ DeclResultIdMapper::getNormalDeclResultId(const NamedDecl *decl) const {
}
std::vector<uint32_t> DeclResultIdMapper::collectStageVariables() const {
std::vector<uint32_t> stageVars;
std::vector<uint32_t> vars;
for (const auto &builtin : stageBuiltins) {
stageVars.push_back(builtin.first);
}
for (const auto &input : stageInputs) {
stageVars.push_back(input.first);
}
for (const auto &output : stageOutputs) {
stageVars.push_back(output.first);
}
for (const auto &var : stageVars)
vars.push_back(var.getSpirvId());
return stageVars;
return vars;
}
void DeclResultIdMapper::finalizeStageIOLocations() {
@ -97,11 +92,14 @@ void DeclResultIdMapper::finalizeStageIOLocations() {
// TODO: sort the variables according to some criteria first, e.g.,
// alphabetical order of semantic names.
for (const auto &input : stageInputs) {
theBuilder.decorateLocation(input.first, nextInputLocation++);
}
for (const auto &output : stageOutputs) {
theBuilder.decorateLocation(output.first, nextOutputLocation++);
for (auto &var : stageVars) {
if (!var.isSpirvBuitin()) {
if (var.getSigPoint()->IsInput()) {
theBuilder.decorateLocation(var.getSpirvId(), nextInputLocation++);
} else if (var.getSigPoint()->IsOutput()) {
theBuilder.decorateLocation(var.getSpirvId(), nextOutputLocation++);
}
}
}
}
@ -113,49 +111,49 @@ DeclResultIdMapper::getFnParamOrRetType(const DeclaratorDecl *decl) const {
return decl->getType();
}
void DeclResultIdMapper::createStageVariables(const DeclaratorDecl *decl,
bool actAsInput) {
bool DeclResultIdMapper::createStageVariables(const DeclaratorDecl *decl,
bool forRet) {
QualType type = getFnParamOrRetType(decl);
if (type->isVoidType()) {
// No stage variables will be created for void type.
return;
return true;
}
const std::string semantic = getStageVarSemantic(decl);
if (!semantic.empty()) {
const llvm::StringRef semanticStr = getStageVarSemantic(decl);
if (!semanticStr.empty()) {
// Found semantic attached directly to this Decl. This means we need to
// map this decl to a single stage variable.
const uint32_t typeId = typeTranslator.translateType(type);
const auto kind = getStageVarKind(semantic);
if (actAsInput) {
// Stage (builtin) input variable cases
const uint32_t varId =
theBuilder.addStageIOVariable(typeId, spv::StorageClass::Input);
// TODO: fix this when supporting parameter in/out qualifiers
const hlsl::DxilParamInputQual qual =
forRet ? hlsl::DxilParamInputQual::Out : hlsl::DxilParamInputQual::In;
stageInputs.push_back(std::make_pair(varId, semantic));
remappedDecls[decl] = varId;
stageVars.insert(varId);
} else {
// Handle output builtin variables first
if (shaderModel.IsVS() && kind == StageVarKind::Position) {
const uint32_t varId =
theBuilder.addStageBuiltinVariable(typeId, spv::BuiltIn::Position);
// TODO: use the correct isPC value when supporting patch constant function
// in hull shader
const hlsl::SigPoint *sigPoint =
hlsl::SigPoint::GetSigPoint(hlsl::SigPointFromInputQual(
qual, shaderModel.GetKind(), /*isPC*/ false));
stageBuiltins.push_back(std::make_pair(varId, semantic));
remappedDecls[decl] = varId;
stageVars.insert(varId);
} else {
// The rest are normal stage output variables
const uint32_t varId =
theBuilder.addStageIOVariable(typeId, spv::StorageClass::Output);
const auto *semantic = hlsl::Semantic::GetByName(semanticStr);
stageOutputs.push_back(std::make_pair(varId, semantic));
remappedDecls[decl] = varId;
stageVars.insert(varId);
}
// Error out when the given semantic is invalid in this shader model
if (hlsl::SigPoint::GetInterpretation(
semantic->GetKind(), sigPoint->GetKind(), shaderModel.GetMajor(),
shaderModel.GetMinor()) ==
hlsl::DXIL::SemanticInterpretationKind::NA) {
emitError("invalid semantic %0 for shader module %1")
<< semanticStr << shaderModel.GetName();
return false;
}
StageVar stageVar(sigPoint, semantic, typeId);
const uint32_t varId = createSpirvStageVar(&stageVar);
stageVar.setSpirvId(varId);
stageVars.push_back(stageVar);
remappedDecls[decl] = varId;
} else {
// If the decl itself doesn't have semantic, it should be a struct having
// all its fields with semantics.
@ -166,30 +164,100 @@ void DeclResultIdMapper::createStageVariables(const DeclaratorDecl *decl,
// Recursively handle all the fields.
for (const auto *field : structDecl->fields()) {
createStageVariables(field, actAsInput);
if (!createStageVariables(field, forRet))
return false;
}
}
return true;
}
DeclResultIdMapper::StageVarKind
DeclResultIdMapper::getStageVarKind(llvm::StringRef semantic) const {
return llvm::StringSwitch<StageVarKind>(semantic)
.Case("", StageVarKind::None)
.StartsWith("COLOR", StageVarKind::Color)
.StartsWith("POSITION", StageVarKind::Position)
.StartsWith("SV_POSITION", StageVarKind::Position)
.StartsWith("SV_TARGET", StageVarKind::Target)
.Default(StageVarKind::Arbitary);
uint32_t DeclResultIdMapper::createSpirvStageVar(StageVar *stageVar) {
const auto semanticKind = stageVar->getSemantic()->GetKind();
const auto sigPointKind = stageVar->getSigPoint()->GetKind();
const uint32_t type = stageVar->getSpirvTypeId();
// The following translation assumes that semantic validity in the current
// shader model is already checked, so it only covers valid SigPoints for
// each semantic.
switch (semanticKind) {
// According to DXIL spec, the Position SV can be used by all SigPoints
// other than PCIn, HSIn, GSIn, PSOut, CSIn.
// According to Vulkan spec, the Position decoration can only be used
// by PSOut, HS/DS/GS In/Out.
case hlsl::Semantic::Kind::Position: {
switch (sigPointKind) {
case hlsl::SigPoint::Kind::VSIn:
return theBuilder.addStageIOVariable(type, spv::StorageClass::Input);
case hlsl::SigPoint::Kind::VSOut:
stageVar->setIsSpirvBuiltin();
return theBuilder.addStageBuiltinVariable(type, spv::BuiltIn::Position);
case hlsl::SigPoint::Kind::PSIn:
stageVar->setIsSpirvBuiltin();
return theBuilder.addStageBuiltinVariable(type, spv::BuiltIn::FragCoord);
default:
emitError("semantic Position for SigPoint %0 unimplemented yet")
<< stageVar->getSigPoint()->GetName();
break;
}
}
// According to DXIL spec, the VertexID SV can only be used by VSIn.
case hlsl::Semantic::Kind::VertexID:
stageVar->setIsSpirvBuiltin();
return theBuilder.addStageBuiltinVariable(type, spv::BuiltIn::VertexIndex);
// According to DXIL spec, the InstanceID SV can be used by VSIn, VSOut,
// HSCPIn, HSCPOut, DSCPIn, DSOut, GSVIn, GSOut, PSIn.
// According to Vulkan spec, the InstanceIndex can only be used by VSIn.
case hlsl::Semantic::Kind::InstanceID: {
switch (sigPointKind) {
case hlsl::SigPoint::Kind::VSIn:
stageVar->setIsSpirvBuiltin();
return theBuilder.addStageBuiltinVariable(type,
spv::BuiltIn::InstanceIndex);
case hlsl::SigPoint::Kind::VSOut:
return theBuilder.addStageIOVariable(type, spv::StorageClass::Output);
case hlsl::SigPoint::Kind::PSIn:
return theBuilder.addStageIOVariable(type, spv::StorageClass::Input);
default:
emitError("semantic InstanceID for SigPoint %0 unimplemented yet")
<< stageVar->getSigPoint()->GetName();
break;
}
}
// According to DXIL spec, the Depth SV can only be used by PSOut.
case hlsl::Semantic::Kind::Depth:
stageVar->setIsSpirvBuiltin();
return theBuilder.addStageBuiltinVariable(type, spv::BuiltIn::FragDepth);
// According to DXIL spec, the Target SV can only be used by PSOut.
// There is no corresponding builtin decoration in SPIR-V. So generate normal
// Vulkan stage input/output variables.
case hlsl::Semantic::Kind::Target:
// An arbitrary semantic is defined by users. Generate normal Vulkan stage
// input/output variables.
case hlsl::Semantic::Kind::Arbitrary: {
if (stageVar->getSigPoint()->IsInput())
return theBuilder.addStageIOVariable(type, spv::StorageClass::Input);
if (stageVar->getSigPoint()->IsOutput())
return theBuilder.addStageIOVariable(type, spv::StorageClass::Output);
// TODO: patch constant function in hull shader
}
default:
emitError("semantic %0 unimplemented yet")
<< stageVar->getSemantic()->GetName();
break;
}
return 0;
}
std::string
DeclResultIdMapper::getStageVarSemantic(const NamedDecl *decl) const {
llvm::StringRef DeclResultIdMapper::getStageVarSemantic(const NamedDecl *decl) {
for (auto *annotation : decl->getUnusualAnnotations()) {
if (auto *semantic = dyn_cast<hlsl::SemanticDecl>(annotation)) {
return semantic->SemanticName.upper();
return semantic->SemanticName;
}
}
return "";
return {};
}
} // end namespace spirv

Просмотреть файл

@ -10,14 +10,15 @@
#ifndef LLVM_CLANG_LIB_SPIRV_DECLRESULTIDMAPPER_H
#define LLVM_CLANG_LIB_SPIRV_DECLRESULTIDMAPPER_H
#include <string>
#include <vector>
#include "dxc/HLSL//DxilShaderModel.h"
#include "dxc/HLSL/DxilSemantic.h"
#include "dxc/HLSL/DxilShaderModel.h"
#include "dxc/HLSL/DxilSigPoint.h"
#include "spirv/1.0/spirv.hpp11"
#include "clang/SPIRV/ModuleBuilder.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "TypeTranslator.h"
@ -25,6 +26,44 @@
namespace clang {
namespace spirv {
/// \brief The class containing HLSL and SPIR-V information about a Vulkan stage
/// (builtin/input/output) variable.
class StageVar {
public:
StageVar(const hlsl::SigPoint *sig, const hlsl::Semantic *sema, uint32_t type)
: sigPoint(sig), semantic(sema), typeId(type), valueId(0),
isBuiltin(false), location(llvm::None) {}
const hlsl::SigPoint *getSigPoint() const { return sigPoint; }
const hlsl::Semantic *getSemantic() const { return semantic; }
uint32_t getSpirvTypeId() const { return typeId; }
uint32_t getSpirvId() const { return valueId; }
void setSpirvId(uint32_t id) { valueId = id; }
bool isSpirvBuitin() const { return isBuiltin; }
void setIsSpirvBuiltin() { isBuiltin = true; }
bool hasLocation() const { return location.hasValue(); }
void setLocation(uint32_t loc) { location = llvm::Optional<uint32_t>(loc); }
private:
/// HLSL SigPoint. It uniquely identifies each set of parameters that may be
/// input or output for each entry point.
const hlsl::SigPoint *sigPoint;
/// HLSL semantic.
const hlsl::Semantic *semantic;
/// SPIR-V <type-id>.
uint32_t typeId;
/// SPIR-V <result-id>.
uint32_t valueId;
/// Indicates whether this stage variable should be a SPIR-V builtin.
bool isBuiltin;
/// Location assignment if input/output variable.
llvm::Optional<uint32_t> location;
};
/// \brief The class containing mappings from Clang frontend Decls to their
/// corresponding SPIR-V <result-id>s.
///
@ -54,12 +93,12 @@ public:
ModuleBuilder &builder, DiagnosticsEngine &diag);
/// \brief Creates the stage variables by parsing the semantics attached to
/// the given function's return value.
void createStageVarFromFnReturn(const FunctionDecl *funcDecl);
/// the given function's return value and returns true on success.
bool createStageVarFromFnReturn(const FunctionDecl *funcDecl);
/// \brief Creates the stage variables by parsing the semantics attached to
/// the given function's parameter.
void createStageVarFromFnParam(const ParmVarDecl *paramDecl);
/// the given function's parameter and returns true on success.
bool createStageVarFromFnParam(const ParmVarDecl *paramDecl);
/// \brief Registers a decl's <result-id> without generating any SPIR-V
/// instruction. The given decl will be treated as normal decl.
@ -98,64 +137,51 @@ public:
void finalizeStageIOLocations();
private:
/// \brief Stage variable kind.
///
/// Stage variables include builtin, input, and output variables.
/// They participate in interface matching in Vulkan pipelines.
enum class StageVarKind {
None,
Arbitary,
Position,
Color,
Target,
// TODO: other possible kinds
};
using StageVarIdSemanticPair = std::pair<uint32_t, std::string>;
/// \brief Wrapper method to create an error message and report it
/// in the diagnostic engine associated with this consumer.
template <unsigned N> DiagnosticBuilder emitError(const char (&message)[N]) {
const auto diagId =
diags.getCustomDiagID(clang::DiagnosticsEngine::Error, message);
return diags.Report(diagId);
}
/// Returns the type of the given decl. If the given decl is a FunctionDecl,
/// returns its result type.
QualType getFnParamOrRetType(const DeclaratorDecl *decl) const;
/// Creates all the stage variables mapped from semantics on the given decl.
/// Creates all the stage variables mapped from semantics on the given decl
/// and returns true on success.
///
/// Assumes the decl has semantic attached to itself or to its fields.
void createStageVariables(const DeclaratorDecl *decl, bool actAsInput);
bool createStageVariables(const DeclaratorDecl *decl, bool forReturnValue);
/// \brief Returns the stage variable's kind for the given semantic.
StageVarKind getStageVarKind(llvm::StringRef semantic) const;
/// Creates the SPIR-V variable instruction for the given StageVar and returns
/// the <result-id>. Also sets whether the StageVar is a SPIR-V builtin
/// accordingly.
uint32_t createSpirvStageVar(StageVar *);
/// \brief Returns the stage variable's semantic for the given Decl.
std::string getStageVarSemantic(const NamedDecl *decl) const;
static llvm::StringRef getStageVarSemantic(const NamedDecl *decl);
private:
const hlsl::ShaderModel &shaderModel;
ModuleBuilder &theBuilder;
TypeTranslator typeTranslator;
DiagnosticsEngine &diags;
/// Mapping of all remapped decls to their <result-id>s.
llvm::DenseMap<const NamedDecl *, uint32_t> remappedDecls;
/// Mapping of all normal decls to their <result-id>s.
llvm::DenseMap<const NamedDecl *, uint32_t> normalDecls;
/// <result-id>s of all defined stage variables.
///
/// We need to keep a separate list here to avoid looping through the
/// remappedDecls to find whether an <result-id> is for a stage variable.
llvm::SmallSet<uint32_t, 16> stageVars;
/// Stage input/oupt/builtin variables and their kinds.
///
/// We need to keep a separate list here in order to sort them at the end
/// of the module building.
llvm::SmallVector<StageVarIdSemanticPair, 8> stageInputs;
llvm::SmallVector<StageVarIdSemanticPair, 8> stageOutputs;
llvm::SmallVector<StageVarIdSemanticPair, 8> stageBuiltins;
/// Vector of all defined stage variables.
llvm::SmallVector<StageVar, 8> stageVars;
};
DeclResultIdMapper::DeclResultIdMapper(const hlsl::ShaderModel &model,
ModuleBuilder &builder,
DiagnosticsEngine &diag)
: shaderModel(model), theBuilder(builder), typeTranslator(builder, diag) {}
: shaderModel(model), theBuilder(builder), typeTranslator(builder, diag),
diags(diag) {}
} // end namespace spirv
} // end namespace clang

Просмотреть файл

@ -300,6 +300,7 @@ uint32_t ModuleBuilder::addStageBuiltinVariable(uint32_t type,
switch (builtin) {
case spv::BuiltIn::Position:
case spv::BuiltIn::PointSize:
case spv::BuiltIn::FragDepth:
// TODO: add the rest output builtins
sc = spv::StorageClass::Output;
break;

Просмотреть файл

@ -364,9 +364,12 @@ void SPIRVEmitter::doFunctionDecl(const FunctionDecl *decl) {
if (funcName == entryFunctionName) {
// First create stage variables for the entry point.
declIdMapper.createStageVarFromFnReturn(decl);
if (!declIdMapper.createStageVarFromFnReturn(decl))
return;
for (const auto *param : decl->params())
declIdMapper.createStageVarFromFnParam(param);
if (!declIdMapper.createStageVarFromFnParam(param))
return;
// Construct the function signature.
const uint32_t voidType = theBuilder.getVoidType();

Просмотреть файл

@ -1,4 +1,5 @@
// Run: %dxc -T ps_6_0 -E main
float4 main(float4 input: COLOR): SV_TARGET
{
return input;
@ -12,12 +13,12 @@ float4 main(float4 input: COLOR): SV_TARGET
// ; Schema: 0
// OpCapability Shader
// OpMemoryModel Logical GLSL450
// OpEntryPoint Fragment %main "main" %6 %4
// OpEntryPoint Fragment %main "main" %4 %6
// OpExecutionMode %main OriginUpperLeft
// OpName %main "main"
// OpName %bb_entry "bb.entry"
// OpDecorate %6 Location 0
// OpDecorate %4 Location 0
// OpDecorate %6 Location 0
// %float = OpTypeFloat 32
// %v4float = OpTypeVector %float 4
// %_ptr_Output_v4float = OpTypePointer Output %v4float

Просмотреть файл

@ -1,7 +1,7 @@
// Run: %dxc -T vs_6_0 -E VSmain
struct PSInput {
float4 position : POSITION;
float4 position : SV_POSITION;
float4 color : COLOR;
};
@ -21,14 +21,14 @@ PSInput VSmain(float4 position: POSITION, float4 color: COLOR) {
// ; Schema: 0
// OpCapability Shader
// OpMemoryModel Logical GLSL450
// OpEntryPoint Vertex %VSmain "VSmain" %gl_Position %7 %8 %5
// OpEntryPoint Vertex %VSmain "VSmain" %gl_Position %5 %7 %8
// OpName %VSmain "VSmain"
// OpName %bb_entry "bb.entry"
// OpName %result "result"
// OpDecorate %gl_Position BuiltIn Position
// OpDecorate %5 Location 0
// OpDecorate %7 Location 0
// OpDecorate %8 Location 1
// OpDecorate %5 Location 0
// %int = OpTypeInt 32 1
// %float = OpTypeFloat 32
// %v4float = OpTypeVector %float 4

Просмотреть файл

@ -0,0 +1,17 @@
// Run: %dxc -T vs_6_0 -E main
// CHECK: OpEntryPoint Vertex %main "main" [[out:%\d+]] [[a:%\d+]] [[b:%\d+]] [[c:%\d+]]
// CHECK: OpDecorate [[out]] Location 0
// CHECK: OpDecorate [[a]] Location 0
// CHECK: OpDecorate [[b]] Location 1
// CHECK: OpDecorate [[c]] Location 2
// CHECK: [[out]] = OpVariable %_ptr_Output_float Output
// CHECK: [[a]] = OpVariable %_ptr_Input_v4float Input
// CHECK: [[b]] = OpVariable %_ptr_Input_int Input
// CHECK: [[c]] = OpVariable %_ptr_Input_mat2v3float Input
float main(float4 a: AAA, int b: B, float2x3 c: CC) : DDDD {
return 1.0;
}

Просмотреть файл

@ -0,0 +1,11 @@
// Run: %dxc -T ps_6_0 -E main
// CHECK: OpEntryPoint Fragment %main "main" %gl_FragDepth {{%\d+}}
// CHECK: OpDecorate %gl_FragDepth BuiltIn FragDepth
// CHECK: %gl_FragDepth = OpVariable %_ptr_Output_float Output
float main(float input: A) : SV_Depth {
return input;
}

Просмотреть файл

@ -0,0 +1,11 @@
// Run: %dxc -T ps_6_0 -E main
// CHECK: OpEntryPoint Fragment %main "main" {{%\d+}} [[input:%\d+]]
// CHECK: OpDecorate [[input]] Location 0
// CHECK: [[input]] = OpVariable %_ptr_Input_int Input
float4 main(int input: SV_InstanceID) : SV_Target {
return input;
}

Просмотреть файл

@ -0,0 +1,14 @@
// Run: %dxc -T vs_6_0 -E main
// CHECK: OpEntryPoint Vertex %main "main" [[output:%\d+]] %gl_InstanceIndex
// CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
// CHECK: OpDecorate [[output]] Location 0
// CHECK: [[output]] = OpVariable %_ptr_Output_int Output
// CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_int Input
int main(int input: SV_InstanceID) : SV_InstanceID {
return input;
}

Просмотреть файл

@ -0,0 +1,11 @@
// Run: %dxc -T ps_6_0 -E main
// CHECK: OpEntryPoint Fragment %main "main" {{%\d+}} %gl_FragCoord
// CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
// CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
float4 main(float4 input: SV_Position) : SV_Target {
return input;
}

Просмотреть файл

@ -0,0 +1,13 @@
// Run: %dxc -T vs_6_0 -E main
// CHECK: OpEntryPoint Vertex %main "main" %gl_Position [[input:%\d+]]
// CHECK: OpDecorate %gl_Position BuiltIn Position
// CHECK: OpDecorate [[input]] Location 0
// CHECK: %gl_Position = OpVariable %_ptr_Output_v4float Output
// CHECK: [[input]] = OpVariable %_ptr_Input_v4float Input
float4 main(float4 input: SV_Position) : SV_Position {
return input;
}

Просмотреть файл

@ -0,0 +1,11 @@
// Run: %dxc -T ps_6_0 -E main
// CHECK: OpEntryPoint Fragment %main "main" [[target:%\d+]] {{%\d+}}
// CHECK: OpDecorate [[target]] Location 0
// CHECK: [[target]] = OpVariable %_ptr_Output_v4float Output
float4 main(float4 input: A) : SV_Target {
return input;
}

Просмотреть файл

@ -0,0 +1,11 @@
// Run: %dxc -T vs_6_0 -E main
// CHECK: OpEntryPoint Vertex %main "main" {{%\d+}} %gl_VertexIndex
// CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
// CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_int Input
int main(int input: SV_VertexID) : A {
return input;
}

Просмотреть файл

@ -217,6 +217,26 @@ TEST_F(FileTest, ControlFlowConditionalOp) { runFileTest("cf.cond-op.hlsl"); }
// For function calls
TEST_F(FileTest, FunctionCall) { runFileTest("fn.call.hlsl"); }
// For semantics
TEST_F(FileTest, SemanticPositionVS) {
runFileTest("semantic.position.vs.hlsl");
}
TEST_F(FileTest, SemanticPositionPS) {
runFileTest("semantic.position.ps.hlsl");
}
TEST_F(FileTest, SemanticVertexIDVS) {
runFileTest("semantic.vertex-id.vs.hlsl");
}
TEST_F(FileTest, SemanticInstanceIDVS) {
runFileTest("semantic.instance-id.vs.hlsl");
}
TEST_F(FileTest, SemanticInstanceIDPS) {
runFileTest("semantic.instance-id.ps.hlsl");
}
TEST_F(FileTest, SemanticTargetPS) { runFileTest("semantic.target.ps.hlsl"); }
TEST_F(FileTest, SemanticDepthPS) { runFileTest("semantic.depth.ps.hlsl"); }
TEST_F(FileTest, SemanticArbitrary) { runFileTest("semantic.arbitrary.hlsl"); }
// For intrinsic functions
TEST_F(FileTest, IntrinsicsDot) { runFileTest("intrinsics.dot.hlsl"); }
TEST_F(FileTest, IntrinsicsAll) { runFileTest("intrinsics.all.hlsl"); }