Implement 4 AMD-specific extensions.

- Support GL_AMD_shader_ballot (SPV_AMD_shader_ballot).
- Support GL_AMD_shader_trinary_minmax (SPV_AMD_shader_trinary_minmax).
- Support GL_AMD_shader_explicit_vertex_parameter
  (SPV_AMD_shader_explicit_vertex_parameter).
- Support GL_AMD_gcn_shader (SPV_AMD_gcn_shader).
This commit is contained in:
Rex Xu
2016-05-05 12:30:44 +08:00
parent 934855a642
commit 9d93a2370d
20 changed files with 5425 additions and 4120 deletions

View File

@@ -43,6 +43,9 @@
#include "SpvBuilder.h"
namespace spv {
#include "GLSL.std.450.h"
#ifdef AMD_EXTENSIONS
#include "GLSL.ext.AMD.h"
#endif
}
// Glslang includes
@@ -147,9 +150,9 @@ protected:
spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id destTypeId, spv::Id operand, glslang::TBasicType typeProxy);
spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
spv::Id createInvocationsOperation(glslang::TOperator, spv::Id typeId, spv::Id operand);
spv::Id createInvocationsOperation(glslang::TOperator, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy);
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
spv::Id createNoArgOperation(glslang::TOperator op);
spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId);
spv::Id getSymbolId(const glslang::TIntermSymbol* node);
void addDecoration(spv::Id id, spv::Decoration dec);
void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
@@ -160,6 +163,7 @@ protected:
bool isTrivialLeaf(const glslang::TIntermTyped* node);
bool isTrivial(const glslang::TIntermTyped* node);
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
spv::Id getExtBuiltins(const char* name);
spv::Function* shaderEntry;
spv::Instruction* entryPoint;
@@ -175,6 +179,7 @@ protected:
std::set<spv::Id> iOSet; // all input/output variables from either static use or declaration of interface
const glslang::TIntermediate* glslangIntermediate;
spv::Id stdBuiltins;
std::unordered_map<const char*, spv::Id> extBuiltinMap;
std::unordered_map<int, spv::Id> symbolValues;
std::unordered_set<int> constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
@@ -371,6 +376,10 @@ spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qual
return spv::DecorationNoPerspective;
else if (qualifier.flat)
return spv::DecorationFlat;
#ifdef AMD_EXTENSIONS
else if (qualifier.explicitInterp)
return spv::DecorationExplicitInterpAMD;
#endif
else
return spv::DecorationMax;
}
@@ -508,6 +517,15 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI
// TODO: Add SPIR-V builtin ID.
logger->missingFunctionality("shader ballot");
return spv::BuiltInMax;
#ifdef AMD_EXTENSIONS
case glslang::EbvBaryCoordNoPersp: return spv::BuiltInBaryCoordNoPerspAMD;
case glslang::EbvBaryCoordNoPerspCentroid: return spv::BuiltInBaryCoordNoPerspCentroidAMD;
case glslang::EbvBaryCoordNoPerspSample: return spv::BuiltInBaryCoordNoPerspSampleAMD;
case glslang::EbvBaryCoordSmooth: return spv::BuiltInBaryCoordSmoothAMD;
case glslang::EbvBaryCoordSmoothCentroid: return spv::BuiltInBaryCoordSmoothCentroidAMD;
case glslang::EbvBaryCoordSmoothSample: return spv::BuiltInBaryCoordSmoothSampleAMD;
case glslang::EbvBaryCoordPullModel: return spv::BuiltInBaryCoordPullModelAMD;
#endif
default: return spv::BuiltInMax;
}
}
@@ -628,6 +646,10 @@ void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& pa
child.invariant = true;
if (parent.nopersp)
child.nopersp = true;
#ifdef AMD_EXTENSIONS
if (parent.explicitInterp)
child.explicitInterp = true;
#endif
if (parent.flat)
child.flat = true;
if (parent.centroid)
@@ -1484,6 +1506,9 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
break;
case glslang::EOpInterpolateAtSample:
case glslang::EOpInterpolateAtOffset:
#ifdef AMD_EXTENSIONS
case glslang::EOpInterpolateAtVertex:
#endif
if (arg == 0)
lvalue = true;
break;
@@ -1524,7 +1549,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
// Pass through to generic operations.
switch (glslangOperands.size()) {
case 0:
result = createNoArgOperation(node->getOp());
result = createNoArgOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()));
break;
case 1:
result = createUnaryOperation(
@@ -3169,6 +3194,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec
spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy)
{
spv::Op unaryOp = spv::OpNop;
int extBuiltins = -1;
int libCall = -1;
bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
@@ -3448,7 +3474,32 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
case glslang::EOpAnyInvocation:
case glslang::EOpAllInvocations:
case glslang::EOpAllInvocationsEqual:
return createInvocationsOperation(op, typeId, operand);
#ifdef AMD_EXTENSIONS
case glslang::EOpMinInvocations:
case glslang::EOpMaxInvocations:
case glslang::EOpAddInvocations:
case glslang::EOpMinInvocationsNonUniform:
case glslang::EOpMaxInvocationsNonUniform:
case glslang::EOpAddInvocationsNonUniform:
#endif
return createInvocationsOperation(op, typeId, operand, typeProxy);
#ifdef AMD_EXTENSIONS
case glslang::EOpMbcnt:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
libCall = spv::MbcntAMD;
break;
case glslang::EOpCubeFaceIndex:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
libCall = spv::CubeFaceIndexAMD;
break;
case glslang::EOpCubeFaceCoord:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
libCall = spv::CubeFaceCoordAMD;
break;
#endif
default:
return 0;
@@ -3458,7 +3509,7 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
if (libCall >= 0) {
std::vector<spv::Id> args;
args.push_back(operand);
id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, args);
id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, args);
} else {
id = builder.createUnaryOp(unaryOp, typeId, operand);
}
@@ -3765,12 +3816,20 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
}
// Create group invocation operations.
spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, spv::Id operand)
spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy)
{
bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
builder.addCapability(spv::CapabilityGroups);
std::vector<spv::Id> operands;
operands.push_back(builder.makeUintConstant(spv::ScopeSubgroup));
#ifdef AMD_EXTENSIONS
if (op == glslang::EOpMinInvocations || op == glslang::EOpMaxInvocations || op == glslang::EOpAddInvocations ||
op == glslang::EOpMinInvocationsNonUniform || op == glslang::EOpMaxInvocationsNonUniform || op == glslang::EOpAddInvocationsNonUniform)
operands.push_back(spv::GroupOperationReduce);
#endif
operands.push_back(operand);
switch (op) {
@@ -3786,6 +3845,74 @@ spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op
return builder.createBinOp(spv::OpLogicalOr, typeId, groupAll,
builder.createUnaryOp(spv::OpLogicalNot, typeId, groupAny));
}
#ifdef AMD_EXTENSIONS
case glslang::EOpMinInvocations:
case glslang::EOpMaxInvocations:
case glslang::EOpAddInvocations:
{
spv::Op spvOp = spv::OpNop;
if (op == glslang::EOpMinInvocations) {
if (isFloat)
spvOp = spv::OpGroupFMin;
else {
if (isUnsigned)
spvOp = spv::OpGroupUMin;
else
spvOp = spv::OpGroupSMin;
}
} else if (op == glslang::EOpMaxInvocations) {
if (isFloat)
spvOp = spv::OpGroupFMax;
else {
if (isUnsigned)
spvOp = spv::OpGroupUMax;
else
spvOp = spv::OpGroupSMax;
}
} else {
if (isFloat)
spvOp = spv::OpGroupFAdd;
else
spvOp = spv::OpGroupIAdd;
}
return builder.createOp(spvOp, typeId, operands);
}
case glslang::EOpMinInvocationsNonUniform:
case glslang::EOpMaxInvocationsNonUniform:
case glslang::EOpAddInvocationsNonUniform:
{
spv::Op spvOp = spv::OpNop;
if (op == glslang::EOpMinInvocationsNonUniform) {
if (isFloat)
spvOp = spv::OpGroupFMinNonUniformAMD;
else {
if (isUnsigned)
spvOp = spv::OpGroupUMinNonUniformAMD;
else
spvOp = spv::OpGroupSMinNonUniformAMD;
}
}
else if (op == glslang::EOpMaxInvocationsNonUniform) {
if (isFloat)
spvOp = spv::OpGroupFMaxNonUniformAMD;
else {
if (isUnsigned)
spvOp = spv::OpGroupUMaxNonUniformAMD;
else
spvOp = spv::OpGroupSMaxNonUniformAMD;
}
}
else {
if (isFloat)
spvOp = spv::OpGroupFAddNonUniformAMD;
else
spvOp = spv::OpGroupIAddNonUniformAMD;
}
return builder.createOp(spvOp, typeId, operands);
}
#endif
default:
logger->missingFunctionality("invocation operation");
return spv::NoResult;
@@ -3798,6 +3925,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
spv::Op opCode = spv::OpNop;
int extBuiltins = -1;
int libCall = -1;
size_t consumedOperands = operands.size();
spv::Id typeId0 = 0;
@@ -3941,6 +4069,60 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
libCall = spv::GLSLstd450Bad;
break;
#ifdef AMD_EXTENSIONS
case glslang::EOpSwizzleInvocations:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
libCall = spv::SwizzleInvocationsAMD;
break;
case glslang::EOpSwizzleInvocationsMasked:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
libCall = spv::SwizzleInvocationsMaskedAMD;
break;
case glslang::EOpWriteInvocation:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
libCall = spv::WriteInvocationAMD;
break;
case glslang::EOpMin3:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
if (isFloat)
libCall = spv::FMin3AMD;
else {
if (isUnsigned)
libCall = spv::UMin3AMD;
else
libCall = spv::SMin3AMD;
}
break;
case glslang::EOpMax3:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
if (isFloat)
libCall = spv::FMax3AMD;
else {
if (isUnsigned)
libCall = spv::UMax3AMD;
else
libCall = spv::SMax3AMD;
}
break;
case glslang::EOpMid3:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
if (isFloat)
libCall = spv::FMid3AMD;
else {
if (isUnsigned)
libCall = spv::UMid3AMD;
else
libCall = spv::SMid3AMD;
}
break;
case glslang::EOpInterpolateAtVertex:
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
libCall = spv::InterpolateAtVertexAMD;
break;
#endif
default:
return 0;
}
@@ -3951,7 +4133,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
// Construct the call arguments, without modifying the original operands vector.
// We might need the remaining arguments, e.g. in the EOpFrexp case.
std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);
id = builder.createBuiltinCall(typeId, stdBuiltins, libCall, callArguments);
id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, callArguments);
} else {
switch (consumedOperands) {
case 0:
@@ -3997,8 +4179,8 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
return builder.setPrecision(id, precision);
}
// Intrinsics with no arguments, no return value, and no precision.
spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
// Intrinsics with no arguments (or no return value, and no precision).
spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId)
{
// TODO: get the barrier operands correct
@@ -4045,6 +4227,14 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
// Control barrier with non-"None" semantic is also a memory barrier.
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask);
return 0;
#ifdef AMD_EXTENSIONS
case glslang::EOpTime:
{
std::vector<spv::Id> args; // Dummy arguments
spv::Id id = builder.createBuiltinCall(typeId, getExtBuiltins(spv::E_SPV_AMD_gcn_shader), spv::TimeAMD, args);
return builder.setPrecision(id, precision);
}
#endif
default:
logger->missingFunctionality("unknown operation with no arguments");
return 0;
@@ -4437,6 +4627,20 @@ spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslan
return builder.createOp(spv::OpPhi, boolTypeId, phiOperands);
}
// Return type Id of the imported set of extended instructions corresponds to the name.
// Import this set if it has not been imported yet.
spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name)
{
if (extBuiltinMap.find(name) != extBuiltinMap.end())
return extBuiltinMap[name];
else {
builder.addExtensions(name);
spv::Id extBuiltins = builder.import(name);
extBuiltinMap[name] = extBuiltins;
return extBuiltins;
}
}
}; // end anonymous namespace
namespace glslang {