[SPIR-V] add support for extension KHR_fragment_shading_barycentric (SV_Barycentrics) (#4638)

Implement latest `SV_Barycentrics` semantics in DXC, according to DXC wiki spec.

  For variant qualifier decorated baryCoord inputs, as KHR extension has no matched built-in, still mapped to Bary*AMD.

  Add support for using input as first parameter of GetAttributeAtVertex. This would expand input's dimension to meet extension spec.

  Merge some features from AMD_shader_explicit_parameter and current extension together for MSAA usage. Keep generated SPIR-V codes similar to GLSL as possible.

  With concern to HLSL/DXIL part, keep most type modification/variable decoration change in SPIRV trans unit.

  Remove AMD_shader_explicit_parameter related features.

  Support struct member as parameter of GetAttributeAtVertex.

  Support using Decorator for MSAA features.
This commit is contained in:
Chow 2023-05-31 21:48:52 +08:00 коммит произвёл GitHub
Родитель e2c42174d1
Коммит cd3b40bd2e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
19 изменённых файлов: 336 добавлений и 90 удалений

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

@ -297,10 +297,10 @@ Supported extensions
* SPV_EXT_mesh_shader
* SPV_EXT_shader_stencil_support
* SPV_AMD_shader_early_and_late_fragment_tests
* SPV_AMD_shader_explicit_vertex_parameter
* SPV_GOOGLE_hlsl_functionality1
* SPV_GOOGLE_user_type
* SPV_NV_mesh_shader
* SPV_KHR_fragment_shading_barycentric
Vulkan specific attributes
--------------------------
@ -1550,7 +1550,7 @@ some system-value (SV) semantic strings will be translated into SPIR-V
+---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
| SV_StencilRef | PSOut | ``FragStencilRefEXT`` | N/A | ``StencilExportEXT`` |
+---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
| SV_Barycentrics | PSIn | ``BaryCoord*AMD`` | N/A | ``Shader`` |
| SV_Barycentrics | PSIn | ``BaryCoord*KHR`` | N/A | ``FragmentBarycentricKHR`` |
+---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
| | GSOut | ``Layer`` | N/A | ``Geometry`` |
| +-------------+----------------------------------------+-----------------------+-----------------------------+

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

@ -48,7 +48,6 @@ enum class Extension {
EXT_shader_viewport_index_layer,
AMD_gpu_shader_half_float,
AMD_shader_early_and_late_fragment_tests,
AMD_shader_explicit_vertex_parameter,
GOOGLE_hlsl_functionality1,
GOOGLE_user_type,
NV_ray_tracing,
@ -57,6 +56,7 @@ enum class Extension {
EXT_shader_image_int64,
KHR_physical_storage_buffer,
KHR_vulkan_memory_model,
KHR_fragment_shader_barycentric,
Unknown,
};

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

@ -706,6 +706,9 @@ public:
void decoratePerTaskNV(SpirvInstruction *target, uint32_t offset,
SourceLocation);
/// \brief Decorates the given target with PerVertexKHR
void decoratePerVertexKHR(SpirvInstruction *argInst, SourceLocation);
/// \brief Decorates the given target with Coherent
void decorateCoherent(SpirvInstruction *target, SourceLocation);

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

@ -247,6 +247,11 @@ bool CapabilityVisitor::visit(SpirvDecoration *decor) {
loc);
break;
}
case spv::Decoration::PerVertexKHR: {
addExtension(Extension::KHR_fragment_shader_barycentric, "PerVertexKHR", loc);
addCapability(spv::Capability::FragmentBarycentricKHR);
break;
}
// Capabilities needed for built-ins
case spv::Decoration::BuiltIn: {
AddVulkanMemoryModelForVolatile(decor, loc);
@ -360,15 +365,14 @@ bool CapabilityVisitor::visit(SpirvDecoration *decor) {
addCapability(spv::Capability::CullDistance);
break;
}
case spv::BuiltIn::BaryCoordNoPerspAMD:
case spv::BuiltIn::BaryCoordNoPerspCentroidAMD:
case spv::BuiltIn::BaryCoordNoPerspSampleAMD:
case spv::BuiltIn::BaryCoordSmoothAMD:
case spv::BuiltIn::BaryCoordSmoothCentroidAMD:
case spv::BuiltIn::BaryCoordSmoothSampleAMD:
case spv::BuiltIn::BaryCoordPullModelAMD: {
addExtension(Extension::AMD_shader_explicit_vertex_parameter,
case spv::BuiltIn::BaryCoordKHR:
case spv::BuiltIn::BaryCoordNoPerspKHR: {
// SV_Barycentrics will have only two builtins
// But it is still allowed to decorate those two builtins with
// interpolation qualifier like centroid or sample.
addExtension(Extension::KHR_fragment_shader_barycentric,
"SV_Barycentrics", loc);
addCapability(spv::Capability::FragmentBarycentricKHR);
break;
}
case spv::BuiltIn::ShadingRateKHR:

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

@ -2643,7 +2643,7 @@ bool DeclResultIdMapper::createStageVars(
evalType = astContext.BoolTy;
break;
case hlsl::Semantic::Kind::Barycentrics:
evalType = astContext.getExtVectorType(astContext.FloatTy, 2);
evalType = astContext.getExtVectorType(astContext.FloatTy, 3);
break;
case hlsl::Semantic::Kind::DispatchThreadID:
case hlsl::Semantic::Kind::GroupThreadID:
@ -2774,15 +2774,16 @@ bool DeclResultIdMapper::createStageVars(
// Decorate with interpolation modes for pixel shader input variables
// or vertex shader output variables.
if (((spvContext.isPS() && sigPoint->IsInput()) ||
(spvContext.isVS() && sigPoint->IsOutput())) &&
// BaryCoord*AMD buitins already encode the interpolation mode.
semanticKind != hlsl::Semantic::Kind::Barycentrics)
decorateInterpolationMode(decl, type, varInstr);
if ((spvContext.isPS() && sigPoint->IsInput()) ||
(spvContext.isVS() && sigPoint->IsOutput()))
decorateInterpolationMode(decl, type, varInstr, *semanticToUse);
if (asInput) {
if (decl->getAttr<HLSLNoInterpolationAttr>()) {
spvBuilder.decoratePerVertexKHR(varInstr,
varInstr->getSourceLocation());
}
*value = spvBuilder.createLoad(evalType, varInstr, loc);
// Fix ups for corner cases
// Special handling of SV_TessFactor DS patch constant input.
@ -2857,8 +2858,8 @@ bool DeclResultIdMapper::createStageVars(
constOne, constZero, thisSemantic.loc);
}
// Special handling of SV_Barycentrics, which is a float3, but the
// underlying stage input variable is a float2 (only provides the first
// two components). Calculate the third element.
// The 3 values are NOT guaranteed to add up to floating-point 1.0 exactly.
// Calculate the third element here.
else if (semanticKind == hlsl::Semantic::Kind::Barycentrics) {
const auto x = spvBuilder.createCompositeExtract(
astContext.FloatTy, *value, {0}, thisSemantic.loc);
@ -3349,11 +3350,52 @@ DeclResultIdMapper::invertWIfRequested(SpirvInstruction *position,
void DeclResultIdMapper::decorateInterpolationMode(const NamedDecl *decl,
QualType type,
SpirvVariable *varInstr) {
SpirvVariable *varInstr,
const SemanticInfo semanticInfo)
{
if (varInstr->getStorageClass() != spv::StorageClass::Input &&
varInstr->getStorageClass() != spv::StorageClass::Output) {
return;
}
const bool isBaryCoord = (semanticInfo.getKind() == hlsl::Semantic::Kind::Barycentrics);
uint32_t semanticIndex = semanticInfo.index;
if (isBaryCoord) {
// BaryCentrics inputs cannot have attrib 'nointerpolation'.
if (decl->getAttr<HLSLNoInterpolationAttr>()) {
emitError("SV_BaryCentrics inputs cannot have attribute 'nointerpolation'.",
decl->getLocation());
}
// SV_BaryCentrics could only have two index and apply to different inputs.
// The index should be 0 or 1, each index should be mapped to different
// interpolation type.
if (semanticIndex > 1) {
emitError("The index SV_BaryCentrics semantics could only be 1 or 0.",
decl->getLocation());
}
else if (noPerspBaryCentricsIndex < 2 && perspBaryCentricsIndex < 2) {
emitError("Cannot have more than 2 inputs with SV_BaryCentrics semantics.",
decl->getLocation());
}
else if (decl->getAttr<HLSLNoPerspectiveAttr>()) {
if (noPerspBaryCentricsIndex == 2 && perspBaryCentricsIndex != semanticIndex) {
noPerspBaryCentricsIndex = semanticIndex;
}
else {
emitError("Cannot have more than 1 noperspective inputs with SV_BaryCentrics semantics.",
decl->getLocation());
}
}
else {
if (perspBaryCentricsIndex == 2 && noPerspBaryCentricsIndex != semanticIndex) {
perspBaryCentricsIndex = semanticIndex;
}
else{
emitError("Cannot have more than 1 perspective-correct inputs with SV_BaryCentrics semantics.",
decl->getLocation());
}
}
}
const auto loc = decl->getLocation();
if (isUintOrVecMatOfUintType(type) || isSintOrVecMatOfSintType(type) ||
@ -3374,9 +3416,9 @@ void DeclResultIdMapper::decorateInterpolationMode(const NamedDecl *decl,
// Attributes can be used together. So cannot use else if.
if (decl->getAttr<HLSLCentroidAttr>())
spvBuilder.decorateCentroid(varInstr, loc);
if (decl->getAttr<HLSLNoInterpolationAttr>())
if (decl->getAttr<HLSLNoInterpolationAttr>() && !isBaryCoord)
spvBuilder.decorateFlat(varInstr, loc);
if (decl->getAttr<HLSLNoPerspectiveAttr>())
if (decl->getAttr<HLSLNoPerspectiveAttr>() && !isBaryCoord)
spvBuilder.decorateNoPerspective(varInstr, loc);
if (decl->getAttr<HLSLSampleAttr>()) {
spvBuilder.decorateSample(varInstr, loc);
@ -3467,7 +3509,6 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
const auto sigPointKind = sigPoint->GetKind();
const auto type = stageVar->getAstType();
const auto isPrecise = decl->hasAttr<HLSLPreciseAttr>();
spv::StorageClass sc = getStorageClassForSigPoint(sigPoint);
if (sc == spv::StorageClass::Max)
return 0;
@ -3741,21 +3782,9 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
// Selecting the correct builtin according to interpolation mode
auto bi = BuiltIn::Max;
if (decl->hasAttr<HLSLNoPerspectiveAttr>()) {
if (decl->hasAttr<HLSLCentroidAttr>()) {
bi = BuiltIn::BaryCoordNoPerspCentroidAMD;
} else if (decl->hasAttr<HLSLSampleAttr>()) {
bi = BuiltIn::BaryCoordNoPerspSampleAMD;
} else {
bi = BuiltIn::BaryCoordNoPerspAMD;
}
bi = BuiltIn::BaryCoordNoPerspKHR;
} else {
if (decl->hasAttr<HLSLCentroidAttr>()) {
bi = BuiltIn::BaryCoordSmoothCentroidAMD;
} else if (decl->hasAttr<HLSLSampleAttr>()) {
bi = BuiltIn::BaryCoordSmoothSampleAMD;
} else {
bi = BuiltIn::BaryCoordSmoothAMD;
}
bi = BuiltIn::BaryCoordKHR;
}
return spvBuilder.addStageBuiltinVar(type, sc, bi, isPrecise, srcLoc);

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

@ -714,7 +714,7 @@ private:
/// Decorates varInstr of the given asType with proper interpolation modes
/// considering the attributes on the given decl.
void decorateInterpolationMode(const NamedDecl *decl, QualType asType,
SpirvVariable *varInstr);
SpirvVariable *varInstr, const SemanticInfo semanticInfo);
/// Returns the proper SPIR-V storage class (Input or Output) for the given
/// SigPoint.
@ -893,6 +893,8 @@ private:
/// an additional SPIR-V optimization pass to flatten such structures.
bool needsFlatteningCompositeResources;
uint32_t perspBaryCentricsIndex, noPerspBaryCentricsIndex;
public:
/// The gl_PerVertex structs for both input and output
GlPerVertex glPerVertex;
@ -924,6 +926,7 @@ DeclResultIdMapper::DeclResultIdMapper(ASTContext &context,
spirvOptions(options), astContext(context), spvContext(spirvContext),
diags(context.getDiagnostics()), entryFunction(nullptr),
needsLegalization(false), needsFlatteningCompositeResources(false),
perspBaryCentricsIndex(2), noPerspBaryCentricsIndex(2),
glPerVertex(context, spirvContext, spirvBuilder) {}
bool DeclResultIdMapper::decorateStageIOLocations() {

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

@ -181,8 +181,6 @@ Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
Extension::AMD_gpu_shader_half_float)
.Case("SPV_AMD_shader_early_and_late_fragment_tests",
Extension::AMD_shader_early_and_late_fragment_tests)
.Case("SPV_AMD_shader_explicit_vertex_parameter",
Extension::AMD_shader_explicit_vertex_parameter)
.Case("SPV_GOOGLE_hlsl_functionality1",
Extension::GOOGLE_hlsl_functionality1)
.Case("SPV_GOOGLE_user_type", Extension::GOOGLE_user_type)
@ -197,6 +195,7 @@ Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
.Case("SPV_KHR_physical_storage_buffer",
Extension::KHR_physical_storage_buffer)
.Case("SPV_KHR_vulkan_memory_model", Extension::KHR_vulkan_memory_model)
.Case("SPV_KHR_fragment_shader_barycentric", Extension::KHR_fragment_shader_barycentric)
.Default(Extension::Unknown);
}
@ -238,8 +237,6 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
return "SPV_AMD_gpu_shader_half_float";
case Extension::AMD_shader_early_and_late_fragment_tests:
return "SPV_AMD_shader_early_and_late_fragment_tests";
case Extension::AMD_shader_explicit_vertex_parameter:
return "SPV_AMD_shader_explicit_vertex_parameter";
case Extension::GOOGLE_hlsl_functionality1:
return "SPV_GOOGLE_hlsl_functionality1";
case Extension::GOOGLE_user_type:
@ -258,6 +255,8 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
return "SPV_KHR_physical_storage_buffer";
case Extension::KHR_vulkan_memory_model:
return "SPV_KHR_vulkan_memory_model";
case Extension::KHR_fragment_shader_barycentric:
return "SPV_KHR_fragment_shader_barycentric";
default:
break;
}

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

@ -1543,6 +1543,13 @@ void SpirvBuilder::decoratePerTaskNV(SpirvInstruction *target, uint32_t offset,
mod->addDecoration(decor);
}
void SpirvBuilder::decoratePerVertexKHR(SpirvInstruction *target,
SourceLocation srcLoc) {
auto *decor = new (context)
SpirvDecoration(srcLoc, target, spv::Decoration::PerVertexKHR);
mod->addDecoration(decor);
}
void SpirvBuilder::decorateCoherent(SpirvInstruction *target,
SourceLocation srcLoc) {
auto *decor =

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

@ -1251,6 +1251,46 @@ SpirvInstruction *SpirvEmitter::loadIfAliasVarRef(const Expr *expr,
return instr;
}
QualType SpirvEmitter::expandNoInterpolationParamToArray(QualType type,
ParmVarDecl* param)
{
// Expand nointerpolation decorated parameter in entry function
// to be an array. Boolean types would be cast back to dstType
// when return values later in processGetAttributeAt()
QualType resultType = type;
if (type->isStructureType()) {
// For structure type inputs, only expand nointerpolation decorated field.
const auto *structDecl = type->getAs<RecordType>()->getDecl();
for (auto *field : structDecl->fields()) {
if (param->hasAttr<HLSLNoInterpolationAttr>() ||
(field->hasAttr<HLSLNoInterpolationAttr>() &&
!field->getType()->isArrayType())) {
QualType qtype = field->getType();
if (isBoolOrVecMatOfBoolType(qtype)) {
qtype = getUintTypeForBool(astContext, theCompilerInstance, qtype);
}
qtype = astContext.getConstantArrayType(qtype, llvm::APInt(32, 3),
clang::ArrayType::Normal, 0);
field->setType(qtype);
}
}
resultType = type;
} else if (param->hasAttr<HLSLNoInterpolationAttr>() &&
!type->isArrayType()) {
// Redecl parameter type as it will be used in later instrics process.
QualType qtype = type;
if (isBoolOrVecMatOfBoolType(qtype)) {
qtype = getUintTypeForBool(astContext, theCompilerInstance, type);
}
qtype = astContext.getConstantArrayType(qtype, llvm::APInt(32, 3),
clang::ArrayType::Normal, 0);
param->setType(qtype);
resultType = qtype;
}
return resultType;
}
bool SpirvEmitter::loadIfAliasVarRef(const Expr *varExpr,
SpirvInstruction **instr,
SourceRange rangeOverride) {
@ -5855,9 +5895,19 @@ SpirvInstruction *SpirvEmitter::doMemberExpr(const MemberExpr *expr,
return instr;
}
QualType elemType = expr->getType();
if (expr->getMemberDecl()->hasAttr<HLSLNoInterpolationAttr>() &&
!elemType->isArrayType()) {
if (isBoolOrVecMatOfBoolType(elemType)) {
elemType = getUintTypeForBool(astContext, theCompilerInstance, elemType);
}
elemType = astContext.getConstantArrayType(elemType, llvm::APInt(32, 3),
clang::ArrayType::Normal, 0);
}
const auto *fieldDecl = dyn_cast<FieldDecl>(expr->getMemberDecl());
if (!fieldDecl || !fieldDecl->isBitField()) {
return derefOrCreatePointerToValue(base->getType(), instr, expr->getType(),
return derefOrCreatePointerToValue(base->getType(), instr, elemType,
indices, loc, range);
}
@ -8600,6 +8650,10 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
retVal = processIntrinsicUsingGLSLInst(callExpr, glslOpcode, true, srcLoc,
srcRange);
break;
}
case hlsl::IntrinsicOp::IOP_GetAttributeAtVertex: {
retVal = processGetAttributeAtVertex(callExpr);
break;
}
INTRINSIC_SPIRV_OP_CASE(ddx, DPdx, true);
INTRINSIC_SPIRV_OP_CASE(ddx_coarse, DPdxCoarse, false);
@ -11539,6 +11593,78 @@ void SpirvEmitter::processMeshOutputCounts(const CallExpr *callExpr) {
}
}
SpirvInstruction*
SpirvEmitter::processGetAttributeAtVertex(const CallExpr *expr) {
const auto exprLoc = expr->getExprLoc();
const auto exprRange = expr->getSourceRange();
QualType arg0Type;
// arg1 : vertexId
const auto *arg1BaseExpr = doExpr(expr->getArg(1)->IgnoreParenLValueCasts());
const auto *arg1ConstExpr = dyn_cast<SpirvConstantInteger>(arg1BaseExpr);
const auto *vertexId = arg1ConstExpr->getValue().getRawData();
// arg0 : <NoInterpolation> decorated input
// Tip : for input with boolean type, we need to ignore implicit cast first,
// to match surrounded workaround cast expr.
auto *arg0NoCast = expr->getArg(0)->IgnoreCasts();
bool hasImplicitCast = false;
if (dyn_cast<CastExpr>(expr->getArg(0)->IgnoreParenLValueCasts())) {
// If stage inputs is boolean type, it has been cast to uint type.
hasImplicitCast = true;
}
if (dyn_cast<MemberExpr>(arg0NoCast)) {
// As a structure field
auto arg0Expr = (dyn_cast<MemberExpr>(arg0NoCast));
const auto *arg0NamedDecl = arg0Expr->getFoundDecl().getDecl();
if (!arg0NamedDecl->hasAttr<HLSLNoInterpolationAttr>() &&
!(dyn_cast<DeclRefExpr>(arg0Expr->getBase()))->getDecl()->hasAttr<HLSLNoInterpolationAttr>()) {
emitError("First parameter of GetAttributeAtVertex should be decorated with 'nointerpolation'.",
arg0NamedDecl->getLocation());
return nullptr;
}
arg0Type = dyn_cast<ValueDecl>(arg0NamedDecl)->getType()->getAsArrayTypeUnsafe()->getElementType();
} else {
// Normal type arg0
const auto *arg0ValDecl = (dyn_cast<DeclRefExpr>(arg0NoCast))->getDecl();
if (!arg0ValDecl->hasAttr<HLSLNoInterpolationAttr>()) {
emitError("First parameter of GetAttributeAtVertex should be decorated with 'nointerpolation'.",
arg0ValDecl->getLocation());
return nullptr;
}
arg0Type = (dyn_cast<VarDecl>(arg0ValDecl))->getType()->getAsArrayTypeUnsafe()->getElementType();
}
// Change to access chain instr
auto *arg0BaseExpr = doExpr(arg0NoCast);
auto *accessChainPtr = spvBuilder.createAccessChain( arg0Type, arg0BaseExpr,
spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, *vertexId)),
exprLoc, exprRange);
auto *loadPtr = spvBuilder.createLoad(arg0Type, accessChainPtr, exprLoc, exprRange);
if (hasImplicitCast) {
// For normal types, results will be followed with OpConvertXXX later.
// For boolean type, we need to emulate its results with specific result types.
// Add 'cast' emulation to get Boolean result.
if (arg0Type->isPointerType())
arg0Type = arg0Type->getPointeeType();
QualType elemType = {};
QualType retType = astContext.BoolTy;
uint32_t vecSize = 1;
if (isVectorType(arg0Type, &elemType, &vecSize)) {
retType = astContext.getExtVectorType(retType, vecSize);
}
auto *eqResult = castToBool(loadPtr, arg0Type, retType, exprLoc, exprRange);
QualType selectType = dyn_cast<CastExpr>(expr->getArg(0))->getType();
auto *result = castToType(eqResult, retType, selectType, exprLoc, exprRange);
return result;
} else {
return loadPtr;
}
}
SpirvConstant *SpirvEmitter::getValueZero(QualType type) {
{
QualType scalarType = {};
@ -12601,13 +12727,15 @@ bool SpirvEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
// Create temporary variables for holding function call arguments
llvm::SmallVector<SpirvInstruction *, 4> params;
for (const auto *param : decl->params()) {
const auto paramType = param->getType();
for (auto *param : decl->params()) {
QualType paramType = param->getType();
paramType = expandNoInterpolationParamToArray(paramType, param);
std::string tempVarName = "param.var." + param->getNameAsString();
auto *tempVar =
spvBuilder.addFnVar(paramType, param->getLocation(), tempVarName,
param->hasAttr<HLSLPreciseAttr>());
params.push_back(tempVar);
// Create the stage input variable for parameter not marked as pure out and

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

@ -162,6 +162,10 @@ private:
SpirvInstruction **aliasVarInstr,
SourceRange rangeOverride = {});
/// Redecl variable type for some special usage like PerVertexKHR decorated input.
///
QualType expandNoInterpolationParamToArray(QualType type, ParmVarDecl *param);
private:
/// Translates the given frontend binary operator into its SPIR-V equivalent
/// taking consideration of the operand type.
@ -622,6 +626,9 @@ private:
/// Process mesh shader intrinsics.
void processMeshOutputCounts(const CallExpr *callExpr);
/// Process GetAttributeAtVertex for barycentrics.
SpirvInstruction* processGetAttributeAtVertex(const CallExpr *expr);
/// Process ray query traceinline intrinsics.
SpirvInstruction *processTraceRayInline(const CXXMemberCallExpr *expr);

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

@ -0,0 +1,42 @@
// RUN: %dxc -T ps_6_1 -E main
enum VertexID {
FIRST = 0,
SECOND = 1,
THIRD = 2
};
struct PSInput
{
float4 position : SV_POSITION;
nointerpolation float3 color1 : COLOR1;
nointerpolation bool3 color2 : COLOR2;
};
// CHECK: OpCapability FragmentBarycentricKHR
// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
// CHECK: OpDecorate [[ivc:%\w+]] PerVertexKHR
// CHECK: OpDecorate [[ivc2:%\w+]] PerVertexKHR
// CHECK: [[ivc]] = OpVariable %_ptr_Input__arr_v3float_uint_3 Input
// CHECK: [[ivc2]] = OpVariable %_ptr_Input__arr_v3uint_uint_3 Input
// CHECK: [[pvi:%\w+]] = OpVariable %_ptr_Function_PSInput Function
// CHECK: [[pvi1:%\d+]] = OpLoad %v4float [[fragColor:%\w+]]
// CHECK: [[pvi2:%\d+]] = OpLoad %_arr_v3float_uint_3 [[ivc]]
// CHECK: [[pvi3:%\d+]] = OpLoad %_arr_v3uint_uint_3 [[ivc2]]
// CHECK: [[pvitmp:%\d+]] = OpCompositeConstruct %PSInput [[pvi1]] [[pvi2]] [[pvi3]]
// CHECK: OpStore [[pvi]] [[pvitmp]]
// CHECK: [[pvicall:%\d+]] = OpFunctionCall %v3float %src_main [[pvi]]
float3 main(PSInput input ) : SV_Target
{
float3 vColor0 = GetAttributeAtVertex( input.color1, VertexID::SECOND );
float3 vColor1 = GetAttributeAtVertex( input.color2, VertexID::THIRD );
return (vColor0 + vColor1);
}
// CHECK: [[input:%\w+]] = OpFunctionParameter %_ptr_Function_PSInput
// CHECK: [[color:%\w+]] = OpAccessChain %_ptr_Function__arr_v3float_uint_3 [[input]] %int_1
// CHECK: [[color1:%\w+]] = OpAccessChain %_ptr_Function__arr_v3uint_uint_3 [[input]] %int_2
// CHECK: [[result:%\w+]] = OpLoad %v3uint [[color10:%\w+]]
// CHECK: [[resultEq:%\w+]] = OpINotEqual %v3bool [[result]] [[constZeroUint:%\w+]]
// CHECK: [[resultSlt:%\w+]] = OpSelect %v3float [[resultEq]] [[constOneDst:%\w+]] [[constZeroDst:%\w+]]

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

@ -1,25 +1,42 @@
// RUN: %dxc -T ps_6_1 -E main
struct PSInput {
float4 position : SV_POSITION;
nointerpolation float3 color : COLOR;
enum VertexID {
FIRST = 0,
SECOND = 1,
THIRD = 2
};
cbuffer constants : register(b0) {
float4 g_constants;
// CHECK: OpCapability FragmentBarycentricKHR
// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
// CHECK: OpDecorate [[ivc:%\w+]] Flat
// CHECK: OpDecorate [[ivc]] PerVertexKHR
// CHECK: OpDecorate [[ivc2:%\w+]] Flat
// CHECK: OpDecorate [[ivc2]] PerVertexKHR
// CHECK: [[ivc]] = OpVariable %_ptr_Input__arr_v3float_uint_3 Input
// CHECK: [[ivc2]] = OpVariable %_ptr_Input__arr_v3uint_uint_3 Input
// CHECK: [[pvc:%\w+]] = OpVariable %_ptr_Function__arr_v3float_uint_3 Function
// CHECK: [[pvc2:%\w+]] = OpVariable %_ptr_Function__arr_v3uint_uint_3 Function
// CHECK: [[ivcl:%\d+]] = OpLoad %_arr_v3float_uint_3 [[ivc]]
// CHECK: OpStore [[pvc]] [[ivcl]]
// CHECK: [[ivcl2:%\d+]] = OpLoad %_arr_v3uint_uint_3 [[ivc2]]
// CHECK: OpStore [[pvc2]] [[ivcl2]]
float3 main( float3 vBaryWeights : SV_Barycentrics,
nointerpolation float3 Color : COLOR,
nointerpolation bool3 Color2 : COLOR2 ) : SV_Target
{
float3 vColor;
float3 vColor0 = GetAttributeAtVertex( Color, VertexID::FIRST );
float3 vColor1 = GetAttributeAtVertex( Color, VertexID::SECOND );
float3 vColor2 = GetAttributeAtVertex( Color2, VertexID::THIRD );
vColor = vBaryWeights.x*vColor0 + vBaryWeights.y*vColor1 + vColor2;
return vColor;
}
float4 main(PSInput input) : SV_TARGET {
uint cmp = (uint)(g_constants[0]);
// CHECK: 16:21: error: GetAttributeAtVertex intrinsic function unimplemented
float colorAtV0 = GetAttributeAtVertex(input.color, 0)[cmp];
// CHECK: 19:21: error: GetAttributeAtVertex intrinsic function unimplemented
float colorAtV1 = GetAttributeAtVertex(input.color, 1)[cmp];
// CHECK: 22:21: error: GetAttributeAtVertex intrinsic function unimplemented
float colorAtV2 = GetAttributeAtVertex(input.color, 2)[cmp];
return float4(colorAtV0, colorAtV1, colorAtV2, 0);
}
// CHECK: [[color:%\w+]] = OpFunctionParameter %_ptr_Function__arr_v3float_uint_3
// CHECK: [[color2:%\w+]] = OpFunctionParameter %_ptr_Function__arr_v3uint_uint_3
// CHECK: [[c0:%\w+]] = OpAccessChain %_ptr_Function_v3float [[color]] %uint_0
// CHECK: [[c0l:%\w+]] = OpLoad %v3float [[c0]]
// CHECK: OpStore [[vC0:%\w+]] [[c0l]]
// CHECK: [[c1Ne:%\w+]] = OpINotEqual %v3bool [[c1load:%\w+]] [[constZeroUint:%\w+]]
// CHECK: [[c1Sel:%\w+]] = OpSelect %v3float [[c1Ne]] [[constOneTarget:%\w+]] [[constZeroTarget:%\w+]]

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

@ -1,18 +1,19 @@
// RUN: %dxc -T ps_6_1 -E main
// CHECK: OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
// CHECK: OpEntryPoint Fragment
// CHECK-SAME: [[bary:%\d+]]
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordNoPerspCentroidAMD
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordNoPerspKHR
// CHECK: OpDecorate [[bary]] Centroid
// CHECK: [[bary]] = OpVariable %_ptr_Input_v2float Input
// CHECK: [[bary]] = OpVariable %_ptr_Input_v3float Input
float4 main(noperspective centroid float3 bary : SV_Barycentrics) : SV_Target {
return float4(bary, 1.0);
// CHECK: %param_var_bary = OpVariable %_ptr_Function_v3float Function
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v2float [[bary]]
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v3float [[bary]]
// CHECK-NEXT: [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
// CHECK-NEXT: [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
// CHECK-NEXT: [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

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

@ -1,18 +1,19 @@
// RUN: %dxc -T ps_6_1 -E main
// CHECK: OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
// CHECK: OpEntryPoint Fragment
// CHECK-SAME: [[bary:%\d+]]
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordNoPerspSampleAMD
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordNoPerspKHR
// CHECK: OpDecorate [[bary]] Sample
// CHECK: [[bary]] = OpVariable %_ptr_Input_v2float Input
// CHECK: [[bary]] = OpVariable %_ptr_Input_v3float Input
float4 main(noperspective sample float3 bary : SV_Barycentrics) : SV_Target {
return float4(bary, 1.0);
// CHECK: %param_var_bary = OpVariable %_ptr_Function_v3float Function
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v2float [[bary]]
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v3float [[bary]]
// CHECK-NEXT: [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
// CHECK-NEXT: [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
// CHECK-NEXT: [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

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

@ -1,18 +1,18 @@
// RUN: %dxc -T ps_6_1 -E main
// CHECK: OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
// CHECK: OpEntryPoint Fragment
// CHECK-SAME: [[bary:%\d+]]
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordNoPerspAMD
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordNoPerspKHR
// CHECK: [[bary]] = OpVariable %_ptr_Input_v2float Input
// CHECK: [[bary]] = OpVariable %_ptr_Input_v3float Input
float4 main(noperspective float3 bary : SV_Barycentrics) : SV_Target {
return float4(bary, 1.0);
// CHECK: %param_var_bary = OpVariable %_ptr_Function_v3float Function
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v2float [[bary]]
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v3float [[bary]]
// CHECK-NEXT: [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
// CHECK-NEXT: [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
// CHECK-NEXT: [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

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

@ -1,18 +1,19 @@
// RUN: %dxc -T ps_6_1 -E main
// CHECK: OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
// CHECK: OpEntryPoint Fragment
// CHECK-SAME: [[bary:%\d+]]
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordSmoothCentroidAMD
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordKHR
// CHECK: OpDecorate [[bary]] Centroid
// CHECK: [[bary]] = OpVariable %_ptr_Input_v2float Input
// CHECK: [[bary]] = OpVariable %_ptr_Input_v3float Input
float4 main(centroid float3 bary : SV_Barycentrics) : SV_Target {
return float4(bary, 1.0);
// CHECK: %param_var_bary = OpVariable %_ptr_Function_v3float Function
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v2float [[bary]]
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v3float [[bary]]
// CHECK-NEXT: [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
// CHECK-NEXT: [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
// CHECK-NEXT: [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

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

@ -1,18 +1,19 @@
// RUN: %dxc -T ps_6_1 -E main
// CHECK: OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
// CHECK: OpEntryPoint Fragment
// CHECK-SAME: [[bary:%\d+]]
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordSmoothSampleAMD
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordKHR
// CHECK: OpDecorate [[bary]] Sample
// CHECK: [[bary]] = OpVariable %_ptr_Input_v2float Input
// CHECK: [[bary]] = OpVariable %_ptr_Input_v3float Input
float4 main(sample float3 bary : SV_Barycentrics) : SV_Target {
return float4(bary, 1.0);
// CHECK: %param_var_bary = OpVariable %_ptr_Function_v3float Function
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v2float [[bary]]
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v3float [[bary]]
// CHECK-NEXT: [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
// CHECK-NEXT: [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
// CHECK-NEXT: [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

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

@ -1,18 +1,18 @@
// RUN: %dxc -T ps_6_1 -E main
// CHECK: OpExtension "SPV_AMD_shader_explicit_vertex_parameter"
// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
// CHECK: OpEntryPoint Fragment
// CHECK-SAME: [[bary:%\d+]]
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordSmoothAMD
// CHECK: OpDecorate [[bary]] BuiltIn BaryCoordKHR
// CHECK: [[bary]] = OpVariable %_ptr_Input_v2float Input
// CHECK: [[bary]] = OpVariable %_ptr_Input_v3float Input
float4 main(float3 bary : SV_Barycentrics) : SV_Target {
return float4(bary, 1.0);
// CHECK: %param_var_bary = OpVariable %_ptr_Function_v3float Function
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v2float [[bary]]
// CHECK-NEXT: [[c2:%\d+]] = OpLoad %v3float [[bary]]
// CHECK-NEXT: [[x:%\d+]] = OpCompositeExtract %float [[c2]] 0
// CHECK-NEXT: [[y:%\d+]] = OpCompositeExtract %float [[c2]] 1
// CHECK-NEXT: [[xy:%\d+]] = OpFAdd %float [[x]] [[y]]

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

@ -1393,7 +1393,10 @@ TEST_F(FileTest, IntrinsicsMultiPrefix) {
runFileTest("intrinsics.multiprefix.hlsl", Expect::Failure);
}
TEST_F(FileTest, IntrinsicsGetAttributeAtVertex) {
runFileTest("intrinsics.get-attribute-at-vertex.hlsl", Expect::Failure);
runFileTest("intrinsics.get-attribute-at-vertex.hlsl");
}
TEST_F(FileTest, IntrinsicsGetAttributeAtVertexBlock) {
runFileTest("intrinsics.get-attribute-at-vertex.b.hlsl");
}
TEST_F(FileTest, IntrinsicsDot4Add) {
runFileTest("intrinsics.dot4add.hlsl", Expect::Failure);