SPIR-V: Rewrite basic control-flow to use a while loop paired with a switch statement
This commit is contained in:
parent
52c75c8dbc
commit
300d1c57ba
|
@ -396,7 +396,7 @@ void GlslShaderTranslator::ProcessLabel(uint32_t cf_index) {
|
|||
}
|
||||
}
|
||||
|
||||
void GlslShaderTranslator::ProcessControlFlowNopInstruction() {
|
||||
void GlslShaderTranslator::ProcessControlFlowNopInstruction(uint32_t cf_index) {
|
||||
EmitSource("// cnop\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ class GlslShaderTranslator : public ShaderTranslator {
|
|||
public:
|
||||
enum class Dialect {
|
||||
kGL45,
|
||||
kVulkan,
|
||||
};
|
||||
|
||||
GlslShaderTranslator(Dialect dialect);
|
||||
|
@ -39,7 +40,7 @@ class GlslShaderTranslator : public ShaderTranslator {
|
|||
std::vector<uint8_t> CompleteTranslation() override;
|
||||
|
||||
void ProcessLabel(uint32_t cf_index) override;
|
||||
void ProcessControlFlowNopInstruction() override;
|
||||
void ProcessControlFlowNopInstruction(uint32_t cf_index) override;
|
||||
void ProcessControlFlowInstructionBegin(uint32_t cf_index) override;
|
||||
void ProcessControlFlowInstructionEnd(uint32_t cf_index) override;
|
||||
void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) override;
|
||||
|
|
|
@ -368,7 +368,8 @@ bool ShaderTranslator::TranslateBlocks() {
|
|||
// This is what freedreno does.
|
||||
uint32_t max_cf_dword_index = static_cast<uint32_t>(ucode_dword_count_);
|
||||
std::set<uint32_t> label_addresses;
|
||||
for (uint32_t i = 0, cf_index = 0; i < max_cf_dword_index; i += 3) {
|
||||
std::vector<ControlFlowInstruction> cf_instructions;
|
||||
for (uint32_t i = 0; i < max_cf_dword_index; i += 3) {
|
||||
ControlFlowInstruction cf_a;
|
||||
ControlFlowInstruction cf_b;
|
||||
UnpackControlFlowInstructions(ucode_dwords_ + i, &cf_a, &cf_b);
|
||||
|
@ -383,12 +384,12 @@ bool ShaderTranslator::TranslateBlocks() {
|
|||
AddControlFlowTargetLabel(cf_a, &label_addresses);
|
||||
AddControlFlowTargetLabel(cf_b, &label_addresses);
|
||||
|
||||
PreProcessControlFlowInstruction(cf_index, cf_a);
|
||||
++cf_index;
|
||||
PreProcessControlFlowInstruction(cf_index, cf_b);
|
||||
++cf_index;
|
||||
cf_instructions.push_back(cf_a);
|
||||
cf_instructions.push_back(cf_b);
|
||||
}
|
||||
|
||||
PreProcessControlFlowInstructions(cf_instructions);
|
||||
|
||||
// Translate all instructions.
|
||||
for (uint32_t i = 0, cf_index = 0; i < max_cf_dword_index; i += 3) {
|
||||
ControlFlowInstruction cf_a;
|
||||
|
@ -491,7 +492,7 @@ void ShaderTranslator::TranslateControlFlowNop(
|
|||
const ControlFlowInstruction& cf) {
|
||||
ucode_disasm_buffer_.Append(" cnop\n");
|
||||
|
||||
ProcessControlFlowNopInstruction();
|
||||
ProcessControlFlowNopInstruction(cf_index_);
|
||||
}
|
||||
|
||||
void ShaderTranslator::TranslateControlFlowExec(
|
||||
|
@ -1065,7 +1066,9 @@ void ParseAluInstructionOperand(const AluInstruction& op, int i,
|
|||
uint32_t b = ((swizzle >> 0) + 0) & 0x3;
|
||||
out_op->components[0] = GetSwizzleFromComponentIndex(a);
|
||||
out_op->components[1] = GetSwizzleFromComponentIndex(b);
|
||||
} else {
|
||||
} else if (swizzle_component_count == 3) {
|
||||
assert_always();
|
||||
} else if (swizzle_component_count == 4) {
|
||||
for (int j = 0; j < swizzle_component_count; ++j, swizzle >>= 2) {
|
||||
out_op->components[j] = GetSwizzleFromComponentIndex((swizzle + j) & 0x3);
|
||||
}
|
||||
|
@ -1316,8 +1319,8 @@ void ShaderTranslator::ParseAluScalarInstruction(
|
|||
&i.operands[0]);
|
||||
} else {
|
||||
uint32_t src3_swizzle = op.src_swizzle(3);
|
||||
uint32_t swiz_a = ((src3_swizzle >> 6) - 1) & 0x3;
|
||||
uint32_t swiz_b = (src3_swizzle & 0x3);
|
||||
uint32_t swiz_a = ((src3_swizzle >> 6) + 3) & 0x3;
|
||||
uint32_t swiz_b = ((src3_swizzle >> 0) + 0) & 0x3;
|
||||
uint32_t reg2 = (static_cast<int>(op.scalar_opcode()) & 1) |
|
||||
(src3_swizzle & 0x3C) | (op.src_is_temp(3) << 1);
|
||||
int const_slot = (op.src_is_temp(1) || op.src_is_temp(2)) ? 1 : 0;
|
||||
|
|
|
@ -82,8 +82,8 @@ class ShaderTranslator {
|
|||
}
|
||||
|
||||
// Pre-process a control-flow instruction before anything else.
|
||||
virtual void PreProcessControlFlowInstruction(
|
||||
uint32_t cf_index, const ucode::ControlFlowInstruction& instr) {}
|
||||
virtual void PreProcessControlFlowInstructions(
|
||||
std::vector<ucode::ControlFlowInstruction> instrs) {}
|
||||
|
||||
// Handles translation for control flow label addresses.
|
||||
// This is triggered once for each label required (due to control flow
|
||||
|
@ -91,7 +91,7 @@ class ShaderTranslator {
|
|||
virtual void ProcessLabel(uint32_t cf_index) {}
|
||||
|
||||
// Handles translation for control flow nop instructions.
|
||||
virtual void ProcessControlFlowNopInstruction() {}
|
||||
virtual void ProcessControlFlowNopInstruction(uint32_t cf_index) {}
|
||||
// Handles the start of a control flow instruction at the given address.
|
||||
virtual void ProcessControlFlowInstructionBegin(uint32_t cf_index) {}
|
||||
// Handles the end of a control flow instruction that began at the given
|
||||
|
|
|
@ -103,6 +103,8 @@ void SpirvShaderTranslator::StartTranslation() {
|
|||
"ps");
|
||||
pv_ = b.createVariable(spv::StorageClass::StorageClassFunction,
|
||||
vec4_float_type_, "pv");
|
||||
pc_ = b.createVariable(spv::StorageClass::StorageClassFunction, int_type_,
|
||||
"pc");
|
||||
a0_ = b.createVariable(spv::StorageClass::StorageClassFunction, int_type_,
|
||||
"a0");
|
||||
|
||||
|
@ -219,6 +221,7 @@ void SpirvShaderTranslator::StartTranslation() {
|
|||
for (const auto& binding : vertex_bindings()) {
|
||||
for (const auto& attrib : binding.attributes) {
|
||||
Id attrib_type = 0;
|
||||
bool is_signed = attrib.fetch_instr.attributes.is_signed;
|
||||
switch (attrib.fetch_instr.attributes.data_format) {
|
||||
case VertexFormat::k_32:
|
||||
case VertexFormat::k_32_FLOAT:
|
||||
|
@ -230,8 +233,6 @@ void SpirvShaderTranslator::StartTranslation() {
|
|||
case VertexFormat::k_32_32_FLOAT:
|
||||
attrib_type = vec2_float_type_;
|
||||
break;
|
||||
case VertexFormat::k_10_11_11:
|
||||
case VertexFormat::k_11_11_10:
|
||||
case VertexFormat::k_32_32_32_FLOAT:
|
||||
attrib_type = vec3_float_type_;
|
||||
break;
|
||||
|
@ -243,6 +244,11 @@ void SpirvShaderTranslator::StartTranslation() {
|
|||
case VertexFormat::k_32_32_32_32_FLOAT:
|
||||
attrib_type = vec4_float_type_;
|
||||
break;
|
||||
case VertexFormat::k_10_11_11:
|
||||
case VertexFormat::k_11_11_10:
|
||||
// Manually converted.
|
||||
attrib_type = is_signed ? int_type_ : uint_type_;
|
||||
break;
|
||||
default:
|
||||
assert_always();
|
||||
}
|
||||
|
@ -387,15 +393,44 @@ void SpirvShaderTranslator::StartTranslation() {
|
|||
|
||||
ifb.makeEndIf();
|
||||
}
|
||||
|
||||
b.createStore(b.makeIntConstant(0x0), pc_);
|
||||
|
||||
loop_head_block_ = &b.makeNewBlock();
|
||||
auto block = &b.makeNewBlock();
|
||||
loop_body_block_ = &b.makeNewBlock();
|
||||
loop_cont_block_ = &b.makeNewBlock();
|
||||
loop_exit_block_ = &b.makeNewBlock();
|
||||
b.createBranch(loop_head_block_);
|
||||
|
||||
// Setup continue block
|
||||
b.setBuildPoint(loop_cont_block_);
|
||||
b.createBranch(loop_head_block_);
|
||||
|
||||
// While loop header block
|
||||
b.setBuildPoint(loop_head_block_);
|
||||
b.createLoopMerge(loop_exit_block_, loop_cont_block_,
|
||||
spv::LoopControlMask::LoopControlDontUnrollMask);
|
||||
b.createBranch(block);
|
||||
|
||||
// Condition block
|
||||
b.setBuildPoint(block);
|
||||
|
||||
// while (pc != 0xFFFF)
|
||||
auto c = b.createBinOp(spv::Op::OpINotEqual, bool_type_, b.createLoad(pc_),
|
||||
b.makeIntConstant(0xFFFF));
|
||||
b.createConditionalBranch(c, loop_body_block_, loop_exit_block_);
|
||||
b.setBuildPoint(loop_body_block_);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
||||
auto& b = *builder_;
|
||||
|
||||
assert_false(open_predicated_block_);
|
||||
auto block = &b.makeNewBlock();
|
||||
b.createBranch(block);
|
||||
b.setBuildPoint(loop_exit_block_);
|
||||
b.makeReturn(false);
|
||||
exec_cond_ = false;
|
||||
exec_skip_block_ = nullptr;
|
||||
|
||||
// main() entry point.
|
||||
auto mainFn = b.makeMain();
|
||||
|
@ -411,6 +446,9 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
|||
mainFn, "main");
|
||||
b.addExecutionMode(mainFn, spv::ExecutionModeOriginUpperLeft);
|
||||
|
||||
// FIXME(DrChat): We need to declare the DepthReplacing execution mode if
|
||||
// we write depth, and we must unconditionally write depth if declared!
|
||||
|
||||
for (auto id : interface_ids_) {
|
||||
entry->addIdOperand(id);
|
||||
}
|
||||
|
@ -527,12 +565,17 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
|||
b.makeReturn(false);
|
||||
|
||||
// Compile the spv IR
|
||||
compiler_.Compile(b.getModule());
|
||||
// compiler_.Compile(b.getModule());
|
||||
|
||||
std::vector<uint32_t> spirv_words;
|
||||
b.dump(spirv_words);
|
||||
|
||||
// Cleanup builder.
|
||||
cf_blocks_.clear();
|
||||
loop_head_block_ = nullptr;
|
||||
loop_body_block_ = nullptr;
|
||||
loop_cont_block_ = nullptr;
|
||||
loop_exit_block_ = nullptr;
|
||||
builder_.reset();
|
||||
|
||||
interface_ids_.clear();
|
||||
|
@ -568,30 +611,68 @@ void SpirvShaderTranslator::PostTranslation(Shader* shader) {
|
|||
}
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::PreProcessControlFlowInstruction(
|
||||
uint32_t cf_index, const ControlFlowInstruction& instr) {
|
||||
void SpirvShaderTranslator::PreProcessControlFlowInstructions(
|
||||
std::vector<ucode::ControlFlowInstruction> instrs) {
|
||||
auto& b = *builder_;
|
||||
|
||||
if (cf_blocks_.find(cf_index) == cf_blocks_.end()) {
|
||||
CFBlock block;
|
||||
block.block = &b.makeNewBlock();
|
||||
cf_blocks_[cf_index] = block;
|
||||
} else {
|
||||
cf_blocks_[cf_index].block = &b.makeNewBlock();
|
||||
auto default_block = &b.makeNewBlock();
|
||||
switch_break_block_ = &b.makeNewBlock();
|
||||
|
||||
b.setBuildPoint(default_block);
|
||||
b.createStore(b.makeIntConstant(0xFFFF), pc_);
|
||||
b.createBranch(switch_break_block_);
|
||||
|
||||
b.setBuildPoint(switch_break_block_);
|
||||
b.createBranch(loop_cont_block_);
|
||||
|
||||
// Now setup the switch.
|
||||
default_block->addPredecessor(loop_body_block_);
|
||||
b.setBuildPoint(loop_body_block_);
|
||||
|
||||
cf_blocks_.resize(instrs.size());
|
||||
for (size_t i = 0; i < cf_blocks_.size(); i++) {
|
||||
cf_blocks_[i].block = &b.makeNewBlock();
|
||||
cf_blocks_[i].labelled = false;
|
||||
}
|
||||
|
||||
if (instr.opcode() == ControlFlowOpcode::kCondJmp) {
|
||||
auto cf_block = cf_blocks_.find(instr.cond_jmp.address());
|
||||
if (cf_block == cf_blocks_.end()) {
|
||||
CFBlock block;
|
||||
block.prev_dominates = false;
|
||||
cf_blocks_[instr.cond_jmp.address()] = block;
|
||||
} else {
|
||||
cf_block->second.prev_dominates = false;
|
||||
std::vector<uint32_t> operands;
|
||||
operands.push_back(b.createLoad(pc_)); // Selector
|
||||
operands.push_back(default_block->getId()); // Default
|
||||
|
||||
// Always have a case for block 0.
|
||||
operands.push_back(0);
|
||||
operands.push_back(cf_blocks_[0].block->getId());
|
||||
cf_blocks_[0].block->addPredecessor(loop_body_block_);
|
||||
cf_blocks_[0].labelled = true;
|
||||
|
||||
for (size_t i = 0; i < instrs.size(); i++) {
|
||||
auto& instr = instrs[i];
|
||||
if (instr.opcode() == ucode::ControlFlowOpcode::kCondJmp) {
|
||||
uint32_t address = instr.cond_jmp.address();
|
||||
cf_blocks_[address].labelled = true;
|
||||
|
||||
operands.push_back(address);
|
||||
operands.push_back(cf_blocks_[address].block->getId());
|
||||
cf_blocks_[address].block->addPredecessor(loop_body_block_);
|
||||
} else if (instr.opcode() == ucode::ControlFlowOpcode::kLoopStart) {
|
||||
uint32_t address = instr.loop_start.address();
|
||||
cf_blocks_[address].labelled = true;
|
||||
|
||||
operands.push_back(address);
|
||||
operands.push_back(cf_blocks_[address].block->getId());
|
||||
cf_blocks_[address].block->addPredecessor(loop_body_block_);
|
||||
} else if (instr.opcode() == ucode::ControlFlowOpcode::kLoopEnd) {
|
||||
uint32_t address = instr.loop_end.address();
|
||||
cf_blocks_[address].labelled = true;
|
||||
|
||||
operands.push_back(address);
|
||||
operands.push_back(cf_blocks_[address].block->getId());
|
||||
cf_blocks_[address].block->addPredecessor(loop_body_block_);
|
||||
}
|
||||
} else if (instr.opcode() == ControlFlowOpcode::kLoopStart) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
b.createSelectionMerge(switch_break_block_, 0);
|
||||
b.createNoResultOp(spv::Op::OpSwitch, operands);
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::ProcessLabel(uint32_t cf_index) {
|
||||
|
@ -601,11 +682,6 @@ void SpirvShaderTranslator::ProcessLabel(uint32_t cf_index) {
|
|||
void SpirvShaderTranslator::ProcessControlFlowInstructionBegin(
|
||||
uint32_t cf_index) {
|
||||
auto& b = *builder_;
|
||||
|
||||
if (cf_index == 0) {
|
||||
// Kind of cheaty, but emit a branch to the first block.
|
||||
b.createBranch(cf_blocks_[cf_index].block);
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::ProcessControlFlowInstructionEnd(
|
||||
|
@ -613,10 +689,18 @@ void SpirvShaderTranslator::ProcessControlFlowInstructionEnd(
|
|||
auto& b = *builder_;
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::ProcessControlFlowNopInstruction() {
|
||||
void SpirvShaderTranslator::ProcessControlFlowNopInstruction(
|
||||
uint32_t cf_index) {
|
||||
auto& b = *builder_;
|
||||
|
||||
// b.createNoResultOp(spv::Op::OpNop);
|
||||
auto head = cf_blocks_[cf_index].block;
|
||||
b.setBuildPoint(head);
|
||||
b.createNoResultOp(spv::Op::OpNop);
|
||||
if (cf_blocks_.size() > cf_index + 1) {
|
||||
b.createBranch(cf_blocks_[cf_index + 1].block);
|
||||
} else {
|
||||
b.makeReturn(false);
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::ProcessExecInstructionBegin(
|
||||
|
@ -635,6 +719,7 @@ void SpirvShaderTranslator::ProcessExecInstructionBegin(
|
|||
switch (instr.type) {
|
||||
case ParsedExecInstruction::Type::kUnconditional: {
|
||||
// No need to do anything.
|
||||
exec_cond_ = false;
|
||||
} break;
|
||||
case ParsedExecInstruction::Type::kConditional: {
|
||||
// Based off of bool_consts
|
||||
|
@ -665,27 +750,34 @@ void SpirvShaderTranslator::ProcessExecInstructionBegin(
|
|||
// Conditional branch
|
||||
assert_true(cf_blocks_.size() > instr.dword_index + 1);
|
||||
body = &b.makeNewBlock();
|
||||
exec_cond_ = true;
|
||||
exec_skip_block_ = &b.makeNewBlock();
|
||||
|
||||
auto next_block = cf_blocks_[instr.dword_index + 1];
|
||||
if (next_block.prev_dominates) {
|
||||
b.createSelectionMerge(next_block.block, spv::SelectionControlMaskNone);
|
||||
}
|
||||
b.createConditionalBranch(cond, body, next_block.block);
|
||||
b.createSelectionMerge(
|
||||
exec_skip_block_,
|
||||
spv::SelectionControlMask::SelectionControlMaskNone);
|
||||
b.createConditionalBranch(cond, body, exec_skip_block_);
|
||||
|
||||
b.setBuildPoint(exec_skip_block_);
|
||||
b.createBranch(cf_blocks_[instr.dword_index + 1].block);
|
||||
} break;
|
||||
case ParsedExecInstruction::Type::kPredicated: {
|
||||
// Branch based on p0.
|
||||
assert_true(cf_blocks_.size() > instr.dword_index + 1);
|
||||
body = &b.makeNewBlock();
|
||||
exec_cond_ = true;
|
||||
exec_skip_block_ = &b.makeNewBlock();
|
||||
|
||||
auto cond =
|
||||
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_),
|
||||
b.makeBoolConstant(instr.condition));
|
||||
b.createSelectionMerge(
|
||||
exec_skip_block_,
|
||||
spv::SelectionControlMask::SelectionControlMaskNone);
|
||||
b.createConditionalBranch(cond, body, exec_skip_block_);
|
||||
|
||||
auto next_block = cf_blocks_[instr.dword_index + 1];
|
||||
if (next_block.prev_dominates) {
|
||||
b.createSelectionMerge(next_block.block, spv::SelectionControlMaskNone);
|
||||
}
|
||||
b.createConditionalBranch(cond, body, next_block.block);
|
||||
|
||||
b.setBuildPoint(exec_skip_block_);
|
||||
b.createBranch(cf_blocks_[instr.dword_index + 1].block);
|
||||
} break;
|
||||
}
|
||||
b.setBuildPoint(body);
|
||||
|
@ -705,6 +797,8 @@ void SpirvShaderTranslator::ProcessExecInstructionEnd(
|
|||
|
||||
if (instr.is_end) {
|
||||
b.makeReturn(false);
|
||||
} else if (exec_cond_) {
|
||||
b.createBranch(exec_skip_block_);
|
||||
} else {
|
||||
assert_true(cf_blocks_.size() > instr.dword_index + 1);
|
||||
b.createBranch(cf_blocks_[instr.dword_index + 1].block);
|
||||
|
@ -779,7 +873,8 @@ void SpirvShaderTranslator::ProcessJumpInstruction(
|
|||
b.setBuildPoint(head);
|
||||
switch (instr.type) {
|
||||
case ParsedJumpInstruction::Type::kUnconditional: {
|
||||
b.createBranch(cf_blocks_[instr.target_address].block);
|
||||
b.createStore(b.makeIntConstant(instr.target_address), pc_);
|
||||
b.createBranch(switch_break_block_);
|
||||
} break;
|
||||
case ParsedJumpInstruction::Type::kConditional: {
|
||||
assert_true(cf_blocks_.size() > instr.dword_index + 1);
|
||||
|
@ -810,8 +905,11 @@ void SpirvShaderTranslator::ProcessJumpInstruction(
|
|||
instr.condition ? spv::Op::OpINotEqual : spv::Op::OpIEqual,
|
||||
bool_type_, v, b.makeUintConstant(0));
|
||||
|
||||
b.createConditionalBranch(cond, cf_blocks_[instr.target_address].block,
|
||||
cf_blocks_[instr.dword_index + 1].block);
|
||||
auto next_pc = b.createTriOp(spv::Op::OpSelect, int_type_, cond,
|
||||
b.makeIntConstant(instr.target_address),
|
||||
b.makeIntConstant(instr.dword_index + 1));
|
||||
b.createStore(next_pc, pc_);
|
||||
b.createBranch(switch_break_block_);
|
||||
} break;
|
||||
case ParsedJumpInstruction::Type::kPredicated: {
|
||||
assert_true(cf_blocks_.size() > instr.dword_index + 1);
|
||||
|
@ -819,8 +917,12 @@ void SpirvShaderTranslator::ProcessJumpInstruction(
|
|||
auto cond =
|
||||
b.createBinOp(spv::Op::OpLogicalEqual, bool_type_, b.createLoad(p0_),
|
||||
b.makeBoolConstant(instr.condition));
|
||||
b.createConditionalBranch(cond, cf_blocks_[instr.target_address].block,
|
||||
cf_blocks_[instr.dword_index + 1].block);
|
||||
|
||||
auto next_pc = b.createTriOp(spv::Op::OpSelect, int_type_, cond,
|
||||
b.makeIntConstant(instr.target_address),
|
||||
b.makeIntConstant(instr.dword_index + 1));
|
||||
b.createStore(next_pc, pc_);
|
||||
b.createBranch(switch_break_block_);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
@ -854,6 +956,43 @@ void SpirvShaderTranslator::ProcessAllocInstruction(
|
|||
b.createBranch(cf_blocks_[instr.dword_index + 1].block);
|
||||
}
|
||||
|
||||
spv::Id SpirvShaderTranslator::BitfieldExtract(spv::Id result_type,
|
||||
spv::Id base, bool is_signed,
|
||||
uint32_t offset,
|
||||
uint32_t count) {
|
||||
auto& b = *builder_;
|
||||
|
||||
spv::Id base_type = b.getTypeId(base);
|
||||
|
||||
// <-- 32 - (offset + count) ------ [bits] -?-
|
||||
base = b.createBinOp(spv::Op::OpShiftLeftLogical, base_type, base,
|
||||
b.makeUintConstant(32 - (offset + count)));
|
||||
// [bits] -?-?-?---------------------------
|
||||
auto op = is_signed ? spv::Op::OpShiftRightArithmetic
|
||||
: spv::Op::OpShiftRightLogical;
|
||||
base = b.createBinOp(op, base_type, base, b.makeUintConstant(32 - count));
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
spv::Id SpirvShaderTranslator::ConvertNormVar(spv::Id var, spv::Id result_type,
|
||||
uint32_t bits, bool is_signed) {
|
||||
auto& b = *builder_;
|
||||
if (is_signed) {
|
||||
auto c = b.createBinOp(spv::Op::OpFOrdEqual, bool_type_, var,
|
||||
b.makeFloatConstant(-float(1 << (bits - 1))));
|
||||
auto v = b.createBinOp(spv::Op::OpFDiv, result_type, var,
|
||||
b.makeFloatConstant(float((1 << (bits - 1)) - 1)));
|
||||
var = b.createTriOp(spv::Op::OpSelect, result_type, c,
|
||||
b.makeFloatConstant(-1.f), v);
|
||||
} else {
|
||||
var = b.createBinOp(spv::Op::OpFDiv, result_type, var,
|
||||
b.makeFloatConstant(float((1 << bits) - 1)));
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::ProcessVertexFetchInstruction(
|
||||
const ParsedVertexFetchInstruction& instr) {
|
||||
auto& b = *builder_;
|
||||
|
@ -894,6 +1033,9 @@ void SpirvShaderTranslator::ProcessVertexFetchInstruction(
|
|||
vertex_idx = b.createUnaryOp(spv::Op::OpConvertFToS, int_type_, vertex_idx);
|
||||
auto shader_vertex_idx = b.createLoad(vertex_idx_);
|
||||
|
||||
auto vertex_components =
|
||||
GetVertexFormatComponentCount(instr.attributes.data_format);
|
||||
|
||||
// Skip loading if it's an indexed fetch.
|
||||
auto vertex_ptr = vertex_binding_map_[instr.operands[1].storage_index]
|
||||
[instr.attributes.offset];
|
||||
|
@ -902,7 +1044,6 @@ void SpirvShaderTranslator::ProcessVertexFetchInstruction(
|
|||
|
||||
auto cond = b.createBinOp(spv::Op::OpIEqual, bool_type_, vertex_idx,
|
||||
shader_vertex_idx);
|
||||
auto vertex_components = b.getNumComponents(vertex);
|
||||
Id alt_vertex = 0;
|
||||
switch (vertex_components) {
|
||||
case 1:
|
||||
|
@ -949,11 +1090,79 @@ void SpirvShaderTranslator::ProcessVertexFetchInstruction(
|
|||
break;
|
||||
|
||||
case VertexFormat::k_10_11_11: {
|
||||
// No conversion needed. Natively supported.
|
||||
// This needs to be converted.
|
||||
bool is_signed = instr.attributes.is_signed;
|
||||
auto op =
|
||||
is_signed ? spv::Op::OpBitFieldSExtract : spv::Op::OpBitFieldUExtract;
|
||||
auto comp_type = is_signed ? int_type_ : uint_type_;
|
||||
|
||||
assert_true(comp_type == b.getTypeId(vertex));
|
||||
|
||||
spv::Id components[3] = {0};
|
||||
/*
|
||||
components[2] = b.createTriOp(
|
||||
op, comp_type, vertex, b.makeUintConstant(0), b.makeUintConstant(10));
|
||||
components[1] =
|
||||
b.createTriOp(op, comp_type, vertex, b.makeUintConstant(10),
|
||||
b.makeUintConstant(11));
|
||||
components[0] =
|
||||
b.createTriOp(op, comp_type, vertex, b.makeUintConstant(21),
|
||||
b.makeUintConstant(11));
|
||||
*/
|
||||
// Workaround until NVIDIA fixes their compiler :|
|
||||
components[0] = BitfieldExtract(comp_type, vertex, is_signed, 00, 10);
|
||||
components[1] = BitfieldExtract(comp_type, vertex, is_signed, 10, 11);
|
||||
components[2] = BitfieldExtract(comp_type, vertex, is_signed, 21, 11);
|
||||
|
||||
op = is_signed ? spv::Op::OpConvertSToF : spv::Op::OpConvertUToF;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
components[i] = b.createUnaryOp(op, float_type_, components[i]);
|
||||
}
|
||||
|
||||
components[0] = ConvertNormVar(components[0], float_type_, 11, is_signed);
|
||||
components[1] = ConvertNormVar(components[1], float_type_, 11, is_signed);
|
||||
components[2] = ConvertNormVar(components[2], float_type_, 10, is_signed);
|
||||
|
||||
vertex = b.createCompositeConstruct(
|
||||
vec3_float_type_,
|
||||
std::vector<Id>({components[0], components[1], components[2]}));
|
||||
} break;
|
||||
|
||||
case VertexFormat::k_11_11_10: {
|
||||
// This needs to be converted.
|
||||
bool is_signed = instr.attributes.is_signed;
|
||||
auto op =
|
||||
is_signed ? spv::Op::OpBitFieldSExtract : spv::Op::OpBitFieldUExtract;
|
||||
auto comp_type = is_signed ? int_type_ : uint_type_;
|
||||
|
||||
spv::Id components[3] = {0};
|
||||
/*
|
||||
components[2] = b.createTriOp(
|
||||
op, comp_type, vertex, b.makeUintConstant(0), b.makeUintConstant(11));
|
||||
components[1] =
|
||||
b.createTriOp(op, comp_type, vertex, b.makeUintConstant(11),
|
||||
b.makeUintConstant(11));
|
||||
components[0] =
|
||||
b.createTriOp(op, comp_type, vertex, b.makeUintConstant(22),
|
||||
b.makeUintConstant(10));
|
||||
*/
|
||||
// Workaround until NVIDIA fixes their compiler :|
|
||||
components[0] = BitfieldExtract(comp_type, vertex, is_signed, 00, 11);
|
||||
components[1] = BitfieldExtract(comp_type, vertex, is_signed, 11, 11);
|
||||
components[2] = BitfieldExtract(comp_type, vertex, is_signed, 22, 10);
|
||||
|
||||
op = is_signed ? spv::Op::OpConvertSToF : spv::Op::OpConvertUToF;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
components[i] = b.createUnaryOp(op, float_type_, components[i]);
|
||||
}
|
||||
|
||||
components[0] = ConvertNormVar(components[0], float_type_, 11, is_signed);
|
||||
components[1] = ConvertNormVar(components[1], float_type_, 11, is_signed);
|
||||
components[2] = ConvertNormVar(components[2], float_type_, 10, is_signed);
|
||||
|
||||
vertex = b.createCompositeConstruct(
|
||||
vec3_float_type_,
|
||||
std::vector<Id>({components[0], components[1], components[2]}));
|
||||
} break;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,12 +56,12 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
std::vector<uint8_t> CompleteTranslation() override;
|
||||
void PostTranslation(Shader* shader) override;
|
||||
|
||||
void PreProcessControlFlowInstruction(
|
||||
uint32_t cf_index, const ucode::ControlFlowInstruction& instr) override;
|
||||
void PreProcessControlFlowInstructions(
|
||||
std::vector<ucode::ControlFlowInstruction> instrs) override;
|
||||
void ProcessLabel(uint32_t cf_index) override;
|
||||
void ProcessControlFlowInstructionBegin(uint32_t cf_index) override;
|
||||
void ProcessControlFlowInstructionEnd(uint32_t cf_index) override;
|
||||
void ProcessControlFlowNopInstruction() override;
|
||||
void ProcessControlFlowNopInstruction(uint32_t cf_index) override;
|
||||
void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) override;
|
||||
void ProcessExecInstructionEnd(const ParsedExecInstruction& instr) override;
|
||||
void ProcessLoopStartInstruction(
|
||||
|
@ -84,6 +84,11 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
void ProcessVectorAluInstruction(const ParsedAluInstruction& instr);
|
||||
void ProcessScalarAluInstruction(const ParsedAluInstruction& instr);
|
||||
|
||||
spv::Id BitfieldExtract(spv::Id result_type, spv::Id base, bool is_signed,
|
||||
uint32_t offset, uint32_t count);
|
||||
spv::Id ConvertNormVar(spv::Id var, spv::Id result_type, uint32_t bits,
|
||||
bool is_signed);
|
||||
|
||||
// Creates a call to the given GLSL intrinsic.
|
||||
spv::Id SpirvShaderTranslator::CreateGlslStd450InstructionCall(
|
||||
spv::Decoration precision, spv::Id result_type,
|
||||
|
@ -107,6 +112,10 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
bool predicated_block_cond_ = false;
|
||||
spv::Block* predicated_block_end_ = nullptr;
|
||||
|
||||
// Exec block conditional?
|
||||
bool exec_cond_ = false;
|
||||
spv::Block* exec_skip_block_ = nullptr;
|
||||
|
||||
// TODO(benvanik): replace with something better, make reusable, etc.
|
||||
std::unique_ptr<spv::Builder> builder_;
|
||||
spv::Id glsl_std_450_instruction_set_ = 0;
|
||||
|
@ -132,6 +141,7 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
spv::Id registers_ptr_ = 0, registers_type_ = 0;
|
||||
spv::Id consts_ = 0, a0_ = 0, aL_ = 0, p0_ = 0;
|
||||
spv::Id ps_ = 0, pv_ = 0; // IDs of previous results
|
||||
spv::Id pc_ = 0; // Program counter
|
||||
spv::Id pos_ = 0;
|
||||
spv::Id push_consts_ = 0;
|
||||
spv::Id interpolators_ = 0;
|
||||
|
@ -148,9 +158,14 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
|
||||
struct CFBlock {
|
||||
spv::Block* block = nullptr;
|
||||
bool prev_dominates = true;
|
||||
bool labelled = false;
|
||||
};
|
||||
std::map<uint32_t, CFBlock> cf_blocks_;
|
||||
std::vector<CFBlock> cf_blocks_;
|
||||
spv::Block* switch_break_block_ = nullptr;
|
||||
spv::Block* loop_head_block_ = nullptr;
|
||||
spv::Block* loop_body_block_ = nullptr;
|
||||
spv::Block* loop_cont_block_ = nullptr;
|
||||
spv::Block* loop_exit_block_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
|
|
@ -896,19 +896,18 @@ PipelineCache::UpdateStatus PipelineCache::UpdateVertexInputState(
|
|||
break;
|
||||
case VertexFormat::k_2_10_10_10:
|
||||
vertex_attrib_descr.format = is_signed
|
||||
? VK_FORMAT_A2R10G10B10_SNORM_PACK32
|
||||
: VK_FORMAT_A2R10G10B10_UNORM_PACK32;
|
||||
? VK_FORMAT_A2B10G10R10_SNORM_PACK32
|
||||
: VK_FORMAT_A2B10G10R10_UNORM_PACK32;
|
||||
break;
|
||||
case VertexFormat::k_10_11_11:
|
||||
assert_true(is_signed);
|
||||
vertex_attrib_descr.format = VK_FORMAT_B10G11R11_UFLOAT_PACK32;
|
||||
// Converted in-shader.
|
||||
vertex_attrib_descr.format =
|
||||
is_signed ? VK_FORMAT_R32_SINT : VK_FORMAT_R32_UINT;
|
||||
break;
|
||||
case VertexFormat::k_11_11_10:
|
||||
// Converted in-shader.
|
||||
// TODO(DrChat)
|
||||
assert_always();
|
||||
// vertex_attrib_descr.format = VK_FORMAT_R32_UINT;
|
||||
vertex_attrib_descr.format = VK_FORMAT_B10G11R11_UFLOAT_PACK32;
|
||||
vertex_attrib_descr.format =
|
||||
is_signed ? VK_FORMAT_R32_SINT : VK_FORMAT_R32_UINT;
|
||||
break;
|
||||
case VertexFormat::k_16_16:
|
||||
vertex_attrib_descr.format =
|
||||
|
@ -927,14 +926,20 @@ PipelineCache::UpdateStatus PipelineCache::UpdateVertexInputState(
|
|||
vertex_attrib_descr.format = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
break;
|
||||
case VertexFormat::k_32:
|
||||
// FIXME: Is this a NORM format?
|
||||
assert_always();
|
||||
vertex_attrib_descr.format =
|
||||
is_signed ? VK_FORMAT_R32_SINT : VK_FORMAT_R32_UINT;
|
||||
break;
|
||||
case VertexFormat::k_32_32:
|
||||
// FIXME: Is this a NORM format?
|
||||
assert_always();
|
||||
vertex_attrib_descr.format =
|
||||
is_signed ? VK_FORMAT_R32G32_SINT : VK_FORMAT_R32G32_UINT;
|
||||
break;
|
||||
case VertexFormat::k_32_32_32_32:
|
||||
// FIXME: Is this a NORM format?
|
||||
assert_always();
|
||||
vertex_attrib_descr.format =
|
||||
is_signed ? VK_FORMAT_R32G32B32A32_SINT : VK_FORMAT_R32_UINT;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue