-
Notifications
You must be signed in to change notification settings - Fork 965
Add support for SPV_KHR_constant_data and SPV_KHR_abort #4196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e0cfe59
7fa0e24
da855bd
e0fc6bd
42ba270
7310ffa
6eadc2b
2140ff5
71eef95
d219610
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -246,6 +246,7 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser { | |
| spv::Id translateForcedType(spv::Id object); | ||
| spv::Id createCompositeConstruct(spv::Id typeId, std::vector<spv::Id> constituents); | ||
| void recordDescHeapAccessChainInfo(glslang::TIntermBinary* node); | ||
| void createAbortEXT(const glslang::TIntermSequence glslangOperands); | ||
|
|
||
| glslang::SpvOptions& options; | ||
| spv::Function* shaderEntry; | ||
|
|
@@ -3136,6 +3137,101 @@ spv::Id TGlslangToSpvTraverser::createCompositeConstruct(spv::Id resultTypeId, s | |
| return builder.createCompositeConstruct(resultTypeId, constituents); | ||
| } | ||
|
|
||
| void TGlslangToSpvTraverser::createAbortEXT(const glslang::TIntermSequence glslangOperands) | ||
| { | ||
| bool isEmptyMsg = glslangOperands.size() == 0; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/ |
||
| // Add Capability and extensions. | ||
| builder.addCapability(spv::Capability::AbortKHR); | ||
| builder.addCapability(spv::Capability::ConstantDataKHR); | ||
| builder.addExtension(spv::E_SPV_KHR_constant_data); | ||
| builder.addExtension(spv::E_SPV_KHR_abort); | ||
|
|
||
| typedef struct constStrInfo { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit. No |
||
| glslang::TString string; | ||
| int specifierIndex; // -1 if not a specifier. | ||
| constStrInfo(glslang::TString str, int spec) : string(str), specifierIndex(spec){}; | ||
| } strInfo; | ||
|
|
||
| std::vector<strInfo> splitedStr, tempSplitedStr; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. grammar nit: s/ |
||
| const uint32_t formatSpecifiersSize = 4; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't recall whether this string splitting is required by the spec or whether the spec allows a simpler representation like a single
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://gitlab.khronos.org/GLSL/GLSL/-/merge_requests/132/diffs Spec mentioned in the end as:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I remember correctly, data is not simple char type now, but sub-strings. Discussed internally before. |
||
| const char* formatSpecifiers[formatSpecifiersSize] = {"%d", "%i", "%f", "%u"}; | ||
| // 1. Split original message string with format specifiers. | ||
| const glslang::TString* msg = !isEmptyMsg ? glslangOperands[0]->getAsConstantUnion()->getConstArray()[0].getSConst() | ||
| : new glslang::TString("\0"); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| splitedStr.push_back(strInfo(*const_cast<glslang::TString*>(msg), -1)); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to |
||
| for (uint32_t i = 0; i < formatSpecifiersSize; i++) { | ||
| for (uint32_t j = 0; j < splitedStr.size(); j++) { | ||
| auto str = splitedStr[j].string; | ||
| int specifierIndex = splitedStr[j].specifierIndex; | ||
| auto pos = str.find(formatSpecifiers[i]); | ||
| while (pos != std::string::npos) { | ||
| tempSplitedStr.push_back(strInfo(str.substr(0, pos), specifierIndex)); | ||
| tempSplitedStr.push_back(strInfo(glslang::TString(formatSpecifiers[i]), i)); | ||
| str = str.substr(pos + strlen(formatSpecifiers[i])); | ||
| pos = str.find(formatSpecifiers[i]); | ||
| } | ||
| if (str.size() > 0 || isEmptyMsg) | ||
| tempSplitedStr.push_back(strInfo(str, specifierIndex)); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Check for Note that This needs a test for an empty string and special handling for empty string literals (
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea. I'm now treating it as an empty string. |
||
| } | ||
| splitedStr.clear(); | ||
| splitedStr = tempSplitedStr; | ||
| tempSplitedStr.clear(); | ||
| } | ||
| // 2. Prepare to construct message struct variable, record members' types, data and offsets. | ||
| std::vector<int> structMemberOffsets; | ||
| std::vector<spv::Id> structMemberType; | ||
| std::vector<spv::Id> structLoadMemberType; | ||
| std::vector<spv::Id> structMemberData; | ||
| structMemberOffsets.push_back(0); | ||
| auto charType = builder.makeIntType(8); | ||
| for (auto elem : splitedStr) { | ||
| // 2.1 get sub string's length (if specifier, be spec const). | ||
| unsigned int strElemLen = isEmptyMsg ? 1 : elem.string.size(); | ||
| spv::Id constLen = builder.makeUintConstant(strElemLen); | ||
| spv::Op constDataOp = spv::Op::OpConstantDataKHR; | ||
| if (elem.specifierIndex >= 0) { | ||
| constLen = builder.createSpecConst(spv::Op::OpSpecConstant, builder.makeUintType(32), strElemLen); | ||
| constDataOp = spv::Op::OpSpecConstantDataKHR; | ||
| } | ||
| // 2.2 get sub string's array type (if specifier, be spec const). | ||
| auto strElemArrType = builder.makeArrayType(charType, constLen, 1); | ||
| auto strElemLoadArrType = builder.makeArrayType(charType, constLen, 1); | ||
| // 2.3 add sub string constant data | ||
| auto strElemConstData = builder.createConstData(constDataOp, strElemArrType, {elem.string.c_str()}); | ||
| // 2.4 add decoration for those sub string. | ||
| builder.addDecoration(strElemArrType, spv::Decoration::UTFCodePointsKHR); | ||
| builder.addDecoration(strElemLoadArrType, spv::Decoration::UTFCodePointsKHR); | ||
| builder.addDecoration(strElemLoadArrType, spv::Decoration::ArrayStride, 1); | ||
| // 2.5 Collect data and type for construct an internal message structure member. | ||
| structMemberType.push_back(strElemArrType); | ||
| structLoadMemberType.push_back(strElemLoadArrType); | ||
| structMemberOffsets.push_back(structMemberOffsets.back() + strElemLen); | ||
| structMemberData.push_back(strElemConstData); | ||
| } | ||
| structMemberOffsets.pop_back(); | ||
| // 3. Add extra following arguments/variables' types in member structure. | ||
| for (unsigned int i = 1; i < glslangOperands.size(); i++) { | ||
| spv::Builder::AccessChain save = builder.getAccessChain(); | ||
| builder.clearAccessChain(); | ||
| auto width = GetNumBits(glslangOperands[i]->getAsTyped()->getBasicType()); | ||
| structMemberOffsets.push_back(structMemberOffsets.back() + width / 8); | ||
| glslangOperands[i]->traverse(this); | ||
| structMemberData.push_back(accessChainLoad(glslangOperands[i]->getAsTyped()->getType())); | ||
| spv::Id reservedOpType = builder.getTypeId(structMemberData.back()); | ||
| structMemberType.push_back(reservedOpType); | ||
| structLoadMemberType.push_back(reservedOpType); | ||
|
|
||
| builder.setAccessChain(save); | ||
| } | ||
| // 4. Construct struct message variable, add abortExt instruction. | ||
| auto structLoadType = builder.makeStructType(structLoadMemberType, {}, "abortMessageLoadType"); | ||
| for (unsigned int i = 0; i < structMemberOffsets.size(); i++) | ||
| builder.addMemberDecoration(structLoadType, i, spv::Decoration::Offset, structMemberOffsets[i]); | ||
| auto structType = builder.makeStructType(structMemberType, {}, "abortMessage"); | ||
| auto messageVar = builder.createCompositeConstruct(structType, structMemberData); | ||
| builder.makeStatementTerminator(spv::Op::OpAbortKHR, {structLoadType, messageVar}, "post-abort"); | ||
| } | ||
|
|
||
| bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node) | ||
| { | ||
| SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); | ||
|
|
@@ -3873,6 +3969,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt | |
| glslang::TIntermSequence& glslangOperands = node->getSequence(); | ||
| std::vector<spv::Id> operands; | ||
| std::vector<spv::IdImmediate> memoryAccessOperands; | ||
| if (node->getOp() == glslang::EOpAbortEXT) { | ||
| createAbortEXT(glslangOperands); | ||
| return false; | ||
| } | ||
| for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) { | ||
| // special case l-value operands; there are just a few | ||
| bool lvalue = false; | ||
|
|
@@ -4073,6 +4173,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt | |
| break; | ||
| } | ||
| builder.clearAccessChain(); | ||
|
|
||
| if (invertedType != spv::NoType && arg == 0) | ||
| glslangOperands[0]->getAsBinaryNode()->getLeft()->traverse(this); | ||
| else | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1778,13 +1778,15 @@ bool Builder::isConstantOpCode(Op opcode) const | |
| case Op::OpConstantTrue: | ||
| case Op::OpConstantFalse: | ||
| case Op::OpConstant: | ||
| case Op::OpConstantDataKHR: | ||
| case Op::OpConstantComposite: | ||
| case Op::OpConstantCompositeReplicateEXT: | ||
| case Op::OpConstantSampler: | ||
| case Op::OpConstantNull: | ||
| case Op::OpSpecConstantTrue: | ||
| case Op::OpSpecConstantFalse: | ||
| case Op::OpSpecConstant: | ||
| case Op::OpSpecConstantDataKHR: | ||
| case Op::OpSpecConstantComposite: | ||
| case Op::OpSpecConstantCompositeReplicateEXT: | ||
| case Op::OpSpecConstantOp: | ||
|
|
@@ -1802,6 +1804,7 @@ bool Builder::isSpecConstantOpCode(Op opcode) const | |
| case Op::OpSpecConstantTrue: | ||
| case Op::OpSpecConstantFalse: | ||
| case Op::OpSpecConstant: | ||
| case Op::OpSpecConstantDataKHR: | ||
| case Op::OpSpecConstantComposite: | ||
| case Op::OpSpecConstantOp: | ||
| case Op::OpSpecConstantCompositeReplicateEXT: | ||
|
|
@@ -3468,6 +3471,29 @@ Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3) | |
| return op->getResultId(); | ||
| } | ||
|
|
||
| Id Builder::createConstData(Op opCode, Id typeId, const std::vector<const char*> operands) | ||
| { | ||
| Instruction* op = new Instruction(getUniqueId(), typeId, opCode); | ||
| op->reserveOperands(operands.size()); | ||
| for (auto id : operands) | ||
| op->addStringOperand(id); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the encoding use
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is 8 bit width elements here, so should be Bytes I think? |
||
| module.mapInstruction(op); | ||
| constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op)); | ||
|
|
||
| return op->getResultId(); | ||
| } | ||
|
|
||
| Id Builder::createSpecConst(Op opCode, Id typeId, const unsigned int literalOp) | ||
| { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is equivalent to builder.makeUintConstant(strElemLen, /specConstant=/true). Could you remove |
||
| Instruction* op = new Instruction(getUniqueId(), typeId, opCode); | ||
| op->reserveOperands(1); | ||
| op->addImmediateOperand(literalOp); | ||
| module.mapInstruction(op); | ||
| constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op)); | ||
|
|
||
| return op->getResultId(); | ||
| } | ||
|
|
||
| Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands) | ||
| { | ||
| Instruction* op = new Instruction(getUniqueId(), typeId, opCode); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will copy the vector on every call. Pass it by const reference, please.