[spirv] Add mechanism for Vulkan-specific builtins (#805)

[[vk::builtin("...")]] is introduced to support Vulkan-specific
builtins.

There are two supported in this commit:

* gl_PointSize
* gl_HelperInvocation

Validating the usages of these two builtins is left for anther
commit.
This commit is contained in:
Lei Zhang 2017-11-25 17:32:39 -08:00 коммит произвёл GitHub
Родитель 8903528e88
Коммит 53f3f69b36
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 236 добавлений и 59 удалений

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

@ -160,8 +160,8 @@ non-intrusive ways in HLSL, which means we will prefer native language
constructs when possible. If that is inadequate, we then consider attaching
`Vulkan specific attributes`_ to them, or introducing new syntax.
Descriptor sets
~~~~~~~~~~~~~~~
Descriptors
~~~~~~~~~~~
To specify which Vulkan descriptor a particular resource binds to, use the
``[[vk::binding(X[, Y])]]`` attribute.
@ -176,6 +176,19 @@ annotated with the ``[[vk::push_constant]]`` attribute.
Please note as per the requirements of Vulkan, "there must be no more than one
push constant block statically used per shader entry point."
Builtin variables
~~~~~~~~~~~~~~~~~
Some of the Vulkan builtin variables have no equivalents in native HLSL
language. To support them, ``[[vk::builtin("<builtin>")]]`` is introduced.
Right now only two ``<builtin>`` are supported:
* ``PointSize``: The GLSL equivalent is ``gl_PointSize``.
* ``HelperInvocation``: The GLSL equivalent is ``gl_HelperInvocation``.
Please see Vulkan spec. `14.6. Built-In Variables <https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#interfaces-builtin-variables>`_
for detailed explanation of these builtins.
Vulkan specific attributes
--------------------------
@ -196,6 +209,9 @@ The namespace ``vk`` will be used for all Vulkan attributes:
- ``push_constant``: For marking a variable as the push constant block. Allowed
on global variables of struct type. At most one variable can be marked as
``push_constant`` in a shader.
- ``builtin("X")``: For specifying an entity should be translated into a certain
Vulkan builtin variable. Allowed on function parameters, function returns,
and struct fields.
Only ``vk::`` attributes in the above list are supported. Other attributes will
result in warnings and be ignored by the compiler. All C++11 attributes will

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

@ -863,6 +863,14 @@ def HLSLExperimental : InheritableAttr {
// SPIRV Change Starts
def VKBuiltIn : InheritableAttr {
let Spellings = [CXX11<"vk", "builtin">];
let Subjects = SubjectList<[Function, ParmVar, Field], ErrorDiag>;
let Args = [StringArgument<"BuiltIn">];
let LangOpts = [SPIRV];
let Documentation = [Undocumented];
}
def VKLocation : InheritableAttr {
let Spellings = [CXX11<"vk", "location">];
let Subjects = SubjectList<[Function, ParmVar, Field], ErrorDiag>;

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

@ -739,11 +739,10 @@ bool DeclResultIdMapper::decorateResourceBindings() {
// - m3, mX * c2
BindingSet bindingSet;
bool noError = true;
// Decorates the given varId of the given category with set number
// setNo, binding number bindingNo. Emits warning if overlap.
const auto tryToDecorate = [this, &bindingSet, &noError](
const auto tryToDecorate = [this, &bindingSet](
const uint32_t varId, const uint32_t setNo,
const uint32_t bindingNo,
const ResourceVar::Category cat,
@ -754,7 +753,6 @@ bool DeclResultIdMapper::decorateResourceBindings() {
loc)
<< bindingNo << setNo;
emitNote("binding number previously assigned here", prevUseLoc);
// noError = false;
}
theBuilder.decorateDSetBinding(varId, setNo, bindingNo);
};
@ -838,7 +836,7 @@ bool DeclResultIdMapper::decorateResourceBindings() {
}
}
return noError;
return true;
}
bool DeclResultIdMapper::createStageVars(
@ -907,6 +905,16 @@ bool DeclResultIdMapper::createStageVars(
return false;
}
const auto *builtinAttr = decl->getAttr<VKBuiltInAttr>();
// For VS/HS/DS, the PointSize builtin is handled in gl_PerVertex.
// For GSVIn also in gl_PerVertex; for GSOut, it's a stand-alone
// variable handled below.
if (builtinAttr && builtinAttr->getBuiltIn() == "PointSize" &&
glPerVertex.tryToAccessPointSize(sigPoint->GetKind(), invocationId,
value, noWriteBack))
return true;
// Special handling of certain mappings between HLSL semantics and
// SPIR-V builtins:
// * SV_Position/SV_CullDistance/SV_ClipDistance should be grouped into the
@ -957,7 +965,8 @@ bool DeclResultIdMapper::createStageVars(
theBuilder.getConstantUint32(arraySize));
StageVar stageVar(sigPoint, semanticToUse->str, semanticToUse->semantic,
semanticToUse->name, semanticToUse->index, typeId);
semanticToUse->name, semanticToUse->index, builtinAttr,
typeId);
const auto name = namePrefix.str() + "." + stageVar.getSemanticStr();
const uint32_t varId =
createSpirvStageVar(&stageVar, decl, name, semanticToUse->loc);
@ -1297,6 +1306,7 @@ uint32_t DeclResultIdMapper::createSpirvStageVar(StageVar *stageVar,
const llvm::StringRef name,
SourceLocation srcLoc) {
using spv::BuiltIn;
const auto sigPoint = stageVar->getSigPoint();
const auto semanticKind = stageVar->getSemantic()->GetKind();
const auto sigPointKind = sigPoint->GetKind();
@ -1307,6 +1317,19 @@ uint32_t DeclResultIdMapper::createSpirvStageVar(StageVar *stageVar,
return 0;
stageVar->setStorageClass(sc);
// [[vk::builtin(...)]] takes precedence.
if (const auto *builtinAttr = stageVar->getBuiltInAttr()) {
const auto spvBuiltIn =
llvm::StringSwitch<BuiltIn>(builtinAttr->getBuiltIn())
.Case("PointSize", BuiltIn::PointSize)
.Case("HelperInvocation", BuiltIn::HelperInvocation)
.Default(BuiltIn::Max);
assert(spvBuiltIn != BuiltIn::Max); // The frontend should guarantee this.
return theBuilder.addStageBuiltinVar(type, sc, spvBuiltIn);
}
// The following translation assumes that semantic validity in the current
// shader model is already checked, so it only covers valid SigPoints for
// each semantic.

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

@ -37,11 +37,14 @@ class StageVar {
public:
inline StageVar(const hlsl::SigPoint *sig, llvm::StringRef semaStr,
const hlsl::Semantic *sema, llvm::StringRef semaName,
uint32_t semaIndex, uint32_t type)
uint32_t semaIndex, const VKBuiltInAttr *builtin,
uint32_t type)
: sigPoint(sig), semanticStr(semaStr), semantic(sema),
semanticName(semaName), semanticIndex(semaIndex), typeId(type),
valueId(0), isBuiltin(false), storageClass(spv::StorageClass::Max),
location(nullptr) {}
semanticName(semaName), semanticIndex(semaIndex), builtinAttr(builtin),
typeId(type), valueId(0), isBuiltin(false),
storageClass(spv::StorageClass::Max), location(nullptr) {
isBuiltin = builtinAttr != nullptr;
}
const hlsl::SigPoint *getSigPoint() const { return sigPoint; }
const hlsl::Semantic *getSemantic() const { return semantic; }
@ -51,6 +54,8 @@ public:
uint32_t getSpirvId() const { return valueId; }
void setSpirvId(uint32_t id) { valueId = id; }
const VKBuiltInAttr *getBuiltInAttr() const { return builtinAttr; }
std::string getSemanticStr() const;
uint32_t getSemanticIndex() const { return semanticIndex; }
@ -75,6 +80,8 @@ private:
llvm::StringRef semanticName;
/// HLSL semantic index.
uint32_t semanticIndex;
/// SPIR-V BuiltIn attribute.
const VKBuiltInAttr *builtinAttr;
/// SPIR-V <type-id>.
uint32_t typeId;
/// SPIR-V <result-id>.

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

@ -397,7 +397,7 @@ bool GlPerVertex::tryToAccess(hlsl::SigPoint::Kind sigPointKind,
if (semanticKind == hlsl::Semantic::Kind::Position)
return false; // Fall back to the normal path
// Fall through
// Fall through
case hlsl::SigPoint::Kind::HSCPIn:
case hlsl::SigPoint::Kind::DSCPIn:
@ -409,7 +409,7 @@ bool GlPerVertex::tryToAccess(hlsl::SigPoint::Kind sigPointKind,
if (semanticKind == hlsl::Semantic::Kind::Position)
return false; // Fall back to the normal path
// Fall through
// Fall through
case hlsl::SigPoint::Kind::VSOut:
case hlsl::SigPoint::Kind::HSCPOut:
@ -423,19 +423,41 @@ bool GlPerVertex::tryToAccess(hlsl::SigPoint::Kind sigPointKind,
return false;
}
uint32_t GlPerVertex::readPosition() const {
assert(inIsGrouped); // We do not handle stand-alone Position builtin here.
bool GlPerVertex::tryToAccessPointSize(hlsl::SigPoint::Kind sigPointKind,
llvm::Optional<uint32_t> invocation,
uint32_t *value, bool noWriteBack) {
switch (sigPointKind) {
case hlsl::SigPoint::Kind::HSCPIn:
case hlsl::SigPoint::Kind::DSCPIn:
case hlsl::SigPoint::Kind::GSVIn:
*value = readPositionOrPointSize(/*isPosition=*/false);
return true;
case hlsl::SigPoint::Kind::VSOut:
case hlsl::SigPoint::Kind::HSCPOut:
case hlsl::SigPoint::Kind::DSOut:
writePositionOrPointSize(/*isPosition=*/false, invocation, *value);
return true;
}
return false; // Fall back to normal path: GSOut
}
uint32_t GlPerVertex::readPositionOrPointSize(bool isPosition) const {
// We do not handle stand-alone Position/PointSize builtin here.
assert(inIsGrouped);
// The PointSize builtin is always of float type.
// The Position builtin is always of float4 type.
const uint32_t f32Type = theBuilder.getFloat32Type();
const uint32_t fieldType =
theBuilder.getVecType(theBuilder.getFloat32Type(), 4);
isPosition ? theBuilder.getVecType(f32Type, 4) : f32Type;
const uint32_t ptrType =
theBuilder.getPointerType(fieldType, spv::StorageClass::Input);
const uint32_t fieldIndex = theBuilder.getConstantUint32(0);
const uint32_t fieldIndex = theBuilder.getConstantUint32(isPosition ? 0 : 1);
if (inArraySize == 0) {
// The input builtin block is a single block. Only need one index to
// locate the Position builtin.
// locate the Position/PointSize builtin.
const uint32_t ptr =
theBuilder.createAccessChain(ptrType, inBlockVar, {fieldIndex});
return theBuilder.createLoad(fieldType, ptr);
@ -448,13 +470,13 @@ uint32_t GlPerVertex::readPosition() const {
for (uint32_t i = 0; i < inArraySize; ++i) {
const uint32_t arrayIndex = theBuilder.getConstantUint32(i);
// Get pointer into the array of structs. We need two indices to locate
// the Position builtin now: the first one is the array index, and the
// second one is the struct index.
// the Position/PointSize builtin now: the first one is the array index,
// and the second one is the struct index.
const uint32_t ptr = theBuilder.createAccessChain(ptrType, inBlockVar,
{arrayIndex, fieldIndex});
elements.push_back(theBuilder.createLoad(fieldType, ptr));
}
// Construct a new array of float4 for the Position builtins
// Construct a new array of float4/float for the Position/PointSize builtins
const uint32_t arrayType = theBuilder.getArrayType(
fieldType, theBuilder.getConstantUint32(inArraySize));
return theBuilder.createCompositeConstruct(arrayType, elements);
@ -575,7 +597,7 @@ bool GlPerVertex::readField(hlsl::Semantic::Kind semanticKind,
uint32_t semanticIndex, uint32_t *value) {
switch (semanticKind) {
case hlsl::Semantic::Kind::Position:
*value = readPosition();
*value = readPositionOrPointSize(/*isPosition=*/true);
return true;
case hlsl::Semantic::Kind::ClipDistance: {
const auto offsetIter = inClipOffset.find(semanticIndex);
@ -601,20 +623,24 @@ bool GlPerVertex::readField(hlsl::Semantic::Kind semanticKind,
return false;
}
void GlPerVertex::writePosition(llvm::Optional<uint32_t> invocationId,
uint32_t value) const {
assert(outIsGrouped); // We do not handle stand-alone Position builtin here.
void GlPerVertex::writePositionOrPointSize(
bool isPosition, llvm::Optional<uint32_t> invocationId,
uint32_t value) const {
// We do not handle stand-alone Position/PointSize builtin here.
assert(outIsGrouped);
// The Position builtin is always of float4 type.
// The PointSize builtin is always of float type.
const uint32_t f32Type = theBuilder.getFloat32Type();
const uint32_t fieldType =
theBuilder.getVecType(theBuilder.getFloat32Type(), 4);
isPosition ? theBuilder.getVecType(f32Type, 4) : f32Type;
const uint32_t ptrType =
theBuilder.getPointerType(fieldType, spv::StorageClass::Output);
const uint32_t fieldIndex = theBuilder.getConstantUint32(0);
const uint32_t fieldIndex = theBuilder.getConstantUint32(isPosition ? 0 : 1);
if (outArraySize == 0) {
// The input builtin block is a single block. Only need one index to
// locate the Position builtin.
// locate the Position/PointSize builtin.
const uint32_t ptr =
theBuilder.createAccessChain(ptrType, outBlockVar, {fieldIndex});
theBuilder.createStore(ptr, value);
@ -631,8 +657,8 @@ void GlPerVertex::writePosition(llvm::Optional<uint32_t> invocationId,
const uint32_t arrayIndex = invocationId.getValue();
// Get pointer into the array of structs. We need two indices to locate
// the Position builtin now: the first one is the array index, and the
// second one is the struct index.
// the Position/PointSize builtin now: the first one is the array index,
// and the second one is the struct index.
const uint32_t ptr = theBuilder.createAccessChain(ptrType, outBlockVar,
{arrayIndex, fieldIndex});
theBuilder.createStore(ptr, value);
@ -771,7 +797,7 @@ bool GlPerVertex::writeField(hlsl::Semantic::Kind semanticKind,
// out the value to the correct array element.
switch (semanticKind) {
case hlsl::Semantic::Kind::Position:
writePosition(invocationId, *value);
writePositionOrPointSize(/*isPosition=*/true, invocationId, *value);
return true;
case hlsl::Semantic::Kind::ClipDistance: {
const auto offsetIter = outClipOffset.find(semanticIndex);

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

@ -25,8 +25,9 @@ namespace spirv {
/// The class for representing special gl_PerVertex builtin interface block.
/// The Position, PointSize, ClipDistance, and CullDistance builtin should
/// be handled by this class, except for Position builtin used in GS output
/// and PS input.
/// be handled by this class, except for
/// * Position builtin used in GS output and PS input,
/// * PointSize builtin used in GS output.
///
/// Although the Vulkan spec does not require this directly, it seems the only
/// way to avoid violating the spec is to group the Position, ClipDistance, and
@ -101,10 +102,14 @@ public:
uint32_t semanticIndex, llvm::Optional<uint32_t> invocation,
uint32_t *value, bool noWriteBack);
/// Similar to tryToAccess, but only used for the PointSize builtin.
bool tryToAccessPointSize(hlsl::SigPoint::Kind sigPoint,
llvm::Optional<uint32_t> invocation,
uint32_t *value, bool noWriteBack);
private:
template <unsigned N>
DiagnosticBuilder emitError(const char (&message)[N],
SourceLocation loc) {
DiagnosticBuilder emitError(const char (&message)[N], SourceLocation loc) {
const auto diagId = astContext.getDiagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, message);
return astContext.getDiagnostics().Report(loc, diagId);
@ -121,8 +126,8 @@ private:
/// Creates a stand-alone CullDistance builtin variable.
uint32_t createCullDistanceVar(bool asInput, uint32_t arraySize);
/// Emits SPIR-V instructions for reading the Position builtin.
uint32_t readPosition() const;
/// Emits SPIR-V instructions for reading the Position/PointSize builtin.
uint32_t readPositionOrPointSize(bool isPosition) const;
/// Emits SPIR-V instructions for reading the data starting from offset in
/// the ClipDistance/CullDistance builtin. The data read will be transformed
/// into the given type asType.
@ -132,9 +137,10 @@ private:
bool readField(hlsl::Semantic::Kind semanticKind, uint32_t semanticIndex,
uint32_t *value);
/// Emits SPIR-V instructions for writing the Position builtin.
void writePosition(llvm::Optional<uint32_t> invocationId,
uint32_t value) const;
/// Emits SPIR-V instructions for writing the Position/PointSize builtin.
void writePositionOrPointSize(bool isPosition,
llvm::Optional<uint32_t> invocationId,
uint32_t value) const;
/// Emits SPIR-V instructions for writing data into the ClipDistance/
/// CullDistance builtin starting from offset. The value to be written is
/// fromValue, whose type is fromType. Necessary transformations will be

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

@ -10351,6 +10351,11 @@ void hlsl::HandleDeclAttributeForHLSL(Sema &S, Decl *D, const AttributeList &A,
Handled = true;
switch (A.getKind())
{
case AttributeList::AT_VKBuiltIn:
declAttr = ::new (S.Context) VKBuiltInAttr(A.getRange(), S.Context,
ValidateAttributeStringArg(S, A, "PointSize,HelperInvocation"),
A.getAttributeSpellingListIndex());
break;
case AttributeList::AT_VKLocation:
declAttr = ::new (S.Context) VKLocationAttr(A.getRange(), S.Context,
ValidateAttributeIntArg(S, A), A.getAttributeSpellingListIndex());

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

@ -0,0 +1,18 @@
// Run: %dxc -T ps_6_0 -E main
// CHECK: OpEntryPoint Fragment
// CHECK-SAME: %gl_HelperInvocation
// CHECK: OpDecorate %gl_HelperInvocation BuiltIn HelperInvocation
// CHECK: %gl_HelperInvocation = OpVariable %_ptr_Input_bool Input
float4 main([[vk::builtin("HelperInvocation")]] bool isHI : HI) : SV_Target {
// CHECK: [[val:%\d+]] = OpLoad %bool %gl_HelperInvocation
// CHECK-NEXT: OpStore %param_var_isHI [[val]]
float ret = 1.0;
if (isHI) ret = 2.0;
return ret;
}

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

@ -31,6 +31,8 @@ struct PerVertexIn {
float4 cull3 : SV_CullDistance3; // Builtin CullDistance
InnerPerVertexIn s;
float2 bar : BAR; // Input variable
[[vk::builtin("PointSize")]]
float ptSize : PSIZE; // Builtin PointSize
};
// Per-vertex output structs
@ -45,6 +47,8 @@ struct InnerPerVertexOut {
Inner2PerVertexOut s;
float2 cull4 : SV_CullDistance4; // Builtin CullDistance
float4 bar : BAR; // Output variable
[[vk::builtin("PointSize")]]
float ptSize : PSIZE; // Builtin PointSize
};
struct DsOut {
@ -280,22 +284,34 @@ DsOut main( const OutputPatch<PerVertexIn, 3> patch,
// CHECK-NEXT: [[inBarArr:%\d+]] = OpLoad %_arr_v2float_uint_3 %in_var_BAR
// Compose an array of input PointSize for later use
// CHECK-NEXT: [[ptr0:%\d+]] = OpAccessChain %_ptr_Input_float %gl_PerVertexIn %uint_0 %uint_1
// CHECK-NEXT: [[val0:%\d+]] = OpLoad %float [[ptr0]]
// CHECK-NEXT: [[ptr1:%\d+]] = OpAccessChain %_ptr_Input_float %gl_PerVertexIn %uint_1 %uint_1
// CHECK-NEXT: [[val1:%\d+]] = OpLoad %float [[ptr1]]
// CHECK-NEXT: [[ptr2:%\d+]] = OpAccessChain %_ptr_Input_float %gl_PerVertexIn %uint_2 %uint_1
// CHECK-NEXT: [[val2:%\d+]] = OpLoad %float [[ptr2]]
// CHECK-NEXT: [[inPtSizeArr:%\d+]] = OpCompositeConstruct %_arr_float_uint_3 [[val0]] [[val1]] [[val2]]
// Decompose temporary arrays created before to compose PerVertexIn
// CHECK-NEXT: [[field0:%\d+]] = OpCompositeExtract %v4float [[inCull3Arr]] 0
// CHECK-NEXT: [[field1:%\d+]] = OpCompositeExtract %InnerPerVertexIn [[inInPVArr]] 0
// CHECK-NEXT: [[field2:%\d+]] = OpCompositeExtract %v2float [[inBarArr]] 0
// CHECK-NEXT: [[val0:%\d+]] = OpCompositeConstruct %PerVertexIn [[field0]] [[field1]] [[field2]]
// CHECK-NEXT: [[field3:%\d+]] = OpCompositeExtract %float [[inPtSizeArr]] 0
// CHECK-NEXT: [[val0:%\d+]] = OpCompositeConstruct %PerVertexIn [[field0]] [[field1]] [[field2]] [[field3]]
// CHECK-NEXT: [[field0:%\d+]] = OpCompositeExtract %v4float [[inCull3Arr]] 1
// CHECK-NEXT: [[field1:%\d+]] = OpCompositeExtract %InnerPerVertexIn [[inInPVArr]] 1
// CHECK-NEXT: [[field2:%\d+]] = OpCompositeExtract %v2float [[inBarArr]] 1
// CHECK-NEXT: [[val1:%\d+]] = OpCompositeConstruct %PerVertexIn [[field0]] [[field1]] [[field2]]
// CHECK-NEXT: [[field3:%\d+]] = OpCompositeExtract %float [[inPtSizeArr]] 1
// CHECK-NEXT: [[val1:%\d+]] = OpCompositeConstruct %PerVertexIn [[field0]] [[field1]] [[field2]] [[field3]]
// CHECK-NEXT: [[field0:%\d+]] = OpCompositeExtract %v4float [[inCull3Arr]] 2
// CHECK-NEXT: [[field1:%\d+]] = OpCompositeExtract %InnerPerVertexIn [[inInPVArr]] 2
// CHECK-NEXT: [[field2:%\d+]] = OpCompositeExtract %v2float [[inBarArr]] 2
// CHECK-NEXT: [[val2:%\d+]] = OpCompositeConstruct %PerVertexIn [[field0]] [[field1]] [[field2]]
// CHECK-NEXT: [[field3:%\d+]] = OpCompositeExtract %float [[inPtSizeArr]] 2
// CHECK-NEXT: [[val2:%\d+]] = OpCompositeConstruct %PerVertexIn [[field0]] [[field1]] [[field2]] [[field3]]
// The final value for the patch parameter!
// CHECK-NEXT: [[patch:%\d+]] = OpCompositeConstruct %_arr_PerVertexIn_uint_3 [[val0]] [[val1]] [[val2]]
@ -355,6 +371,11 @@ DsOut main( const OutputPatch<PerVertexIn, 3> patch,
// CHECK-NEXT: [[bar:%\d+]] = OpCompositeExtract %v4float [[outInPV]] 2
// CHECK-NEXT: OpStore %out_var_BAR [[bar]]
// Decompose InnerPerVertexOut and write out DsOut.s.ptSize (PointSize)
// CHECK-NEXT: [[ptSize:%\d+]] = OpCompositeExtract %float [[outInPV]] 3
// CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Output_float %gl_PerVertexOut %uint_1
// CHECK-NEXT: OpStore [[ptr]] [[ptSize]]
// Write out clip5 (SV_ClipDistance5) at offset 1
// CHECK-NEXT: [[clip5:%\d+]] = OpLoad %v3float %param_var_clip5
// CHECK-NEXT: [[ptr0:%\d+]] = OpAccessChain %_ptr_Output_float %gl_PerVertexOut %uint_2 %uint_1

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

@ -9,12 +9,18 @@ struct GsPerVertexIn {
float3 clip2 : SV_ClipDistance2; // Builtin ClipDistance
float2 clip0 : SV_ClipDistance0; // Builtin ClipDistance
float3 foo : FOO; // Input variable
[[vk::builtin("PointSize")]]
float ptSize : PSIZE; // Builtin PointSize
};
struct GsInnerOut {
float4 pos : SV_Position; // Builtion Position
float2 foo : FOO; // Output variable
float2 cull3 : SV_CullDistance3; // Builtin CullDistance
[[vk::builtin("PointSize")]]
float ptSize : PSIZE; // Builtin PointSize
};
struct GsPerVertexOut {
@ -29,7 +35,7 @@ struct GsPerVertexOut {
// Input variable: FOO, BAR
// Output variable: FOO, BAR
// CHECK: OpEntryPoint Geometry %main "main" %gl_PerVertexIn %gl_ClipDistance %gl_CullDistance %in_var_BAR %in_var_FOO %gl_Position %out_var_FOO %out_var_BAR
// CHECK: OpEntryPoint Geometry %main "main" %gl_PerVertexIn %gl_ClipDistance %gl_CullDistance %in_var_BAR %in_var_FOO %gl_Position %out_var_FOO %gl_PointSize %out_var_BAR
// CHECK: OpMemberDecorate %type_gl_PerVertex 0 BuiltIn Position
// CHECK: OpMemberDecorate %type_gl_PerVertex 1 BuiltIn PointSize
@ -40,6 +46,7 @@ struct GsPerVertexOut {
// CHECK: OpDecorate %gl_ClipDistance BuiltIn ClipDistance
// CHECK: OpDecorate %gl_CullDistance BuiltIn CullDistance
// CHECK: OpDecorate %gl_Position BuiltIn Position
// CHECK: OpDecorate %gl_PointSize BuiltIn PointSize
// CHECK: OpDecorate %in_var_BAR Location 0
// CHECK: OpDecorate %in_var_FOO Location 1
@ -61,6 +68,7 @@ struct GsPerVertexOut {
// CHECK: %in_var_FOO = OpVariable %_ptr_Input__arr_v3float_uint_2 Input
// CHECK: %gl_Position = OpVariable %_ptr_Output_v4float Output
// CHECK: %out_var_FOO = OpVariable %_ptr_Output_v2float Output
// CHECK: %gl_PointSize = OpVariable %_ptr_Output_float Output
// CHECK: %out_var_BAR = OpVariable %_ptr_Output_v4float Output
[maxvertexcount(2)]
@ -128,16 +136,25 @@ void main(in line float2 bar [2] : BAR,
// CHECK-NEXT: [[inFooArr:%\d+]] = OpLoad %_arr_v3float_uint_2 %in_var_FOO
// Compose an array for GsPerVertexIn::ptSize
// CHECK-NEXT: [[ptr0:%\d+]] = OpAccessChain %_ptr_Input_float %gl_PerVertexIn %uint_0 %uint_1
// CHECK-NEXT: [[val0:%\d+]] = OpLoad %float [[ptr0]]
// CHECK-NEXT: [[ptr1:%\d+]] = OpAccessChain %_ptr_Input_float %gl_PerVertexIn %uint_1 %uint_1
// CHECK-NEXT: [[val1:%\d+]] = OpLoad %float [[ptr1]]
// CHECK-NEXT: [[inPtSzArr:%\d+]] = OpCompositeConstruct %_arr_float_uint_2 [[val0]] [[val1]]
// CHECK-NEXT: [[val0:%\d+]] = OpCompositeExtract %v4float [[inPosArr]] 0
// CHECK-NEXT: [[val1:%\d+]] = OpCompositeExtract %v3float [[inClip2Arr]] 0
// CHECK-NEXT: [[val2:%\d+]] = OpCompositeExtract %v2float [[inClip0Arr]] 0
// CHECK-NEXT: [[val3:%\d+]] = OpCompositeExtract %v3float [[inFooArr]] 0
// CHECK-NEXT: [[inData0:%\d+]] = OpCompositeConstruct %GsPerVertexIn [[val0]] [[val1]] [[val2]] [[val3]]
// CHECK-NEXT: [[val4:%\d+]] = OpCompositeExtract %float [[inPtSzArr]] 0
// CHECK-NEXT: [[inData0:%\d+]] = OpCompositeConstruct %GsPerVertexIn [[val0]] [[val1]] [[val2]] [[val3]] [[val4]]
// CHECK-NEXT: [[val0:%\d+]] = OpCompositeExtract %v4float [[inPosArr]] 1
// CHECK-NEXT: [[val1:%\d+]] = OpCompositeExtract %v3float [[inClip2Arr]] 1
// CHECK-NEXT: [[val2:%\d+]] = OpCompositeExtract %v2float [[inClip0Arr]] 1
// CHECK-NEXT: [[val3:%\d+]] = OpCompositeExtract %v3float [[inFooArr]] 1
// CHECK-NEXT: [[inData1:%\d+]] = OpCompositeConstruct %GsPerVertexIn [[val0]] [[val1]] [[val2]] [[val3]]
// CHECK-NEXT: [[val4:%\d+]] = OpCompositeExtract %float [[inPtSzArr]] 1
// CHECK-NEXT: [[inData1:%\d+]] = OpCompositeConstruct %GsPerVertexIn [[val0]] [[val1]] [[val2]] [[val3]] [[val4]]
// CHECK-NEXT: [[inData:%\d+]] = OpCompositeConstruct %_arr_GsPerVertexIn_uint_2 [[inData0]] [[inData1]]
// CHECK-NEXT: OpStore %param_var_inData [[inData]]

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

@ -16,12 +16,18 @@ struct HsCpIn
float3 cull3 : SV_CullDistance3; // Builtin CullDistance
float3 baz : BAZ; // Input variable
[[vk::builtin("PointSize")]]
float ptSize : PSIZE; // Builtin PointSize
};
struct CpInner2 {
float1 clip8 : SV_ClipDistance8; // Builtin ClipDistance
float2 cull6 : SV_CullDistance6; // Builtin CullDistance
float3 foo : FOO; // Output variable
[[vk::builtin("PointSize")]]
float ptSize : PSIZE; // Builtin PointSize
};
struct CpInner1 {
@ -203,6 +209,13 @@ HsCpOut main(InputPatch<HsCpIn, NumOutPoints> patch, uint cpId : SV_OutputContro
// CHECK-NEXT: [[inBazArr:%\d+]] = OpLoad %_arr_v3float_uint_2 %in_var_BAZ
// Read gl_PerVertex[].gl_PointSize[] to compose a new array for HsCpIn::ptSize
// CHECK-NEXT: [[ptr0:%\d+]] = OpAccessChain %_ptr_Input_float %gl_PerVertexIn %uint_0 %uint_1
// CHECK-NEXT: [[val0:%\d+]] = OpLoad %float [[ptr0]]
// CHECK-NEXT: [[ptr1:%\d+]] = OpAccessChain %_ptr_Input_float %gl_PerVertexIn %uint_1 %uint_1
// CHECK-NEXT: [[val1:%\d+]] = OpLoad %float [[ptr1]]
// CHECK-NEXT: [[inPtSzArr:%\d+]] = OpCompositeConstruct %_arr_float_uint_2 [[val0]] [[val1]]
// Compose a temporary HsCpIn value out of the temporary arrays constructed before
// CHECK-NEXT: [[val0:%\d+]] = OpCompositeExtract %v4float [[inPosArr]] 0
// CHECK-NEXT: [[val1:%\d+]] = OpCompositeExtract %v2float [[inClip0Arr]] 0
@ -210,7 +223,8 @@ HsCpOut main(InputPatch<HsCpIn, NumOutPoints> patch, uint cpId : SV_OutputContro
// CHECK-NEXT: [[val3:%\d+]] = OpCompositeExtract %float [[inClip2Arr]] 0
// CHECK-NEXT: [[val4:%\d+]] = OpCompositeExtract %v3float [[inCull3Arr]] 0
// CHECK-NEXT: [[val5:%\d+]] = OpCompositeExtract %v3float [[inBazArr]] 0
// CHECK-NEXT: [[hscpin0:%\d+]] = OpCompositeConstruct %HsCpIn [[val0]] [[val1]] [[val2]] [[val3]] [[val4]] [[val5]]
// CHECK-NEXT: [[val6:%\d+]] = OpCompositeExtract %float [[inPtSzArr]] 0
// CHECK-NEXT: [[hscpin0:%\d+]] = OpCompositeConstruct %HsCpIn [[val0]] [[val1]] [[val2]] [[val3]] [[val4]] [[val5]] [[val6]]
// Compose a temporary HsCpIn value out of the temporary arrays constructed before
// CHECK-NEXT: [[val0:%\d+]] = OpCompositeExtract %v4float [[inPosArr]] 1
@ -219,7 +233,8 @@ HsCpOut main(InputPatch<HsCpIn, NumOutPoints> patch, uint cpId : SV_OutputContro
// CHECK-NEXT: [[val3:%\d+]] = OpCompositeExtract %float [[inClip2Arr]] 1
// CHECK-NEXT: [[val4:%\d+]] = OpCompositeExtract %v3float [[inCull3Arr]] 1
// CHECK-NEXT: [[val5:%\d+]] = OpCompositeExtract %v3float [[inBazArr]] 1
// CHECK-NEXT: [[hscpin1:%\d+]] = OpCompositeConstruct %HsCpIn [[val0]] [[val1]] [[val2]] [[val3]] [[val4]] [[val5]]
// CHECK-NEXT: [[val6:%\d+]] = OpCompositeExtract %float [[inPtSzArr]] 1
// CHECK-NEXT: [[hscpin1:%\d+]] = OpCompositeConstruct %HsCpIn [[val0]] [[val1]] [[val2]] [[val3]] [[val4]] [[val5]] [[val6]]
// Populate the temporary variables for function call
@ -273,6 +288,11 @@ HsCpOut main(InputPatch<HsCpIn, NumOutPoints> patch, uint cpId : SV_OutputContro
// CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Output_v3float %out_var_FOO [[invoId]]
// CHECK-NEXT: OpStore [[ptr]] [[foo]]
// Write out HsCpOut::CpInner1::CpInner2::PointSize to gl_PerVertex[].gl_PointSize
// CHECK-NEXT: [[ptSize:%\d+]] = OpCompositeExtract %float [[outInner2]] 3
// CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Output_float %gl_PerVertexOut [[invoId]] %uint_1
// CHECK-NEXT: OpStore [[ptr]] [[ptSize]]
// Write out HsCpOut::CpInner1::clip6 to gl_PerVertex[].gl_ClipDistance
// CHECK-NEXT: [[clip6:%\d+]] = OpCompositeExtract %float [[outInner1]] 2
// CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Output_float %gl_PerVertexOut [[invoId]] %uint_2 %uint_0

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

@ -45,16 +45,17 @@ struct VSOut {
InnerStruct s;
};
void main(out VSOut vsOut,
out float3 clipdis0 : SV_ClipDistance0, // -> BuiltIn ClipDistance in gl_PerVertex
inout float4 coord : TEXCOORD, // -> Input & output variable
out float culldis5 : SV_CullDistance5, // -> BuiltIn CullDistance in gl_PerVertex
out float culldis3 : SV_CullDistance3, // -> BuiltIn CullDistance in gl_PerVertex
out float culldis6 : SV_CullDistance6, // -> BuiltIn CullDistance in gl_PerVertex
in float4 inPos : SV_Position, // -> Input variable
in float2 inClip : SV_ClipDistance, // -> Input variable
in float3 inCull : SV_CullDistance0 // -> Input variable
) {
[[vk::builtin("PointSize")]]
float main(out VSOut vsOut,
out float3 clipdis0 : SV_ClipDistance0, // -> BuiltIn ClipDistance in gl_PerVertex
inout float4 coord : TEXCOORD, // -> Input & output variable
out float culldis5 : SV_CullDistance5, // -> BuiltIn CullDistance in gl_PerVertex
out float culldis3 : SV_CullDistance3, // -> BuiltIn CullDistance in gl_PerVertex
out float culldis6 : SV_CullDistance6, // -> BuiltIn CullDistance in gl_PerVertex
in float4 inPos : SV_Position, // -> Input variable
in float2 inClip : SV_ClipDistance, // -> Input variable
in float3 inCull : SV_CullDistance0 // -> Input variable
) : PSize { // -> Builtin PointSize
vsOut = (VSOut)0;
clipdis0 = 1.;
coord = 2.;
@ -63,6 +64,8 @@ void main(out VSOut vsOut,
culldis6 = 5.;
inPos = 6.;
return 7.;
// Layout of ClipDistance array:
// clipdis0: 3 floats, offset 0
// clipdis1: 2 floats, offset 3
@ -81,7 +84,10 @@ void main(out VSOut vsOut,
// CHECK-NEXT: [[inCull:%\d+]] = OpLoad %v3float %in_var_SV_CullDistance0
// CHECK-NEXT: OpStore %param_var_inCull [[inCull]]
// CHECK-NEXT: OpFunctionCall %void %src_main
// CHECK-NEXT: [[ptSize:%\d+]] = OpFunctionCall %float %src_main
// CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Output_float %gl_PerVertexOut %uint_1
// CHECK-NEXT: OpStore [[ptr]] [[ptSize]]
// Write out COLOR
// CHECK-NEXT: [[vsOut:%\d+]] = OpLoad %VSOut %param_var_vsOut

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

@ -936,6 +936,10 @@ TEST_F(FileTest, SpirvEntryFunctionInOut) {
runFileTest("spirv.entry-function.inout.hlsl");
}
TEST_F(FileTest, SpirvBuiltInHelperInvocation) {
runFileTest("spirv.builtin.helper-invocation.hlsl");
}
// For shader stage input/output interface
// For semantic SV_Position, SV_ClipDistance, SV_CullDistance
TEST_F(FileTest, SpirvStageIOInterfaceVS) {