SPIR-V: Batch predicated instructions together into a single block.

Add Post-Translation validation.
Fix a couple of type-related typos.
This commit is contained in:
Dr. Chat 2016-04-09 21:03:44 -05:00
parent a1c9540063
commit b7f2c93d73
4 changed files with 210 additions and 112 deletions

View File

@ -986,16 +986,19 @@ void ShaderTranslator::TranslateAluInstruction(const AluInstruction& op) {
return; return;
} }
ParsedAluInstruction instr;
if (op.has_vector_op()) { if (op.has_vector_op()) {
const auto& opcode_info = const auto& opcode_info =
alu_vector_opcode_infos_[static_cast<int>(op.vector_opcode())]; alu_vector_opcode_infos_[static_cast<int>(op.vector_opcode())];
ParseAluVectorInstruction(op, opcode_info); ParseAluVectorInstruction(op, opcode_info, instr);
ProcessAluInstruction(instr);
} }
if (op.has_scalar_op()) { if (op.has_scalar_op()) {
const auto& opcode_info = const auto& opcode_info =
alu_scalar_opcode_infos_[static_cast<int>(op.scalar_opcode())]; alu_scalar_opcode_infos_[static_cast<int>(op.scalar_opcode())];
ParseAluScalarInstruction(op, opcode_info); ParseAluScalarInstruction(op, opcode_info, instr);
ProcessAluInstruction(instr);
} }
} }
@ -1088,8 +1091,8 @@ void ParseAluInstructionOperandSpecial(const AluInstruction& op,
} }
void ShaderTranslator::ParseAluVectorInstruction( void ShaderTranslator::ParseAluVectorInstruction(
const AluInstruction& op, const AluOpcodeInfo& opcode_info) { const AluInstruction& op, const AluOpcodeInfo& opcode_info,
ParsedAluInstruction i; ParsedAluInstruction& i) {
i.dword_index = 0; i.dword_index = 0;
i.type = ParsedAluInstruction::Type::kVector; i.type = ParsedAluInstruction::Type::kVector;
i.vector_opcode = op.vector_opcode(); i.vector_opcode = op.vector_opcode();
@ -1203,13 +1206,11 @@ void ShaderTranslator::ParseAluVectorInstruction(
} }
i.Disassemble(&ucode_disasm_buffer_); i.Disassemble(&ucode_disasm_buffer_);
ProcessAluInstruction(i);
} }
void ShaderTranslator::ParseAluScalarInstruction( void ShaderTranslator::ParseAluScalarInstruction(
const AluInstruction& op, const AluOpcodeInfo& opcode_info) { const AluInstruction& op, const AluOpcodeInfo& opcode_info,
ParsedAluInstruction i; ParsedAluInstruction& i) {
i.dword_index = 0; i.dword_index = 0;
i.type = ParsedAluInstruction::Type::kScalar; i.type = ParsedAluInstruction::Type::kScalar;
i.scalar_opcode = op.scalar_opcode(); i.scalar_opcode = op.scalar_opcode();
@ -1319,8 +1320,6 @@ void ShaderTranslator::ParseAluScalarInstruction(
} }
i.Disassemble(&ucode_disasm_buffer_); i.Disassemble(&ucode_disasm_buffer_);
ProcessAluInstruction(i);
} }
} // namespace gpu } // namespace gpu

View File

@ -173,9 +173,11 @@ class ShaderTranslator {
void TranslateAluInstruction(const ucode::AluInstruction& op); void TranslateAluInstruction(const ucode::AluInstruction& op);
void ParseAluVectorInstruction(const ucode::AluInstruction& op, void ParseAluVectorInstruction(const ucode::AluInstruction& op,
const AluOpcodeInfo& opcode_info); const AluOpcodeInfo& opcode_info,
ParsedAluInstruction& instr);
void ParseAluScalarInstruction(const ucode::AluInstruction& op, void ParseAluScalarInstruction(const ucode::AluInstruction& op,
const AluOpcodeInfo& opcode_info); const AluOpcodeInfo& opcode_info,
ParsedAluInstruction& instr);
// Input shader metadata and microcode. // Input shader metadata and microcode.
ShaderType shader_type_; ShaderType shader_type_;

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * Xenia : Xbox 360 Emulator Research Project *
****************************************************************************** ******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. * * Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. * * Released under the BSD license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */
@ -85,16 +85,14 @@ void SpirvShaderTranslator::StartTranslation() {
"ps"); "ps");
pv_ = b.createVariable(spv::StorageClass::StorageClassFunction, pv_ = b.createVariable(spv::StorageClass::StorageClassFunction,
vec4_float_type_, "pv"); vec4_float_type_, "pv");
a0_ = b.createVariable(spv::StorageClass::StorageClassFunction, a0_ = b.createVariable(spv::StorageClass::StorageClassFunction, int_type_,
b.makeUintType(32), "a0"); "a0");
// Uniform constants. // Uniform constants.
Id float_consts_type = Id float_consts_type =
b.makeArrayType(vec4_float_type_, b.makeUintConstant(512), 1); b.makeArrayType(vec4_float_type_, b.makeUintConstant(512), 1);
Id loop_consts_type = Id loop_consts_type = b.makeArrayType(uint_type_, b.makeUintConstant(32), 1);
b.makeArrayType(b.makeUintType(32), b.makeUintConstant(32), 1); Id bool_consts_type = b.makeArrayType(uint_type_, b.makeUintConstant(8), 1);
Id bool_consts_type =
b.makeArrayType(b.makeUintType(32), b.makeUintConstant(8), 1);
Id consts_struct_type = b.makeStructType( Id consts_struct_type = b.makeStructType(
{float_consts_type, loop_consts_type, bool_consts_type}, "consts_type"); {float_consts_type, loop_consts_type, bool_consts_type}, "consts_type");
@ -242,6 +240,13 @@ void SpirvShaderTranslator::StartTranslation() {
interpolators_ = b.createVariable(spv::StorageClass::StorageClassOutput, interpolators_ = b.createVariable(spv::StorageClass::StorageClassOutput,
interpolators_type, "interpolators"); interpolators_type, "interpolators");
b.addDecoration(interpolators_, spv::Decoration::DecorationLocation, 0); b.addDecoration(interpolators_, spv::Decoration::DecorationLocation, 0);
for (uint32_t i = 0; i < 16; i++) {
// Zero interpolators.
auto ptr = b.createAccessChain(spv::StorageClass::StorageClassOutput,
interpolators_,
std::vector<Id>({b.makeUintConstant(i)}));
b.createStore(vec4_float_zero_, ptr);
}
pos_ = b.createVariable(spv::StorageClass::StorageClassOutput, pos_ = b.createVariable(spv::StorageClass::StorageClassOutput,
vec4_float_type_, "gl_Position"); vec4_float_type_, "gl_Position");
@ -338,6 +343,9 @@ void SpirvShaderTranslator::StartTranslation() {
std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() { std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
auto& b = *builder_; auto& b = *builder_;
assert_false(open_predicated_block_);
auto block = &b.makeNewBlock();
b.createBranch(block);
b.makeReturn(false); b.makeReturn(false);
// main() entry point. // main() entry point.
@ -397,9 +405,10 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
b.createStore(p, pos_); b.createStore(p, pos_);
} else { } else {
// Alpha test // Alpha test
auto alpha_test_x = b.createCompositeExtract( auto alpha_test_x = b.createCompositeExtract(push_consts_, float_type_,
push_consts_, float_type_, std::vector<uint32_t>{2, 0}); std::vector<uint32_t>{2, 0});
auto cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, alpha_test_x, b.makeFloatConstant(1.f)); auto cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, alpha_test_x,
b.makeFloatConstant(1.f));
spv::Builder::If alpha_if(cond, b); spv::Builder::If alpha_if(cond, b);
@ -433,15 +442,25 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
} }
void SpirvShaderTranslator::PostTranslation(Shader* shader) { void SpirvShaderTranslator::PostTranslation(Shader* shader) {
// Validation.
// TODO(DrChat): Only do this if a flag is set (this is pretty slow).
auto validation = validator_.Validate(
reinterpret_cast<const uint32_t*>(shader->translated_binary().data()),
shader->translated_binary().size() / 4);
if (validation->has_error()) {
XELOGE("SPIR-V Shader Validation failed! Error: %s",
validation->error_string());
}
// TODO(benvanik): only if needed? could be slowish. // TODO(benvanik): only if needed? could be slowish.
auto disasm = disassembler_.Disassemble( auto disasm = disassembler_.Disassemble(
reinterpret_cast<const uint32_t*>(shader->translated_binary().data()), reinterpret_cast<const uint32_t*>(shader->translated_binary().data()),
shader->translated_binary().size() / 4); shader->translated_binary().size() / 4);
if (disasm->has_error()) { if (disasm->has_error()) {
XELOGE("Failed to disassemble SPIRV - invalid?"); XELOGE("Failed to disassemble SPIRV - invalid?");
return; } else {
}
set_host_disassembly(shader, disasm->to_string()); set_host_disassembly(shader, disasm->to_string());
}
} }
void SpirvShaderTranslator::PreProcessControlFlowInstruction( void SpirvShaderTranslator::PreProcessControlFlowInstruction(
@ -475,13 +494,18 @@ void SpirvShaderTranslator::ProcessControlFlowInstructionEnd(
void SpirvShaderTranslator::ProcessControlFlowNopInstruction() { void SpirvShaderTranslator::ProcessControlFlowNopInstruction() {
auto& b = *builder_; auto& b = *builder_;
b.createNoResultOp(spv::Op::OpNop); // b.createNoResultOp(spv::Op::OpNop);
} }
void SpirvShaderTranslator::ProcessExecInstructionBegin( void SpirvShaderTranslator::ProcessExecInstructionBegin(
const ParsedExecInstruction& instr) { const ParsedExecInstruction& instr) {
auto& b = *builder_; auto& b = *builder_;
assert_false(open_predicated_block_);
open_predicated_block_ = false;
predicated_block_cond_ = false;
predicated_block_end_ = nullptr;
// Head has the logic to check if the body should execute. // Head has the logic to check if the body should execute.
auto head = cf_blocks_[instr.dword_index]; auto head = cf_blocks_[instr.dword_index];
b.setBuildPoint(head); b.setBuildPoint(head);
@ -500,7 +524,7 @@ void SpirvShaderTranslator::ProcessExecInstructionBegin(
v = b.createLoad(v); v = b.createLoad(v);
// Bitfield extract the bool constant. // Bitfield extract the bool constant.
v = b.createTriOp(spv::Op::OpBitFieldUExtract, b.makeUintType(32), v, v = b.createTriOp(spv::Op::OpBitFieldUExtract, uint_type_, v,
b.makeUintConstant(instr.bool_constant_index % 32), b.makeUintConstant(instr.bool_constant_index % 32),
b.makeUintConstant(1)); b.makeUintConstant(1));
@ -519,6 +543,7 @@ void SpirvShaderTranslator::ProcessExecInstructionBegin(
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_), b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_),
b.makeBoolConstant(instr.condition)); b.makeBoolConstant(instr.condition));
b.createConditionalBranch(cond, body, cf_blocks_[instr.dword_index + 1]); b.createConditionalBranch(cond, body, cf_blocks_[instr.dword_index + 1]);
} break; } break;
} }
b.setBuildPoint(body); b.setBuildPoint(body);
@ -528,6 +553,14 @@ void SpirvShaderTranslator::ProcessExecInstructionEnd(
const ParsedExecInstruction& instr) { const ParsedExecInstruction& instr) {
auto& b = *builder_; auto& b = *builder_;
if (open_predicated_block_) {
b.createBranch(predicated_block_end_);
b.setBuildPoint(predicated_block_end_);
open_predicated_block_ = false;
predicated_block_cond_ = false;
predicated_block_end_ = nullptr;
}
if (instr.is_end) { if (instr.is_end) {
b.makeReturn(false); b.makeReturn(false);
} else { } else {
@ -671,7 +704,30 @@ void SpirvShaderTranslator::ProcessVertexFetchInstruction(
assert_true(is_vertex_shader()); assert_true(is_vertex_shader());
assert_not_zero(vertex_id_); assert_not_zero(vertex_id_);
// TODO: instr.is_predicated // Close the open predicated block if this instr isn't predicated or the
// conditions do not match.
if (open_predicated_block_ &&
(!instr.is_predicated ||
instr.predicate_condition != predicated_block_cond_)) {
b.createBranch(predicated_block_end_);
b.setBuildPoint(predicated_block_end_);
open_predicated_block_ = false;
predicated_block_cond_ = false;
predicated_block_end_ = nullptr;
}
if (!open_predicated_block_ && instr.is_predicated) {
Id pred_cond =
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_),
b.makeBoolConstant(instr.predicate_condition));
auto block = &b.makeNewBlock();
open_predicated_block_ = true;
predicated_block_cond_ = instr.predicate_condition;
predicated_block_end_ = &b.makeNewBlock();
b.createConditionalBranch(pred_cond, block, predicated_block_end_);
b.setBuildPoint(block);
}
// Operand 0 is the index // Operand 0 is the index
// Operand 1 is the binding // Operand 1 is the binding
@ -726,7 +782,31 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
const ParsedTextureFetchInstruction& instr) { const ParsedTextureFetchInstruction& instr) {
auto& b = *builder_; auto& b = *builder_;
// TODO: instr.is_predicated // Close the open predicated block if this instr isn't predicated or the
// conditions do not match.
if (open_predicated_block_ &&
(!instr.is_predicated ||
instr.predicate_condition != predicated_block_cond_)) {
b.createBranch(predicated_block_end_);
b.setBuildPoint(predicated_block_end_);
open_predicated_block_ = false;
predicated_block_cond_ = false;
predicated_block_end_ = nullptr;
}
if (!open_predicated_block_ && instr.is_predicated) {
Id pred_cond =
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_),
b.makeBoolConstant(instr.predicate_condition));
auto block = &b.makeNewBlock();
open_predicated_block_ = true;
predicated_block_cond_ = instr.predicate_condition;
predicated_block_end_ = &b.makeNewBlock();
b.createConditionalBranch(pred_cond, block, predicated_block_end_);
b.setBuildPoint(block);
}
// Operand 0 is the offset // Operand 0 is the offset
// Operand 1 is the sampler index // Operand 1 is the sampler index
Id dest = 0; Id dest = 0;
@ -804,13 +884,32 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
sources[i] = LoadFromOperand(instr.operands[i]); sources[i] = LoadFromOperand(instr.operands[i]);
} }
Id pred_cond = 0; // Close the open predicated block if this instr isn't predicated or the
if (instr.is_predicated) { // conditions do not match.
pred_cond = if (open_predicated_block_ &&
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_), (!instr.is_predicated ||
b.makeBoolConstant(instr.predicate_condition)); instr.predicate_condition != predicated_block_cond_)) {
b.createBranch(predicated_block_end_);
b.setBuildPoint(predicated_block_end_);
open_predicated_block_ = false;
predicated_block_cond_ = false;
predicated_block_end_ = nullptr;
} }
if (!open_predicated_block_ && instr.is_predicated) {
Id pred_cond =
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_),
b.makeBoolConstant(instr.predicate_condition));
auto block = &b.makeNewBlock();
open_predicated_block_ = true;
predicated_block_cond_ = instr.predicate_condition;
predicated_block_end_ = &b.makeNewBlock();
b.createConditionalBranch(pred_cond, block, predicated_block_end_);
b.setBuildPoint(block);
}
bool close_predicated_block = false;
switch (instr.vector_opcode) { switch (instr.vector_opcode) {
case AluVectorOpcode::kAdd: { case AluVectorOpcode::kAdd: {
dest = b.createBinOp(spv::Op::OpFAdd, vec4_float_type_, sources[0], dest = b.createBinOp(spv::Op::OpFAdd, vec4_float_type_, sources[0],
@ -863,8 +962,8 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
auto src1_xy = b.createOp(spv::Op::OpVectorShuffle, vec2_float_type_, auto src1_xy = b.createOp(spv::Op::OpVectorShuffle, vec2_float_type_,
{sources[1], sources[1], 0, 1}); {sources[1], sources[1], 0, 1});
auto src2_x = b.createCompositeExtract(sources[2], float_type_, 0); auto src2_x = b.createCompositeExtract(sources[2], float_type_, 0);
auto dot = b.createBinOp(spv::Op::OpDot, float_type_, src0_xy, src1_xy); dest = b.createBinOp(spv::Op::OpDot, float_type_, src0_xy, src1_xy);
dest = b.createBinOp(spv::Op::OpFAdd, float_type_, dot, src2_x); dest = b.createBinOp(spv::Op::OpFAdd, float_type_, dest, src2_x);
dest = b.smearScalar(spv::NoPrecision, dest, vec4_float_type_); dest = b.smearScalar(spv::NoPrecision, dest, vec4_float_type_);
} break; } break;
@ -873,12 +972,13 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
{sources[0], sources[0], 0, 1, 2}); {sources[0], sources[0], 0, 1, 2});
auto src1_xyz = b.createOp(spv::Op::OpVectorShuffle, vec3_float_type_, auto src1_xyz = b.createOp(spv::Op::OpVectorShuffle, vec3_float_type_,
{sources[1], sources[1], 0, 1, 2}); {sources[1], sources[1], 0, 1, 2});
auto dot = b.createBinOp(spv::Op::OpDot, float_type_, src0_xyz, src1_xyz); dest = b.createBinOp(spv::Op::OpDot, float_type_, src0_xyz, src1_xyz);
dest = b.smearScalar(spv::NoPrecision, dot, vec4_float_type_); dest = b.smearScalar(spv::NoPrecision, dest, vec4_float_type_);
} break; } break;
case AluVectorOpcode::kDp4: { case AluVectorOpcode::kDp4: {
dest = b.createBinOp(spv::Op::OpDot, float_type_, sources[0], sources[1]); dest = b.createBinOp(spv::Op::OpDot, float_type_, sources[0], sources[1]);
dest = b.smearScalar(spv::NoPrecision, dest, vec4_float_type_);
} break; } break;
case AluVectorOpcode::kFloor: { case AluVectorOpcode::kFloor: {
@ -899,10 +999,6 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
auto cond = b.createBinOp(spv::Op::OpFOrdEqual, vec4_bool_type_, auto cond = b.createBinOp(spv::Op::OpFOrdEqual, vec4_bool_type_,
sources[0], sources[1]); sources[0], sources[1]);
cond = b.createUnaryOp(spv::Op::OpAny, bool_type_, cond); cond = b.createUnaryOp(spv::Op::OpAny, bool_type_, cond);
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -918,10 +1014,6 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
auto cond = b.createBinOp(spv::Op::OpFOrdGreaterThanEqual, auto cond = b.createBinOp(spv::Op::OpFOrdGreaterThanEqual,
vec4_bool_type_, sources[0], sources[1]); vec4_bool_type_, sources[0], sources[1]);
cond = b.createUnaryOp(spv::Op::OpAny, bool_type_, cond); cond = b.createUnaryOp(spv::Op::OpAny, bool_type_, cond);
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -937,10 +1029,6 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
auto cond = b.createBinOp(spv::Op::OpFOrdGreaterThan, vec4_bool_type_, auto cond = b.createBinOp(spv::Op::OpFOrdGreaterThan, vec4_bool_type_,
sources[0], sources[1]); sources[0], sources[1]);
cond = b.createUnaryOp(spv::Op::OpAny, bool_type_, cond); cond = b.createUnaryOp(spv::Op::OpAny, bool_type_, cond);
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -956,10 +1044,6 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
auto cond = b.createBinOp(spv::Op::OpFOrdNotEqual, vec4_bool_type_, auto cond = b.createBinOp(spv::Op::OpFOrdNotEqual, vec4_bool_type_,
sources[0], sources[1]); sources[0], sources[1]);
cond = b.createUnaryOp(spv::Op::OpAny, bool_type_, cond); cond = b.createUnaryOp(spv::Op::OpAny, bool_type_, cond);
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -1053,6 +1137,7 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
// p0 // p0
b.createStore(c_and_w, p0_); b.createStore(c_and_w, p0_);
close_predicated_block = true;
// dest // dest
auto s0_x = b.createCompositeExtract(sources[0], float_type_, 0); auto s0_x = b.createCompositeExtract(sources[0], float_type_, 0);
@ -1076,6 +1161,7 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
// p0 // p0
b.createStore(c_and_w, p0_); b.createStore(c_and_w, p0_);
close_predicated_block = true;
// dest // dest
auto s0_x = b.createCompositeExtract(sources[0], float_type_, 0); auto s0_x = b.createCompositeExtract(sources[0], float_type_, 0);
@ -1099,6 +1185,7 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
// p0 // p0
b.createStore(c_and_w, p0_); b.createStore(c_and_w, p0_);
close_predicated_block = true;
// dest // dest
auto s0_x = b.createCompositeExtract(sources[0], float_type_, 0); auto s0_x = b.createCompositeExtract(sources[0], float_type_, 0);
@ -1122,6 +1209,7 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
// p0 // p0
b.createStore(c_and_w, p0_); b.createStore(c_and_w, p0_);
close_predicated_block = true;
// dest // dest
auto s0_x = b.createCompositeExtract(sources[0], float_type_, 0); auto s0_x = b.createCompositeExtract(sources[0], float_type_, 0);
@ -1177,15 +1265,16 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction(
assert_not_zero(dest); assert_not_zero(dest);
if (dest) { if (dest) {
// If predicated, discard the result from the instruction. b.createStore(dest, pv_);
Id pv_dest = dest; StoreToResult(dest, instr.result);
if (instr.is_predicated) {
pv_dest = b.createTriOp(spv::Op::OpSelect, vec4_float_type_, pred_cond,
dest, b.createLoad(pv_));
} }
b.createStore(pv_dest, pv_); if (close_predicated_block && open_predicated_block_) {
StoreToResult(dest, instr.result, pred_cond); b.createBranch(predicated_block_end_);
b.setBuildPoint(predicated_block_end_);
open_predicated_block_ = false;
predicated_block_cond_ = false;
predicated_block_end_ = nullptr;
} }
} }
@ -1229,13 +1318,32 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
} }
} }
Id pred_cond = 0; // Close the open predicated block if this instr isn't predicated or the
if (instr.is_predicated) { // conditions do not match.
pred_cond = if (open_predicated_block_ &&
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_), (!instr.is_predicated ||
b.makeBoolConstant(instr.predicate_condition)); instr.predicate_condition != predicated_block_cond_)) {
b.createBranch(predicated_block_end_);
b.setBuildPoint(predicated_block_end_);
open_predicated_block_ = false;
predicated_block_cond_ = false;
predicated_block_end_ = nullptr;
} }
if (!open_predicated_block_ && instr.is_predicated) {
Id pred_cond =
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_),
b.makeBoolConstant(instr.predicate_condition));
auto block = &b.makeNewBlock();
open_predicated_block_ = true;
predicated_block_cond_ = instr.predicate_condition;
predicated_block_end_ = &b.makeNewBlock();
b.createConditionalBranch(pred_cond, block, predicated_block_end_);
b.setBuildPoint(block);
}
bool close_predicated_block = false;
switch (instr.scalar_opcode) { switch (instr.scalar_opcode) {
case AluScalarOpcode::kAdds: case AluScalarOpcode::kAdds:
case AluScalarOpcode::kAddsc0: case AluScalarOpcode::kAddsc0:
@ -1276,10 +1384,6 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
auto kill_block = &b.makeNewBlock(); auto kill_block = &b.makeNewBlock();
auto cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0], auto cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0],
b.makeFloatConstant(0.f)); b.makeFloatConstant(0.f));
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -1294,10 +1398,6 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
auto kill_block = &b.makeNewBlock(); auto kill_block = &b.makeNewBlock();
auto cond = b.createBinOp(spv::Op::OpFOrdGreaterThanEqual, bool_type_, auto cond = b.createBinOp(spv::Op::OpFOrdGreaterThanEqual, bool_type_,
sources[0], b.makeFloatConstant(0.f)); sources[0], b.makeFloatConstant(0.f));
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -1312,10 +1412,6 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
auto kill_block = &b.makeNewBlock(); auto kill_block = &b.makeNewBlock();
auto cond = b.createBinOp(spv::Op::OpFOrdGreaterThan, bool_type_, auto cond = b.createBinOp(spv::Op::OpFOrdGreaterThan, bool_type_,
sources[0], b.makeFloatConstant(0.f)); sources[0], b.makeFloatConstant(0.f));
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -1330,10 +1426,6 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
auto kill_block = &b.makeNewBlock(); auto kill_block = &b.makeNewBlock();
auto cond = b.createBinOp(spv::Op::OpFOrdNotEqual, bool_type_, sources[0], auto cond = b.createBinOp(spv::Op::OpFOrdNotEqual, bool_type_, sources[0],
b.makeFloatConstant(0.f)); b.makeFloatConstant(0.f));
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -1348,10 +1440,6 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
auto kill_block = &b.makeNewBlock(); auto kill_block = &b.makeNewBlock();
auto cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0], auto cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0],
b.makeFloatConstant(1.f)); b.makeFloatConstant(1.f));
if (pred_cond) {
cond =
b.createBinOp(spv::Op::OpLogicalAnd, bool_type_, cond, pred_cond);
}
b.createConditionalBranch(cond, kill_block, continue_block); b.createConditionalBranch(cond, kill_block, continue_block);
b.setBuildPoint(kill_block); b.setBuildPoint(kill_block);
@ -1448,7 +1536,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
b.makeFloatConstant(0.f)); b.makeFloatConstant(0.f));
auto d = b.createBinOp(spv::Op::OpFDiv, float_type_, auto d = b.createBinOp(spv::Op::OpFDiv, float_type_,
b.makeFloatConstant(1.f), sources[0]); b.makeFloatConstant(1.f), sources[0]);
dest = b.createTriOp(spv::Op::OpSelect, vec4_float_type_, c, dest = b.createTriOp(spv::Op::OpSelect, float_type_, c,
b.makeFloatConstant(0.f), d); b.makeFloatConstant(0.f), d);
} break; } break;
@ -1462,10 +1550,10 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
// dest = src0 != 0.0 ? inversesqrt(src0) : 0.0; // dest = src0 != 0.0 ? inversesqrt(src0) : 0.0;
auto c = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0], auto c = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0],
b.makeFloatConstant(0.f)); b.makeFloatConstant(0.f));
auto d = CreateGlslStd450InstructionCall( auto d = CreateGlslStd450InstructionCall(spv::NoPrecision, float_type_,
spv::NoPrecision, vec4_float_type_, spv::GLSLstd450::kInverseSqrt, spv::GLSLstd450::kInverseSqrt,
{sources[0]}); {sources[0]});
dest = b.createTriOp(spv::Op::OpSelect, vec4_float_type_, c, dest = b.createTriOp(spv::Op::OpSelect, float_type_, c,
b.makeFloatConstant(0.f), d); b.makeFloatConstant(0.f), d);
} break; } break;
@ -1503,6 +1591,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
case AluScalarOpcode::kSetpClr: { case AluScalarOpcode::kSetpClr: {
b.createStore(b.makeBoolConstant(false), p0_); b.createStore(b.makeBoolConstant(false), p0_);
close_predicated_block = true;
dest = b.makeFloatConstant(FLT_MAX); dest = b.makeFloatConstant(FLT_MAX);
} break; } break;
@ -1511,6 +1600,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
b.makeFloatConstant(0.f)); b.makeFloatConstant(0.f));
// p0 = cond // p0 = cond
b.createStore(cond, p0_); b.createStore(cond, p0_);
close_predicated_block = true;
// dest = cond ? 0.f : 1.f; // dest = cond ? 0.f : 1.f;
dest = b.createTriOp(spv::Op::OpSelect, float_type_, cond, dest = b.createTriOp(spv::Op::OpSelect, float_type_, cond,
@ -1522,6 +1612,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
sources[0], b.makeFloatConstant(0.f)); sources[0], b.makeFloatConstant(0.f));
// p0 = cond // p0 = cond
b.createStore(cond, p0_); b.createStore(cond, p0_);
close_predicated_block = true;
// dest = cond ? 0.f : 1.f; // dest = cond ? 0.f : 1.f;
dest = b.createTriOp(spv::Op::OpSelect, float_type_, cond, dest = b.createTriOp(spv::Op::OpSelect, float_type_, cond,
@ -1533,6 +1624,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
sources[0], b.makeFloatConstant(0.f)); sources[0], b.makeFloatConstant(0.f));
// p0 = cond // p0 = cond
b.createStore(cond, p0_); b.createStore(cond, p0_);
close_predicated_block = true;
// dest = cond ? 0.f : 1.f; // dest = cond ? 0.f : 1.f;
dest = b.createTriOp(spv::Op::OpSelect, float_type_, cond, dest = b.createTriOp(spv::Op::OpSelect, float_type_, cond,
@ -1544,6 +1636,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
auto cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0], auto cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0],
b.makeFloatConstant(1.f)); b.makeFloatConstant(1.f));
b.createStore(cond, p0_); b.createStore(cond, p0_);
close_predicated_block = true;
// if (!cond) dest = src0 == 0.0 ? 1.0 : src0; // if (!cond) dest = src0 == 0.0 ? 1.0 : src0;
auto dst_cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, auto dst_cond = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_,
@ -1560,6 +1653,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
// p0 = cond // p0 = cond
b.createStore(cond, p0_); b.createStore(cond, p0_);
close_predicated_block = true;
// dest = cond ? 0.f : 1.f; // dest = cond ? 0.f : 1.f;
dest = b.createTriOp(spv::Op::OpSelect, float_type_, cond, dest = b.createTriOp(spv::Op::OpSelect, float_type_, cond,
@ -1572,6 +1666,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
auto c = b.createBinOp(spv::Op::OpFOrdLessThanEqual, bool_type_, src, auto c = b.createBinOp(spv::Op::OpFOrdLessThanEqual, bool_type_, src,
b.makeFloatConstant(0.f)); b.makeFloatConstant(0.f));
b.createStore(c, p0_); b.createStore(c, p0_);
close_predicated_block = true;
dest = CreateGlslStd450InstructionCall( dest = CreateGlslStd450InstructionCall(
spv::NoPrecision, float_type_, GLSLstd450::kFMax, spv::NoPrecision, float_type_, GLSLstd450::kFMax,
@ -1582,6 +1677,7 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
auto c = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0], auto c = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, sources[0],
b.makeFloatConstant(0.f)); b.makeFloatConstant(0.f));
b.createStore(c, p0_); b.createStore(c, p0_);
close_predicated_block = true;
dest = sources[0]; dest = sources[0];
} break; } break;
@ -1618,15 +1714,16 @@ void SpirvShaderTranslator::ProcessScalarAluInstruction(
assert_not_zero(dest); assert_not_zero(dest);
if (dest) { if (dest) {
// If predicated, discard the result from the instruction. b.createStore(dest, ps_);
Id ps_dest = dest; StoreToResult(dest, instr.result);
if (instr.is_predicated) {
ps_dest = b.createTriOp(spv::Op::OpSelect, float_type_, pred_cond, dest,
b.createLoad(ps_));
} }
b.createStore(ps_dest, ps_); if (close_predicated_block && open_predicated_block_) {
StoreToResult(dest, instr.result, pred_cond); b.createBranch(predicated_block_end_);
b.setBuildPoint(predicated_block_end_);
open_predicated_block_ = false;
predicated_block_cond_ = false;
predicated_block_end_ = nullptr;
} }
} }
@ -1763,8 +1860,7 @@ Id SpirvShaderTranslator::LoadFromOperand(const InstructionOperand& op) {
} }
void SpirvShaderTranslator::StoreToResult(Id source_value_id, void SpirvShaderTranslator::StoreToResult(Id source_value_id,
const InstructionResult& result, const InstructionResult& result) {
Id predicate_cond) {
auto& b = *builder_; auto& b = *builder_;
if (result.storage_target == InstructionStorageTarget::kNone) { if (result.storage_target == InstructionStorageTarget::kNone) {
@ -1865,7 +1961,7 @@ void SpirvShaderTranslator::StoreToResult(Id source_value_id,
// Only load from storage if we need it later. // Only load from storage if we need it later.
Id storage_value = 0; Id storage_value = 0;
if (!result.has_all_writes() || predicate_cond) { if (!result.has_all_writes()) {
storage_value = b.createLoad(storage_pointer); storage_value = b.createLoad(storage_pointer);
} }
@ -1965,13 +2061,8 @@ void SpirvShaderTranslator::StoreToResult(Id source_value_id,
assert_true(b.getNumComponents(source_value_id) == assert_true(b.getNumComponents(source_value_id) ==
b.getNumTypeComponents(storage_type)); b.getNumTypeComponents(storage_type));
// Discard if predicate condition is false. assert_true(b.getTypeId(source_value_id) ==
if (predicate_cond) { b.getDerefTypeId(storage_pointer));
source_value_id =
b.createTriOp(spv::Op::OpSelect, storage_type, predicate_cond,
source_value_id, storage_value);
}
b.createStore(source_value_id, storage_pointer); b.createStore(source_value_id, storage_pointer);
} }

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * Xenia : Xbox 360 Emulator Research Project *
****************************************************************************** ******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. * * Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. * * Released under the BSD license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */
@ -18,6 +18,7 @@
#include "third_party/spirv/GLSL.std.450.hpp11" #include "third_party/spirv/GLSL.std.450.hpp11"
#include "xenia/gpu/shader_translator.h" #include "xenia/gpu/shader_translator.h"
#include "xenia/ui/spirv/spirv_disassembler.h" #include "xenia/ui/spirv/spirv_disassembler.h"
#include "xenia/ui/spirv/spirv_validator.h"
namespace xe { namespace xe {
namespace gpu { namespace gpu {
@ -91,10 +92,15 @@ class SpirvShaderTranslator : public ShaderTranslator {
// Stores a value based on the specified result information. // Stores a value based on the specified result information.
// The value will be transformed into the appropriate form for the result and // The value will be transformed into the appropriate form for the result and
// the proper components will be selected. // the proper components will be selected.
void StoreToResult(spv::Id source_value_id, const InstructionResult& result, void StoreToResult(spv::Id source_value_id, const InstructionResult& result);
spv::Id predicate_cond = 0);
xe::ui::spirv::SpirvDisassembler disassembler_; xe::ui::spirv::SpirvDisassembler disassembler_;
xe::ui::spirv::SpirvValidator validator_;
// True if there's an open predicated block
bool open_predicated_block_ = false;
bool predicated_block_cond_ = false;
spv::Block* predicated_block_end_ = nullptr;
// TODO(benvanik): replace with something better, make reusable, etc. // TODO(benvanik): replace with something better, make reusable, etc.
std::unique_ptr<spv::Builder> builder_; std::unique_ptr<spv::Builder> builder_;