shader/texture: Defer sampler types

Some instructions don't specify the texture type when they are used
(e.g. TXQ), on these cases defer the sampler declaration until an
instruction using the same sampler defines it.
This commit is contained in:
ReinUsesLisp
2019-09-19 18:38:31 -03:00
parent aaec1562f8
commit 91a1a768e9
5 changed files with 78 additions and 51 deletions

View File

@@ -387,7 +387,7 @@ public:
entries.const_buffers.emplace_back(cbuf.second.GetMaxOffset(), cbuf.second.IsIndirect(),
cbuf.first);
}
for (const auto& sampler : ir.GetSamplers()) {
for (const auto& [offset, sampler] : ir.GetSamplers()) {
entries.samplers.emplace_back(sampler);
}
for (const auto& [offset, image] : ir.GetImages()) {
@@ -639,7 +639,7 @@ private:
void DeclareSamplers() {
const auto& samplers = ir.GetSamplers();
for (const auto& sampler : samplers) {
for (const auto& [offset, sampler] : samplers) {
const std::string name{GetSampler(sampler)};
const std::string description{"layout (binding = SAMPLER_BINDING_" +
std::to_string(sampler.GetIndex()) + ") uniform"};

View File

@@ -189,7 +189,7 @@ public:
const auto& [base, usage] = gmem_pair;
entries.global_buffers.emplace_back(base.cbuf_index, base.cbuf_offset);
}
for (const auto& sampler : ir.GetSamplers()) {
for (const auto& [offset, sampler] : ir.GetSamplers()) {
entries.samplers.emplace_back(sampler);
}
for (const auto& attribute : ir.GetInputAttributes()) {
@@ -397,7 +397,7 @@ private:
void DeclareSamplers() {
u32 binding = samplers_base_binding;
for (const auto& sampler : ir.GetSamplers()) {
for (const auto& [offset, sampler] : ir.GetSamplers()) {
const auto dim = GetSamplerDim(sampler);
const int depth = sampler.IsShadow() ? 1 : 0;
const int arrayed = sampler.IsArray() ? 1 : 0;

View File

@@ -141,7 +141,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
const Node component = Immediate(static_cast<u32>(instr.tld4s.component));
const auto& sampler =
GetSampler(instr.sampler, TextureType::Texture2D, false, depth_compare);
GetSampler(instr.sampler, false, TextureType::Texture2D, false, depth_compare);
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
@@ -161,14 +161,8 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
LOG_WARNING(HW_GPU, "TXQ.NODEP implementation is incomplete");
}
// TODO: The new commits on the texture refactor, change the way samplers work.
// Sadly, not all texture instructions specify the type of texture their sampler
// uses. This must be fixed at a later instance.
const auto& sampler =
is_bindless
? GetBindlessSampler(instr.gpr8, Tegra::Shader::TextureType::Texture2D, false,
false)
: GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false);
const auto& sampler = is_bindless ? GetBindlessSampler(instr.gpr8, false, {}, false, false)
: GetSampler(instr.sampler, false, {}, false, false);
u32 indexer = 0;
switch (instr.txq.query_type) {
@@ -207,9 +201,9 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
auto texture_type = instr.tmml.texture_type.Value();
const bool is_array = instr.tmml.array != 0;
const auto& sampler = is_bindless
? GetBindlessSampler(instr.gpr20, texture_type, is_array, false)
: GetSampler(instr.sampler, texture_type, is_array, false);
const auto& sampler =
is_bindless ? GetBindlessSampler(instr.gpr20, true, texture_type, is_array, false)
: GetSampler(instr.sampler, true, texture_type, is_array, false);
std::vector<Node> coords;
@@ -285,48 +279,70 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
return pc;
}
const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, TextureType type,
bool is_array, bool is_shadow) {
const Sampler& ShaderIR::GetSampler(Tegra::Shader::Sampler sampler, bool is_type_known,
TextureType type, bool is_array, bool is_shadow) {
const auto offset = static_cast<std::size_t>(sampler.index.Value());
// If this sampler has already been used, return the existing mapping.
const auto itr =
std::find_if(used_samplers.begin(), used_samplers.end(),
[&](const Sampler& entry) { return entry.GetOffset() == offset; });
if (itr != used_samplers.end()) {
ASSERT(itr->GetType() == type && itr->IsArray() == is_array &&
itr->IsShadow() == is_shadow);
return *itr;
if (const auto sampler =
InspectExistingSampler(offset, is_type_known, type, is_array, is_shadow)) {
return *sampler;
}
// Otherwise create a new mapping for this sampler
if (is_type_known) {
samplers_with_known_type.insert(offset);
}
const std::size_t next_index = used_samplers.size();
const Sampler entry{offset, next_index, type, is_array, is_shadow};
return *used_samplers.emplace(entry).first;
const Sampler entry(offset, next_index, type, is_array, is_shadow);
return used_samplers.emplace(std::make_pair(offset, entry)).first->second;
}
const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, TextureType type,
bool is_array, bool is_shadow) {
const Sampler& ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, bool is_type_known,
TextureType type, bool is_array, bool is_shadow) {
const Node sampler_register = GetRegister(reg);
const auto [base_sampler, cbuf_index, cbuf_offset] =
TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size()));
ASSERT(base_sampler != nullptr);
const auto cbuf_key = (static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset);
// If this sampler has already been used, return the existing mapping.
const auto itr =
std::find_if(used_samplers.begin(), used_samplers.end(),
[&](const Sampler& entry) { return entry.GetOffset() == cbuf_key; });
if (itr != used_samplers.end()) {
ASSERT(itr->GetType() == type && itr->IsArray() == is_array &&
itr->IsShadow() == is_shadow);
return *itr;
if (const auto sampler =
InspectExistingSampler(cbuf_key, is_type_known, type, is_array, is_shadow)) {
return *sampler;
}
// Otherwise create a new mapping for this sampler
if (is_type_known) {
samplers_with_known_type.insert(cbuf_key);
}
const std::size_t next_index = used_samplers.size();
const Sampler entry{cbuf_index, cbuf_offset, next_index, type, is_array, is_shadow};
return *used_samplers.emplace(entry).first;
const Sampler entry(cbuf_index, cbuf_offset, next_index, type, is_array, is_shadow);
return used_samplers.emplace(std::make_pair(cbuf_key, entry)).first->second;
}
const Sampler* ShaderIR::InspectExistingSampler(std::size_t offset, bool is_type_known,
Tegra::Shader::TextureType type, bool is_array,
bool is_shadow) {
// If this sampler has already been used, inspect the existing mapping.
const auto it = used_samplers.find(offset);
if (it == used_samplers.end()) {
return nullptr;
}
auto& sampler = it->second;
if (samplers_with_known_type.find(offset) != samplers_with_known_type.end()) {
// Type is known in stored sampler
if (is_type_known) {
// Only check for sanity when we know the type in the current invocation.
ASSERT(sampler.GetType() == type && sampler.IsArray() == is_array &&
sampler.IsShadow() == is_shadow);
}
return &sampler;
}
if (!is_type_known) {
// Type is not known in stored sampler and we don't know it now either
return &sampler;
}
// Type is not known in the stored sampler and we know it now.
sampler.SetType(type, is_array, is_shadow);
return nullptr;
}
void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) {
@@ -411,9 +427,9 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
(texture_type == TextureType::TextureCube && is_array && is_shadow),
"This method is not supported.");
const auto& sampler = is_bindless
? GetBindlessSampler(*bindless_reg, texture_type, is_array, is_shadow)
: GetSampler(instr.sampler, texture_type, is_array, is_shadow);
const auto& sampler =
is_bindless ? GetBindlessSampler(*bindless_reg, true, texture_type, is_array, is_shadow)
: GetSampler(instr.sampler, true, texture_type, is_array, is_shadow);
const bool lod_needed = process_mode == TextureProcessMode::LZ ||
process_mode == TextureProcessMode::LL ||
@@ -577,7 +593,7 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
dc = GetRegister(parameter_register++);
}
const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare);
const auto& sampler = GetSampler(instr.sampler, true, texture_type, is_array, depth_compare);
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
@@ -610,7 +626,7 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
// const Node aoffi_register{is_aoffi ? GetRegister(gpr20_cursor++) : nullptr};
// const Node multisample{is_multisample ? GetRegister(gpr20_cursor++) : nullptr};
const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false);
const auto& sampler = GetSampler(instr.sampler, true, texture_type, is_array, false);
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
@@ -646,7 +662,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
// When lod is used always is in gpr20
const Node lod = lod_enabled ? GetRegister(instr.gpr20) : Immediate(0);
const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false);
const auto& sampler = GetSampler(instr.sampler, true, texture_type, is_array, false);
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {

View File

@@ -247,6 +247,12 @@ public:
: offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow},
is_bindless{is_bindless} {}
void SetType(Tegra::Shader::TextureType type_, bool is_array_, bool is_shadow_) {
type = type_;
is_array = is_array_;
is_shadow = is_shadow_;
}
std::size_t GetOffset() const {
return offset;
}

View File

@@ -91,7 +91,7 @@ public:
return used_cbufs;
}
const std::set<Sampler>& GetSamplers() const {
const std::map<u64, Sampler>& GetSamplers() const {
return used_samplers;
}
@@ -275,14 +275,18 @@ private:
Node GetConditionCode(Tegra::Shader::ConditionCode cc);
/// Accesses a texture sampler
const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler,
const Sampler& GetSampler(Tegra::Shader::Sampler sampler, bool is_type_known,
Tegra::Shader::TextureType type, bool is_array, bool is_shadow);
// Accesses a texture sampler for a bindless texture.
const Sampler& GetBindlessSampler(const Tegra::Shader::Register& reg,
const Sampler& GetBindlessSampler(Tegra::Shader::Register reg, bool is_type_known,
Tegra::Shader::TextureType type, bool is_array,
bool is_shadow);
const Sampler* InspectExistingSampler(std::size_t offset, bool is_type_known,
Tegra::Shader::TextureType type, bool is_array,
bool is_shadow);
/// Accesses an image.
Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type,
std::optional<Tegra::Shader::ImageAtomicSize> size = {});
@@ -373,7 +377,8 @@ private:
std::set<Tegra::Shader::Attribute::Index> used_input_attributes;
std::set<Tegra::Shader::Attribute::Index> used_output_attributes;
std::map<u32, ConstBuffer> used_cbufs;
std::set<Sampler> used_samplers;
std::map<u64, Sampler> used_samplers;
std::set<u64> samplers_with_known_type;
std::map<u64, Image> used_images;
std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{};
std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;