|
|
@ -165,6 +165,7 @@ public: |
|
|
DeclareConstantBuffers(); |
|
|
DeclareConstantBuffers(); |
|
|
DeclareGlobalMemory(); |
|
|
DeclareGlobalMemory(); |
|
|
DeclareSamplers(); |
|
|
DeclareSamplers(); |
|
|
|
|
|
DeclarePhysicalAttributeReader(); |
|
|
|
|
|
|
|
|
code.AddLine("void execute_" + suffix + "() {"); |
|
|
code.AddLine("void execute_" + suffix + "() {"); |
|
|
++code.scope; |
|
|
++code.scope; |
|
|
@ -330,8 +331,7 @@ private: |
|
|
|
|
|
|
|
|
void DeclareInputAttributes() { |
|
|
void DeclareInputAttributes() { |
|
|
if (ir.HasPhysicalAttributes()) { |
|
|
if (ir.HasPhysicalAttributes()) { |
|
|
const u32 num_inputs{stage == ShaderStage::Vertex ? GetNumPhysicalAttributes() |
|
|
|
|
|
: GetNumPhysicalVaryings()}; |
|
|
|
|
|
|
|
|
const u32 num_inputs{GetNumPhysicalInputAttributes()}; |
|
|
for (u32 i = 0; i < num_inputs; ++i) { |
|
|
for (u32 i = 0; i < num_inputs; ++i) { |
|
|
DeclareInputAttribute(ToGenericAttribute(i)); |
|
|
DeclareInputAttribute(ToGenericAttribute(i)); |
|
|
} |
|
|
} |
|
|
@ -374,7 +374,7 @@ private: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void DeclareOutputAttributes() { |
|
|
void DeclareOutputAttributes() { |
|
|
if (ir.HasPhysicalAttributes()) { |
|
|
|
|
|
|
|
|
if (ir.HasPhysicalAttributes() && stage != ShaderStage::Fragment) { |
|
|
for (u32 i = 0; i < GetNumPhysicalVaryings(); ++i) { |
|
|
for (u32 i = 0; i < GetNumPhysicalVaryings(); ++i) { |
|
|
DeclareOutputAttribute(ToGenericAttribute(i)); |
|
|
DeclareOutputAttribute(ToGenericAttribute(i)); |
|
|
} |
|
|
} |
|
|
@ -461,6 +461,31 @@ private: |
|
|
code.AddNewLine(); |
|
|
code.AddNewLine(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void DeclarePhysicalAttributeReader() { |
|
|
|
|
|
if (!ir.HasPhysicalAttributes()) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
code.AddLine("float readPhysicalAttribute(uint physical_address) {"); |
|
|
|
|
|
++code.scope; |
|
|
|
|
|
code.AddLine("switch (physical_address) {"); |
|
|
|
|
|
|
|
|
|
|
|
// Just declare generic attributes for now.
|
|
|
|
|
|
const auto num_attributes{static_cast<u32>(GetNumPhysicalAttributes())}; |
|
|
|
|
|
for (u32 index = 0; index < num_attributes; ++index) { |
|
|
|
|
|
for (u32 element = 0; element < 4; ++element) { |
|
|
|
|
|
code.AddLine(fmt::format("case 0x{:x}: return {};", 0x80 + index * 16 + element * 4, |
|
|
|
|
|
ReadAttribute(ToGenericAttribute(index), element))); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
code.AddLine("default: return 0;"); |
|
|
|
|
|
|
|
|
|
|
|
code.AddLine('}'); |
|
|
|
|
|
--code.scope; |
|
|
|
|
|
code.AddLine('}'); |
|
|
|
|
|
code.AddNewLine(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void VisitBlock(const NodeBlock& bb) { |
|
|
void VisitBlock(const NodeBlock& bb) { |
|
|
for (const Node node : bb) { |
|
|
for (const Node node : bb) { |
|
|
if (const std::string expr = Visit(node); !expr.empty()) { |
|
|
if (const std::string expr = Visit(node); !expr.empty()) { |
|
|
@ -515,16 +540,70 @@ private: |
|
|
return value; |
|
|
return value; |
|
|
|
|
|
|
|
|
} else if (const auto abuf = std::get_if<AbufNode>(node)) { |
|
|
} else if (const auto abuf = std::get_if<AbufNode>(node)) { |
|
|
const auto attribute = abuf->GetIndex(); |
|
|
|
|
|
const auto element = abuf->GetElement(); |
|
|
|
|
|
|
|
|
UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry, |
|
|
|
|
|
"Physical attributes in geometry shaders are not implemented"); |
|
|
|
|
|
if (abuf->IsPhysicalBuffer()) { |
|
|
|
|
|
return "readPhysicalAttribute(ftou(" + Visit(abuf->GetPhysicalAddress()) + "))"; |
|
|
|
|
|
} |
|
|
|
|
|
return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto cbuf = std::get_if<CbufNode>(node)) { |
|
|
|
|
|
const Node offset = cbuf->GetOffset(); |
|
|
|
|
|
if (const auto immediate = std::get_if<ImmediateNode>(offset)) { |
|
|
|
|
|
// Direct access
|
|
|
|
|
|
const u32 offset_imm = immediate->GetValue(); |
|
|
|
|
|
ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access"); |
|
|
|
|
|
return fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()), |
|
|
|
|
|
offset_imm / (4 * 4), (offset_imm / 4) % 4); |
|
|
|
|
|
|
|
|
|
|
|
} else if (std::holds_alternative<OperationNode>(*offset)) { |
|
|
|
|
|
// Indirect access
|
|
|
|
|
|
const std::string final_offset = code.GenerateTemporary(); |
|
|
|
|
|
code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4);"); |
|
|
|
|
|
return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), |
|
|
|
|
|
final_offset, final_offset); |
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
UNREACHABLE_MSG("Unmanaged offset node type"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto gmem = std::get_if<GmemNode>(node)) { |
|
|
|
|
|
const std::string real = Visit(gmem->GetRealAddress()); |
|
|
|
|
|
const std::string base = Visit(gmem->GetBaseAddress()); |
|
|
|
|
|
const std::string final_offset = "(ftou(" + real + ") - ftou(" + base + ")) / 4"; |
|
|
|
|
|
return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto lmem = std::get_if<LmemNode>(node)) { |
|
|
|
|
|
return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) { |
|
|
|
|
|
return GetInternalFlag(internal_flag->GetFlag()); |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto conditional = std::get_if<ConditionalNode>(node)) { |
|
|
|
|
|
// It's invalid to call conditional on nested nodes, use an operation instead
|
|
|
|
|
|
code.AddLine("if (" + Visit(conditional->GetCondition()) + ") {"); |
|
|
|
|
|
++code.scope; |
|
|
|
|
|
|
|
|
|
|
|
VisitBlock(conditional->GetCode()); |
|
|
|
|
|
|
|
|
|
|
|
--code.scope; |
|
|
|
|
|
code.AddLine('}'); |
|
|
|
|
|
return {}; |
|
|
|
|
|
|
|
|
const auto GeometryPass = [&](const std::string& name) { |
|
|
|
|
|
if (stage == ShaderStage::Geometry && abuf->GetBuffer()) { |
|
|
|
|
|
|
|
|
} else if (const auto comment = std::get_if<CommentNode>(node)) { |
|
|
|
|
|
return "// " + comment->GetText(); |
|
|
|
|
|
} |
|
|
|
|
|
UNREACHABLE(); |
|
|
|
|
|
return {}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) { |
|
|
|
|
|
const auto GeometryPass = [&](std::string name) { |
|
|
|
|
|
if (stage == ShaderStage::Geometry && buffer) { |
|
|
// TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
|
|
|
// TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
|
|
|
// set an 0x80000000 index for those and the shader fails to build. Find out why
|
|
|
// set an 0x80000000 index for those and the shader fails to build. Find out why
|
|
|
// this happens and what's its intent.
|
|
|
// this happens and what's its intent.
|
|
|
return "gs_" + name + "[ftou(" + Visit(abuf->GetBuffer()) + |
|
|
|
|
|
") % MAX_VERTEX_INPUT]"; |
|
|
|
|
|
|
|
|
return "gs_" + std::move(name) + "[ftou(" + Visit(buffer) + ") % MAX_VERTEX_INPUT]"; |
|
|
} |
|
|
} |
|
|
return name; |
|
|
return name; |
|
|
}; |
|
|
}; |
|
|
@ -578,55 +657,7 @@ private: |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); |
|
|
UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); |
|
|
|
|
|
|
|
|
} else if (const auto cbuf = std::get_if<CbufNode>(node)) { |
|
|
|
|
|
const Node offset = cbuf->GetOffset(); |
|
|
|
|
|
if (const auto immediate = std::get_if<ImmediateNode>(offset)) { |
|
|
|
|
|
// Direct access
|
|
|
|
|
|
const u32 offset_imm = immediate->GetValue(); |
|
|
|
|
|
ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access"); |
|
|
|
|
|
return fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()), |
|
|
|
|
|
offset_imm / (4 * 4), (offset_imm / 4) % 4); |
|
|
|
|
|
|
|
|
|
|
|
} else if (std::holds_alternative<OperationNode>(*offset)) { |
|
|
|
|
|
// Indirect access
|
|
|
|
|
|
const std::string final_offset = code.GenerateTemporary(); |
|
|
|
|
|
code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4);"); |
|
|
|
|
|
return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), |
|
|
|
|
|
final_offset, final_offset); |
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
UNREACHABLE_MSG("Unmanaged offset node type"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto gmem = std::get_if<GmemNode>(node)) { |
|
|
|
|
|
const std::string real = Visit(gmem->GetRealAddress()); |
|
|
|
|
|
const std::string base = Visit(gmem->GetBaseAddress()); |
|
|
|
|
|
const std::string final_offset = "(ftou(" + real + ") - ftou(" + base + ")) / 4"; |
|
|
|
|
|
return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto lmem = std::get_if<LmemNode>(node)) { |
|
|
|
|
|
return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) { |
|
|
|
|
|
return GetInternalFlag(internal_flag->GetFlag()); |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto conditional = std::get_if<ConditionalNode>(node)) { |
|
|
|
|
|
// It's invalid to call conditional on nested nodes, use an operation instead
|
|
|
|
|
|
code.AddLine("if (" + Visit(conditional->GetCondition()) + ") {"); |
|
|
|
|
|
++code.scope; |
|
|
|
|
|
|
|
|
|
|
|
VisitBlock(conditional->GetCode()); |
|
|
|
|
|
|
|
|
|
|
|
--code.scope; |
|
|
|
|
|
code.AddLine('}'); |
|
|
|
|
|
return {}; |
|
|
|
|
|
|
|
|
|
|
|
} else if (const auto comment = std::get_if<CommentNode>(node)) { |
|
|
|
|
|
return "// " + comment->GetText(); |
|
|
|
|
|
} |
|
|
|
|
|
UNREACHABLE(); |
|
|
|
|
|
return {}; |
|
|
|
|
|
|
|
|
return "0"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::string ApplyPrecise(Operation operation, const std::string& value) { |
|
|
std::string ApplyPrecise(Operation operation, const std::string& value) { |
|
|
@ -1677,6 +1708,10 @@ private: |
|
|
return name + '_' + std::to_string(index) + '_' + suffix; |
|
|
return name + '_' + std::to_string(index) + '_' + suffix; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
u32 GetNumPhysicalInputAttributes() const { |
|
|
|
|
|
return stage == ShaderStage::Vertex ? GetNumPhysicalAttributes() : GetNumPhysicalVaryings(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
u32 GetNumPhysicalAttributes() const { |
|
|
u32 GetNumPhysicalAttributes() const { |
|
|
return std::min<u32>(device.GetMaxVertexAttributes(), Maxwell::NumVertexAttributes); |
|
|
return std::min<u32>(device.GetMaxVertexAttributes(), Maxwell::NumVertexAttributes); |
|
|
} |
|
|
} |
|
|
|