shader_ir: Clean texture management code

Previous code relied on GLSL parameter order (something that's always
ill-formed on an IR design). This approach passes spatial coordiantes
through operation nodes and array and depth compare values in the the
texture metadata. It still contains an "extra" vector containing generic
nodes for bias and component index (for example) which is still a bit
ill-formed but it should be better than the previous approach.
This commit is contained in:
ReinUsesLisp 2019-01-29 04:31:40 -03:00
parent f09d1dffd1
commit d62b0a9e29
3 changed files with 104 additions and 133 deletions

View file

@ -719,45 +719,51 @@ private:
constexpr std::array<const char*, 4> coord_constructors = {"float", "vec2", "vec3", "vec4"}; constexpr std::array<const char*, 4> coord_constructors = {"float", "vec2", "vec3", "vec4"};
const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
const auto count = static_cast<u32>(operation.GetOperandsCount());
ASSERT(meta); ASSERT(meta);
const auto count = static_cast<u32>(operation.GetOperandsCount());
const bool has_array = meta->sampler.IsArray();
const bool has_shadow = meta->sampler.IsShadow();
std::string expr = func; std::string expr = func;
expr += '('; expr += '(';
expr += GetSampler(meta->sampler); expr += GetSampler(meta->sampler);
expr += ", "; expr += ", ";
expr += coord_constructors[meta->coords_count - 1]; expr += coord_constructors.at(count + (has_array ? 1 : 0) + (has_shadow ? 1 : 0) - 1);
expr += '('; expr += '(';
for (u32 i = 0; i < count; ++i) { for (u32 i = 0; i < count; ++i) {
const bool is_extra = i >= meta->coords_count; expr += Visit(operation[i]);
const bool is_array = i == meta->array_index;
std::string operand = [&]() { const u32 next = i + 1;
if (is_extra && is_extra_int) { if (next < count || has_array || has_shadow)
if (const auto immediate = std::get_if<ImmediateNode>(operation[i])) {
return std::to_string(static_cast<s32>(immediate->GetValue()));
} else {
return "ftoi(" + Visit(operation[i]) + ')';
}
} else {
return Visit(operation[i]);
}
}();
if (is_array) {
ASSERT(!is_extra);
operand = "float(ftoi(" + operand + "))";
}
expr += operand;
if (i + 1 == meta->coords_count) {
expr += ')';
}
if (i + 1 < count) {
expr += ", "; expr += ", ";
}
if (has_array) {
expr += "float(ftoi(" + Visit(meta->array) + "))";
}
if (has_shadow) {
if (has_array)
expr += ", ";
expr += Visit(meta->depth_compare);
}
expr += ')';
for (const Node extra : meta->extras) {
expr += ", ";
if (is_extra_int) {
if (const auto immediate = std::get_if<ImmediateNode>(extra)) {
// Inline the string as an immediate integer in GLSL (some extra arguments are
// required to be constant)
expr += std::to_string(static_cast<s32>(immediate->GetValue()));
} else {
expr += "ftoi(" + Visit(extra) + ')';
}
} else {
expr += Visit(extra);
} }
} }
expr += ')'; expr += ')';
return expr; return expr;
} }
@ -1198,26 +1204,29 @@ private:
std::string F4TexelFetch(Operation operation) { std::string F4TexelFetch(Operation operation) {
constexpr std::array<const char*, 4> constructors = {"int", "ivec2", "ivec3", "ivec4"}; constexpr std::array<const char*, 4> constructors = {"int", "ivec2", "ivec3", "ivec4"};
const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
const auto count = static_cast<u32>(operation.GetOperandsCount());
ASSERT(meta); ASSERT(meta);
UNIMPLEMENTED_IF(meta->sampler.IsArray());
UNIMPLEMENTED_IF(!meta->extras.empty());
const auto count = static_cast<u32>(operation.GetOperandsCount());
std::string expr = "texelFetch("; std::string expr = "texelFetch(";
expr += GetSampler(meta->sampler); expr += GetSampler(meta->sampler);
expr += ", "; expr += ", ";
expr += constructors[meta->coords_count - 1]; expr += constructors.at(count - 1);
expr += '('; expr += '(';
for (u32 i = 0; i < count; ++i) { for (u32 i = 0; i < count; ++i) {
expr += VisitOperand(operation, i, Type::Int); expr += VisitOperand(operation, i, Type::Int);
if (i + 1 == meta->coords_count) { const u32 next = i + 1;
if (next == count)
expr += ')'; expr += ')';
} if (next < count)
if (i + 1 < count) {
expr += ", "; expr += ", ";
}
} }
expr += ')'; expr += ')';
return expr + GetSwizzle(meta->element); return expr + GetSwizzle(meta->element);
} }

View file

@ -306,7 +306,6 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
case OpCode::Id::TLD4S: { case OpCode::Id::TLD4S: {
UNIMPLEMENTED_IF_MSG(instr.tld4s.UsesMiscMode(TextureMiscMode::AOFFI), UNIMPLEMENTED_IF_MSG(instr.tld4s.UsesMiscMode(TextureMiscMode::AOFFI),
"AOFFI is not implemented"); "AOFFI is not implemented");
if (instr.tld4s.UsesMiscMode(TextureMiscMode::NODEP)) { if (instr.tld4s.UsesMiscMode(TextureMiscMode::NODEP)) {
LOG_WARNING(HW_GPU, "TLD4S.NODEP implementation is incomplete"); LOG_WARNING(HW_GPU, "TLD4S.NODEP implementation is incomplete");
} }
@ -315,9 +314,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
const Node op_a = GetRegister(instr.gpr8); const Node op_a = GetRegister(instr.gpr8);
const Node op_b = GetRegister(instr.gpr20); const Node op_b = GetRegister(instr.gpr20);
std::vector<Node> coords;
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
std::vector<Node> coords;
if (depth_compare) { if (depth_compare) {
// Note: TLD4S coordinate encoding works just like TEXS's // Note: TLD4S coordinate encoding works just like TEXS's
const Node op_y = GetRegister(instr.gpr8.Value() + 1); const Node op_y = GetRegister(instr.gpr8.Value() + 1);
@ -328,18 +326,18 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
coords.push_back(op_a); coords.push_back(op_a);
coords.push_back(op_b); coords.push_back(op_b);
} }
const auto num_coords = static_cast<u32>(coords.size()); std::vector<Node> extras;
coords.push_back(Immediate(static_cast<u32>(instr.tld4s.component))); extras.push_back(Immediate(static_cast<u32>(instr.tld4s.component)));
const auto& sampler = const auto& sampler =
GetSampler(instr.sampler, TextureType::Texture2D, false, depth_compare); GetSampler(instr.sampler, TextureType::Texture2D, false, depth_compare);
Node4 values; Node4 values;
for (u32 element = 0; element < values.size(); ++element) { for (u32 element = 0; element < values.size(); ++element) {
auto params = coords; auto coords_copy = coords;
MetaTexture meta{sampler, element, num_coords}; MetaTexture meta{sampler, {}, {}, extras, element};
values[element] = values[element] =
Operation(OperationCode::F4TextureGather, std::move(meta), std::move(params)); Operation(OperationCode::F4TextureGather, meta, std::move(coords_copy));
} }
WriteTexsInstructionFloat(bb, instr, values); WriteTexsInstructionFloat(bb, instr, values);
@ -360,12 +358,13 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
switch (instr.txq.query_type) { switch (instr.txq.query_type) {
case Tegra::Shader::TextureQueryType::Dimension: { case Tegra::Shader::TextureQueryType::Dimension: {
for (u32 element = 0; element < 4; ++element) { for (u32 element = 0; element < 4; ++element) {
if (instr.txq.IsComponentEnabled(element)) { if (!instr.txq.IsComponentEnabled(element)) {
MetaTexture meta{sampler, element}; continue;
const Node value = Operation(OperationCode::F4TextureQueryDimensions,
std::move(meta), GetRegister(instr.gpr8));
SetTemporal(bb, indexer++, value);
} }
MetaTexture meta{sampler, {}, {}, {}, element};
const Node value = Operation(OperationCode::F4TextureQueryDimensions, meta,
GetRegister(instr.gpr8));
SetTemporal(bb, indexer++, value);
} }
for (u32 i = 0; i < indexer; ++i) { for (u32 i = 0; i < indexer; ++i) {
SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i)); SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i));
@ -412,9 +411,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
for (u32 element = 0; element < 2; ++element) { for (u32 element = 0; element < 2; ++element) {
auto params = coords; auto params = coords;
MetaTexture meta_texture{sampler, element, static_cast<u32>(coords.size())}; MetaTexture meta{sampler, {}, {}, {}, element};
const Node value = const Node value = Operation(OperationCode::F4TextureQueryLod, meta, std::move(params));
Operation(OperationCode::F4TextureQueryLod, meta_texture, std::move(params));
SetTemporal(bb, element, value); SetTemporal(bb, element, value);
} }
for (u32 element = 0; element < 2; ++element) { for (u32 element = 0; element < 2; ++element) {
@ -535,15 +533,16 @@ void ShaderIR::WriteTexsInstructionHalfFloat(NodeBlock& bb, Instruction instr,
} }
Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
TextureProcessMode process_mode, bool depth_compare, bool is_array, TextureProcessMode process_mode, std::vector<Node> coords,
std::size_t array_offset, std::size_t bias_offset, Node array, Node depth_compare, u32 bias_offset) {
std::vector<Node>&& coords) { const bool is_array = array;
UNIMPLEMENTED_IF_MSG( const bool is_shadow = depth_compare;
(texture_type == TextureType::Texture3D && (is_array || depth_compare)) ||
(texture_type == TextureType::TextureCube && is_array && depth_compare),
"This method is not supported.");
const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) ||
(texture_type == TextureType::TextureCube && is_array && is_shadow),
"This method is not supported.");
const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, is_shadow);
const bool lod_needed = process_mode == TextureProcessMode::LZ || const bool lod_needed = process_mode == TextureProcessMode::LZ ||
process_mode == TextureProcessMode::LL || process_mode == TextureProcessMode::LL ||
@ -552,35 +551,30 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
// LOD selection (either via bias or explicit textureLod) not supported in GL for // LOD selection (either via bias or explicit textureLod) not supported in GL for
// sampler2DArrayShadow and samplerCubeArrayShadow. // sampler2DArrayShadow and samplerCubeArrayShadow.
const bool gl_lod_supported = const bool gl_lod_supported =
!((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) || !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && is_shadow) ||
(texture_type == Tegra::Shader::TextureType::TextureCube && is_array && depth_compare)); (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && is_shadow));
const OperationCode read_method = const OperationCode read_method =
lod_needed && gl_lod_supported ? OperationCode::F4TextureLod : OperationCode::F4Texture; lod_needed && gl_lod_supported ? OperationCode::F4TextureLod : OperationCode::F4Texture;
UNIMPLEMENTED_IF(process_mode != TextureProcessMode::None && !gl_lod_supported); UNIMPLEMENTED_IF(process_mode != TextureProcessMode::None && !gl_lod_supported);
std::optional<u32> array_offset_value; std::vector<Node> extras;
if (is_array)
array_offset_value = static_cast<u32>(array_offset);
const auto coords_count = static_cast<u32>(coords.size());
if (process_mode != TextureProcessMode::None && gl_lod_supported) { if (process_mode != TextureProcessMode::None && gl_lod_supported) {
if (process_mode == TextureProcessMode::LZ) { if (process_mode == TextureProcessMode::LZ) {
coords.push_back(Immediate(0.0f)); extras.push_back(Immediate(0.0f));
} else { } else {
// If present, lod or bias are always stored in the register indexed by the gpr20 // If present, lod or bias are always stored in the register indexed by the gpr20
// field with an offset depending on the usage of the other registers // field with an offset depending on the usage of the other registers
coords.push_back(GetRegister(instr.gpr20.Value() + bias_offset)); extras.push_back(GetRegister(instr.gpr20.Value() + bias_offset));
} }
} }
Node4 values; Node4 values;
for (u32 element = 0; element < values.size(); ++element) { for (u32 element = 0; element < values.size(); ++element) {
auto params = coords; auto copy_coords = coords;
MetaTexture meta{sampler, element, coords_count, array_offset_value}; MetaTexture meta{sampler, array, depth_compare, extras, element};
values[element] = Operation(read_method, std::move(meta), std::move(params)); values[element] = Operation(read_method, meta, std::move(copy_coords));
} }
return values; return values;
@ -602,28 +596,22 @@ Node4 ShaderIR::GetTexCode(Instruction instr, TextureType texture_type,
for (std::size_t i = 0; i < coord_count; ++i) { for (std::size_t i = 0; i < coord_count; ++i) {
coords.push_back(GetRegister(coord_register + i)); coords.push_back(GetRegister(coord_register + i));
} }
// 1D.DC in opengl the 2nd component is ignored. // 1D.DC in OpenGL the 2nd component is ignored.
if (depth_compare && !is_array && texture_type == TextureType::Texture1D) { if (depth_compare && !is_array && texture_type == TextureType::Texture1D) {
coords.push_back(Immediate(0.0f)); coords.push_back(Immediate(0.0f));
} }
std::size_t array_offset{};
if (is_array) { const Node array = is_array ? GetRegister(array_register) : nullptr;
array_offset = coords.size();
coords.push_back(GetRegister(array_register)); Node dc{};
}
if (depth_compare) { if (depth_compare) {
// Depth is always stored in the register signaled by gpr20 // Depth is always stored in the register signaled by gpr20 or in the next register if lod
// or in the next register if lod or bias are used // or bias are used
const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
coords.push_back(GetRegister(depth_register)); dc = GetRegister(depth_register);
}
// Fill ignored coordinates
while (coords.size() < total_coord_count) {
coords.push_back(Immediate(0));
} }
return GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, array_offset, return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, 0);
0, std::move(coords));
} }
Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type,
@ -641,6 +629,7 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type,
(is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2)) (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2))
? static_cast<u64>(instr.gpr20.Value()) ? static_cast<u64>(instr.gpr20.Value())
: coord_register + 1; : coord_register + 1;
const u32 bias_offset = coord_count > 2 ? 1 : 0;
std::vector<Node> coords; std::vector<Node> coords;
for (std::size_t i = 0; i < coord_count; ++i) { for (std::size_t i = 0; i < coord_count; ++i) {
@ -648,24 +637,17 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type,
coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); coords.push_back(GetRegister(last ? last_coord_register : coord_register + i));
} }
std::size_t array_offset{}; const Node array = is_array ? GetRegister(array_register) : nullptr;
if (is_array) {
array_offset = coords.size(); Node dc{};
coords.push_back(GetRegister(array_register));
}
if (depth_compare) { if (depth_compare) {
// Depth is always stored in the register signaled by gpr20 // Depth is always stored in the register signaled by gpr20 or in the next register if lod
// or in the next register if lod or bias are used // or bias are used
const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
coords.push_back(GetRegister(depth_register)); dc = GetRegister(depth_register);
}
// Fill ignored coordinates
while (coords.size() < total_coord_count) {
coords.push_back(Immediate(0));
} }
return GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, array_offset, return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, bias_offset);
(coord_count > 2 ? 1 : 0), std::move(coords));
} }
Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare,
@ -680,24 +662,16 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
const u64 coord_register = array_register + (is_array ? 1 : 0); const u64 coord_register = array_register + (is_array ? 1 : 0);
std::vector<Node> coords; std::vector<Node> coords;
for (size_t i = 0; i < coord_count; ++i)
for (size_t i = 0; i < coord_count; ++i) {
coords.push_back(GetRegister(coord_register + i)); coords.push_back(GetRegister(coord_register + i));
}
std::optional<u32> array_offset;
if (is_array) {
array_offset = static_cast<u32>(coords.size());
coords.push_back(GetRegister(array_register));
}
const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare);
Node4 values; Node4 values;
for (u32 element = 0; element < values.size(); ++element) { for (u32 element = 0; element < values.size(); ++element) {
auto params = coords; auto coords_copy = coords;
MetaTexture meta{sampler, element, static_cast<u32>(coords.size()), array_offset}; MetaTexture meta{sampler, GetRegister(array_register), {}, {}, element};
values[element] = values[element] = Operation(OperationCode::F4TextureGather, meta, std::move(coords_copy));
Operation(OperationCode::F4TextureGather, std::move(meta), std::move(params));
} }
return values; return values;
@ -705,7 +679,6 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) { Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) {
const std::size_t type_coord_count = GetCoordCount(texture_type); const std::size_t type_coord_count = GetCoordCount(texture_type);
const std::size_t total_coord_count = type_coord_count + (is_array ? 1 : 0);
const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL; const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL;
// If enabled arrays index is always stored in the gpr8 field // If enabled arrays index is always stored in the gpr8 field
@ -719,33 +692,22 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
: coord_register + 1; : coord_register + 1;
std::vector<Node> coords; std::vector<Node> coords;
for (std::size_t i = 0; i < type_coord_count; ++i) { for (std::size_t i = 0; i < type_coord_count; ++i) {
const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1); const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1);
coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); coords.push_back(GetRegister(last ? last_coord_register : coord_register + i));
} }
std::optional<u32> array_offset;
if (is_array) {
array_offset = static_cast<u32>(coords.size());
coords.push_back(GetRegister(array_register));
}
const auto coords_count = static_cast<u32>(coords.size());
if (lod_enabled) { const Node array = is_array ? GetRegister(array_register) : nullptr;
// When lod is used always is in grp20 // When lod is used always is in gpr20
coords.push_back(GetRegister(instr.gpr20)); const Node lod = lod_enabled ? GetRegister(instr.gpr20) : Immediate(0);
} else {
coords.push_back(Immediate(0));
}
const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false); const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false);
Node4 values; Node4 values;
for (u32 element = 0; element < values.size(); ++element) { for (u32 element = 0; element < values.size(); ++element) {
auto params = coords; auto coords_copy = coords;
MetaTexture meta{sampler, element, coords_count, array_offset}; MetaTexture meta{sampler, array, {}, {lod}, element};
values[element] = values[element] = Operation(OperationCode::F4TexelFetch, meta, std::move(coords_copy));
Operation(OperationCode::F4TexelFetch, std::move(meta), std::move(params));
} }
return values; return values;
} }

View file

@ -288,9 +288,10 @@ struct MetaHalfArithmetic {
struct MetaTexture { struct MetaTexture {
const Sampler& sampler; const Sampler& sampler;
Node array{};
Node depth_compare{};
std::vector<Node> extras;
u32 element{}; u32 element{};
u32 coords_count{};
std::optional<u32> array_index;
}; };
constexpr MetaArithmetic PRECISE = {true}; constexpr MetaArithmetic PRECISE = {true};
@ -754,9 +755,8 @@ private:
bool lod_bias_enabled, std::size_t max_coords, std::size_t max_inputs); bool lod_bias_enabled, std::size_t max_coords, std::size_t max_inputs);
Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type,
Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords,
bool is_array, std::size_t array_offset, std::size_t bias_offset, Node array, Node depth_compare, u32 bias_offset);
std::vector<Node>&& coords);
Node GetVideoOperand(Node op, bool is_chunk, bool is_signed, Tegra::Shader::VideoType type, Node GetVideoOperand(Node op, bool is_chunk, bool is_signed, Tegra::Shader::VideoType type,
u64 byte_height); u64 byte_height);