[SPIR-V] Instruction predication

This commit is contained in:
Triang3l 2020-10-26 22:12:01 +03:00
parent 556c8de2ab
commit 1c83c8dcfa
3 changed files with 78 additions and 0 deletions

View File

@ -827,6 +827,51 @@ void SpirvShaderTranslator::UpdateExecConditionals(
builder_->setBuildPoint(&inner_block);
}
void SpirvShaderTranslator::UpdateInstructionPredication(bool predicated,
bool condition) {
if (!predicated) {
CloseInstructionPredication();
return;
}
if (cf_instruction_predicate_merge_) {
if (cf_instruction_predicate_condition_ == condition) {
// Already in the needed instruction-level conditional.
return;
}
CloseInstructionPredication();
}
// If the instruction predicate condition is the same as the exec predicate
// condition, no need to open a check. However, if there was a `setp` prior
// to this instruction, the predicate value now may be different than it was
// in the beginning of the exec.
if (!cf_exec_predicate_written_ && cf_exec_conditional_merge_ &&
cf_exec_bool_constant_or_predicate_ == kCfExecBoolConstantPredicate &&
cf_exec_condition_ == condition) {
return;
}
cf_instruction_predicate_condition_ = condition;
EnsureBuildPointAvailable();
spv::Id predicate_id =
builder_->createLoad(var_main_predicate_, spv::NoPrecision);
spv::Block& predicated_block = builder_->makeNewBlock();
cf_instruction_predicate_merge_ = &builder_->makeNewBlock();
{
std::unique_ptr<spv::Instruction> selection_merge_op =
std::make_unique<spv::Instruction>(spv::OpSelectionMerge);
selection_merge_op->addIdOperand(cf_instruction_predicate_merge_->getId());
selection_merge_op->addImmediateOperand(spv::SelectionControlMaskNone);
builder_->getBuildPoint()->addInstruction(std::move(selection_merge_op));
}
builder_->createConditionalBranch(
predicate_id,
condition ? &predicated_block : cf_instruction_predicate_merge_,
condition ? cf_instruction_predicate_merge_ : &predicated_block);
builder_->setBuildPoint(&predicated_block);
}
void SpirvShaderTranslator::CloseInstructionPredication() {
if (!cf_instruction_predicate_merge_) {
return;

View File

@ -66,6 +66,8 @@ class SpirvShaderTranslator : public ShaderTranslator {
const ParsedLoopEndInstruction& instr) override;
void ProcessJumpInstruction(const ParsedJumpInstruction& instr) override;
void ProcessAluInstruction(const ParsedAluInstruction& instr) override;
private:
// TODO(Triang3l): Depth-only pixel shader.
bool IsSpirvVertexOrTessEvalShader() const { return is_vertex_shader(); }
@ -96,6 +98,9 @@ class SpirvShaderTranslator : public ShaderTranslator {
// needed (for example, in jumps).
void UpdateExecConditionals(ParsedExecInstruction::Type type,
uint32_t bool_constant_index, bool condition);
// Opens or reopens the predicate check conditional for the instruction.
// Should be called before processing a non-control-flow instruction.
void UpdateInstructionPredication(bool predicated, bool condition);
// Closes the instruction-level predicate conditional if it's open, useful if
// a control flow instruction needs to do some code which needs to respect the
// current exec conditional, but can't itself be predicated.

View File

@ -0,0 +1,28 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/spirv_shader_translator.h"
namespace xe {
namespace gpu {
void SpirvShaderTranslator::ProcessAluInstruction(
const ParsedAluInstruction& instr) {
if (instr.IsNop()) {
// Don't even disassemble or update predication.
return;
}
UpdateInstructionPredication(instr.is_predicated, instr.predicate_condition);
// TODO(Triang3l): Translate the ALU instruction.
}
} // namespace gpu
} // namespace xe