diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 4ac8e917e..614a3a9a1 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2021.0-dev", "SPIRV-Tools v2021.0-dev 23b92ce879bc9a7a927e71e98eef1f7e1d82552a" +"v2021.0-dev", "SPIRV-Tools v2021.0-dev a176685a2c84eb6c09ec716962a43bda10d74d3d" diff --git a/3rdparty/spirv-tools/include/generated/generators.inc b/3rdparty/spirv-tools/include/generated/generators.inc index 9e41e850a..ddad4fb44 100644 --- a/3rdparty/spirv-tools/include/generated/generators.inc +++ b/3rdparty/spirv-tools/include/generated/generators.inc @@ -26,4 +26,5 @@ {25, "Netease Games", "Messiah Shader Compiler", "Netease Games Messiah Shader Compiler"}, {26, "Xenia", "Xenia Emulator Microcode Translator", "Xenia Xenia Emulator Microcode Translator"}, {27, "Embark Studios", "Rust GPU Compiler Backend", "Embark Studios Rust GPU Compiler Backend"}, -{28, "gfx-rs community", "Naga", "gfx-rs community Naga"}, \ No newline at end of file +{28, "gfx-rs community", "Naga", "gfx-rs community Naga"}, +{29, "Mikkosoft Productions", "MSP Shader Compiler", "Mikkosoft Productions MSP Shader Compiler"}, \ No newline at end of file diff --git a/3rdparty/spirv-tools/include/spirv-tools/libspirv.h b/3rdparty/spirv-tools/include/spirv-tools/libspirv.h index d2b4754db..44989bd0b 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/libspirv.h +++ b/3rdparty/spirv-tools/include/spirv-tools/libspirv.h @@ -589,6 +589,8 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxLogicalPointer( // 3) Pointers that are actaul parameters on function calls do not have to point // to the same type pointed as the formal parameter. The types just need to // logically match. +// 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant +// for a first argument. SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetBeforeHlslLegalization( spv_validator_options options, bool val); diff --git a/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp b/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp index e7e7fc7aa..0c31a1827 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp @@ -136,6 +136,8 @@ class ValidatorOptions { // 3) Pointers that are actaul parameters on function calls do not have to // point to the same type pointed as the formal parameter. The types just // need to logically match. + // 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant + // for a first argument. void SetBeforeHlslLegalization(bool val) { spvValidatorOptionsSetBeforeHlslLegalization(options_, val); } diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index 1683d077f..e8b5b6982 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp @@ -838,6 +838,15 @@ Optimizer::PassToken CreateWrapOpKillPass(); // capabilities. Optimizer::PassToken CreateAmdExtToKhrPass(); +// Replaces the internal version of GLSLstd450 InterpolateAt* extended +// instructions with the externally valid version. The internal version allows +// an OpLoad of the interpolant for the first argument. This pass removes the +// OpLoad and replaces it with its pointer. glslang and possibly other +// frontends will create the internal version for HLSL. This pass will be part +// of HLSL legalization and should be called after interpolants have been +// propagated into their final positions. +Optimizer::PassToken CreateInterpolateFixupPass(); + } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/3rdparty/spirv-tools/source/opt/interp_fixup_pass.cpp b/3rdparty/spirv-tools/source/opt/interp_fixup_pass.cpp new file mode 100644 index 000000000..ad29e6a72 --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/interp_fixup_pass.cpp @@ -0,0 +1,131 @@ +// Copyright (c) 2021 The Khronos Group Inc. +// Copyright (c) 2021 Valve Corporation +// Copyright (c) 2021 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/interp_fixup_pass.h" + +#include +#include + +#include "ir_builder.h" +#include "source/opt/ir_context.h" +#include "type_manager.h" + +namespace spvtools { +namespace opt { + +namespace { + +// Input Operand Indices +static const int kSpvVariableStorageClassInIdx = 0; + +// Avoid unused variable warning/error on Linux +#ifndef NDEBUG +#define USE_ASSERT(x) assert(x) +#else +#define USE_ASSERT(x) ((void)(x)) +#endif + +// Folding rule function which attempts to replace |op(OpLoad(a),...)| +// by |op(a,...)|, where |op| is one of the GLSLstd450 InterpolateAt* +// instructions. Returns true if replaced, false otherwise. +bool ReplaceInternalInterpolate(IRContext* ctx, Instruction* inst, + const std::vector&) { + uint32_t glsl450_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + assert(glsl450_ext_inst_id != 0); + + uint32_t ext_opcode = inst->GetSingleWordInOperand(1); + + uint32_t op1_id = inst->GetSingleWordInOperand(2); + + Instruction* load_inst = ctx->get_def_use_mgr()->GetDef(op1_id); + if (load_inst->opcode() != SpvOpLoad) return false; + + Instruction* base_inst = load_inst->GetBaseAddress(); + USE_ASSERT(base_inst->opcode() == SpvOpVariable && + base_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx) == + SpvStorageClassInput && + "unexpected interpolant in InterpolateAt*"); + + uint32_t ptr_id = load_inst->GetSingleWordInOperand(0); + uint32_t op2_id = (ext_opcode != GLSLstd450InterpolateAtCentroid) + ? inst->GetSingleWordInOperand(3) + : 0; + + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl450_ext_inst_id}}); + new_operands.push_back( + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {ext_opcode}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}}); + if (op2_id != 0) new_operands.push_back({SPV_OPERAND_TYPE_ID, {op2_id}}); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +class InterpFoldingRules : public FoldingRules { + public: + explicit InterpFoldingRules(IRContext* ctx) : FoldingRules(ctx) {} + + protected: + virtual void AddFoldingRules() override { + uint32_t extension_id = + context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + + if (extension_id != 0) { + ext_rules_[{extension_id, GLSLstd450InterpolateAtCentroid}].push_back( + ReplaceInternalInterpolate); + ext_rules_[{extension_id, GLSLstd450InterpolateAtSample}].push_back( + ReplaceInternalInterpolate); + ext_rules_[{extension_id, GLSLstd450InterpolateAtOffset}].push_back( + ReplaceInternalInterpolate); + } + } +}; + +class InterpConstFoldingRules : public ConstantFoldingRules { + public: + InterpConstFoldingRules(IRContext* ctx) : ConstantFoldingRules(ctx) {} + + protected: + virtual void AddFoldingRules() override {} +}; + +} // namespace + +Pass::Status InterpFixupPass::Process() { + bool changed = false; + + // Traverse the body of the functions to replace instructions that require + // the extensions. + InstructionFolder folder( + context(), + std::unique_ptr(new InterpFoldingRules(context())), + MakeUnique(context())); + for (Function& func : *get_module()) { + func.ForEachInst([&changed, &folder](Instruction* inst) { + if (folder.FoldInstruction(inst)) { + changed = true; + } + }); + } + + return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/interp_fixup_pass.h b/3rdparty/spirv-tools/source/opt/interp_fixup_pass.h new file mode 100644 index 000000000..e112b6515 --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/interp_fixup_pass.h @@ -0,0 +1,54 @@ +// Copyright (c) 2021 The Khronos Group Inc. +// Copyright (c) 2021 Valve Corporation +// Copyright (c) 2021 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_INTERP_FIXUP_H +#define SOURCE_OPT_INTERP_FIXUP_H + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Replaces overloaded internal form for GLSLstd450Interpolate* instructions +// with external form. Specifically, removes OpLoad from the first argument +// and replaces it with the pointer for the OpLoad. glslang generates the +// internal form. This pass is called as part of glslang HLSL legalization. +class InterpFixupPass : public Pass { + public: + const char* name() const override { return "interp-fixup"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_INTERP_FIXUP_H diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 909442cc1..a5d10c3d1 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -155,7 +155,8 @@ Optimizer& Optimizer::RegisterLegalizationPasses() { .RegisterPass(CreateVectorDCEPass()) .RegisterPass(CreateDeadInsertElimPass()) .RegisterPass(CreateReduceLoadSizePass()) - .RegisterPass(CreateAggressiveDCEPass()); + .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateInterpolateFixupPass()); } Optimizer& Optimizer::RegisterPerformancePasses() { @@ -494,6 +495,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateWrapOpKillPass()); } else if (pass_name == "amd-ext-to-khr") { RegisterPass(CreateAmdExtToKhrPass()); + } else if (pass_name == "interpolate-fixup") { + RegisterPass(CreateInterpolateFixupPass()); } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", @@ -925,4 +928,9 @@ Optimizer::PassToken CreateAmdExtToKhrPass() { MakeUnique()); } +Optimizer::PassToken CreateInterpolateFixupPass() { + return MakeUnique( + MakeUnique()); +} + } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/passes.h b/3rdparty/spirv-tools/source/opt/passes.h index 1bc94c7e2..bfb34af71 100644 --- a/3rdparty/spirv-tools/source/opt/passes.h +++ b/3rdparty/spirv-tools/source/opt/passes.h @@ -46,6 +46,7 @@ #include "source/opt/inst_bindless_check_pass.h" #include "source/opt/inst_buff_addr_check_pass.h" #include "source/opt/inst_debug_printf_pass.h" +#include "source/opt/interp_fixup_pass.h" #include "source/opt/licm_pass.h" #include "source/opt/local_access_chain_convert_pass.h" #include "source/opt/local_redundancy_elimination.h" diff --git a/3rdparty/spirv-tools/source/reduce/reducer.cpp b/3rdparty/spirv-tools/source/reduce/reducer.cpp index 18eeaeb66..16bb94fe6 100644 --- a/3rdparty/spirv-tools/source/reduce/reducer.cpp +++ b/3rdparty/spirv-tools/source/reduce/reducer.cpp @@ -54,10 +54,10 @@ void Reducer::SetInterestingnessFunction( } Reducer::ReductionResultStatus Reducer::Run( - std::vector&& binary_in, std::vector* binary_out, + const std::vector& binary_in, std::vector* binary_out, spv_const_reducer_options options, spv_validator_options validator_options) { - std::vector current_binary(std::move(binary_in)); + std::vector current_binary(binary_in); spvtools::SpirvTools tools(target_env_); assert(tools.IsValid() && "Failed to create SPIRV-Tools interface"); @@ -138,13 +138,13 @@ void Reducer::AddDefaultReductionPasses() { } void Reducer::AddReductionPass( - std::unique_ptr&& finder) { + std::unique_ptr finder) { passes_.push_back( spvtools::MakeUnique(target_env_, std::move(finder))); -} +} void Reducer::AddCleanupReductionPass( - std::unique_ptr&& finder) { + std::unique_ptr finder) { cleanup_passes_.push_back( spvtools::MakeUnique(target_env_, std::move(finder))); } diff --git a/3rdparty/spirv-tools/source/reduce/reducer.h b/3rdparty/spirv-tools/source/reduce/reducer.h index 864ce7570..f3ba18066 100644 --- a/3rdparty/spirv-tools/source/reduce/reducer.h +++ b/3rdparty/spirv-tools/source/reduce/reducer.h @@ -84,17 +84,17 @@ class Reducer { // Adds a reduction pass based on the given finder to the sequence of passes // that will be iterated over. - void AddReductionPass(std::unique_ptr&& finder); + void AddReductionPass(std::unique_ptr finder); // Adds a cleanup reduction pass based on the given finder to the sequence of // passes that will run after other passes. void AddCleanupReductionPass( - std::unique_ptr&& finder); + std::unique_ptr finder); // Reduces the given SPIR-V module |binary_out|. // The reduced binary ends up in |binary_out|. // A status is returned. - ReductionResultStatus Run(std::vector&& binary_in, + ReductionResultStatus Run(const std::vector& binary_in, std::vector* binary_out, spv_const_reducer_options options, spv_validator_options validator_options); diff --git a/3rdparty/spirv-tools/source/val/validate_extensions.cpp b/3rdparty/spirv-tools/source/val/validate_extensions.cpp index dc8c0243a..a7167fc15 100644 --- a/3rdparty/spirv-tools/source/val/validate_extensions.cpp +++ b/3rdparty/spirv-tools/source/val/validate_extensions.cpp @@ -692,8 +692,8 @@ spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) { if (extension == ExtensionToString(kSPV_KHR_workgroup_memory_explicit_layout)) { return _.diag(SPV_ERROR_WRONG_VERSION, inst) - << "SPV_KHR_workgroup_memory_explicit_layout extension " - "requires SPIR-V version 1.4 or later."; + << "SPV_KHR_workgroup_memory_explicit_layout extension " + "requires SPIR-V version 1.4 or later."; } } @@ -1372,7 +1372,16 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { << "or vector type"; } - const uint32_t interpolant_type = _.GetOperandTypeId(inst, 4); + // If HLSL legalization and first operand is an OpLoad, use load + // pointer as the interpolant lvalue. Else use interpolate first + // operand. + uint32_t interp_id = inst->GetOperandAs(4); + auto* interp_inst = _.FindDef(interp_id); + uint32_t interpolant_type = (_.options()->before_hlsl_legalization && + interp_inst->opcode() == SpvOpLoad) + ? _.GetOperandTypeId(interp_inst, 2) + : _.GetOperandTypeId(inst, 4); + uint32_t interpolant_storage_class = 0; uint32_t interpolant_data_type = 0; if (!_.GetPointerTypeInfo(interpolant_type, &interpolant_data_type,