mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-15 22:54:00 +00:00
shader/texture: Deduce texture buffers from locker
Instead of specializing shaders to separate texture buffers from 1D textures, use the locker to deduce them while they are being decoded.
This commit is contained in:
parent
c52f37f259
commit
32c1bc6a67
9 changed files with 109 additions and 176 deletions
|
@ -271,9 +271,9 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
|||
const auto stage = static_cast<Maxwell::ShaderStage>(index == 0 ? 0 : index - 1);
|
||||
SetupDrawConstBuffers(stage, shader);
|
||||
SetupDrawGlobalMemory(stage, shader);
|
||||
const auto texture_buffer_usage{SetupDrawTextures(stage, shader, base_bindings)};
|
||||
SetupDrawTextures(stage, shader, base_bindings);
|
||||
|
||||
const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage};
|
||||
const ProgramVariant variant{base_bindings, primitive_mode};
|
||||
const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant);
|
||||
|
||||
switch (program) {
|
||||
|
@ -303,7 +303,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
|||
// When VertexA is enabled, we have dual vertex shaders
|
||||
if (program == Maxwell::ShaderProgram::VertexA) {
|
||||
// VertexB was combined with VertexA, so we skip the VertexB iteration
|
||||
index++;
|
||||
++index;
|
||||
}
|
||||
|
||||
base_bindings = next_bindings;
|
||||
|
@ -732,11 +732,10 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
|
|||
}
|
||||
|
||||
auto kernel = shader_cache.GetComputeKernel(code_addr);
|
||||
ProgramVariant variant;
|
||||
variant.texture_buffer_usage = SetupComputeTextures(kernel);
|
||||
SetupComputeTextures(kernel);
|
||||
SetupComputeImages(kernel);
|
||||
|
||||
const auto [program, next_bindings] = kernel->GetProgramHandle(variant);
|
||||
const auto [program, next_bindings] = kernel->GetProgramHandle({});
|
||||
state.draw.shader_program = program;
|
||||
state.draw.program_pipeline = 0;
|
||||
|
||||
|
@ -918,8 +917,7 @@ void RasterizerOpenGL::SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entr
|
|||
bind_ssbo_pushbuffer.Push(ssbo, buffer_offset, static_cast<GLsizeiptr>(size));
|
||||
}
|
||||
|
||||
TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage,
|
||||
const Shader& shader,
|
||||
void RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage, const Shader& shader,
|
||||
BaseBindings base_bindings) {
|
||||
MICROPROFILE_SCOPE(OpenGL_Texture);
|
||||
const auto& gpu = system.GPU();
|
||||
|
@ -929,8 +927,6 @@ TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stag
|
|||
ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.textures),
|
||||
"Exceeded the number of active textures.");
|
||||
|
||||
TextureBufferUsage texture_buffer_usage{0};
|
||||
|
||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||
const auto& entry = entries[bindpoint];
|
||||
const auto texture = [&] {
|
||||
|
@ -943,15 +939,11 @@ TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stag
|
|||
return maxwell3d.GetTextureInfo(tex_handle);
|
||||
}();
|
||||
|
||||
if (SetupTexture(base_bindings.sampler + bindpoint, texture, entry)) {
|
||||
texture_buffer_usage.set(bindpoint);
|
||||
SetupTexture(base_bindings.sampler + bindpoint, texture, entry);
|
||||
}
|
||||
}
|
||||
|
||||
return texture_buffer_usage;
|
||||
}
|
||||
|
||||
TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) {
|
||||
void RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) {
|
||||
MICROPROFILE_SCOPE(OpenGL_Texture);
|
||||
const auto& compute = system.GPU().KeplerCompute();
|
||||
const auto& entries = kernel->GetShaderEntries().samplers;
|
||||
|
@ -959,8 +951,6 @@ TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel)
|
|||
ASSERT_MSG(entries.size() <= std::size(state.textures),
|
||||
"Exceeded the number of active textures.");
|
||||
|
||||
TextureBufferUsage texture_buffer_usage{0};
|
||||
|
||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||
const auto& entry = entries[bindpoint];
|
||||
const auto texture = [&] {
|
||||
|
@ -972,34 +962,29 @@ TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel)
|
|||
return compute.GetTextureInfo(tex_handle);
|
||||
}();
|
||||
|
||||
if (SetupTexture(bindpoint, texture, entry)) {
|
||||
texture_buffer_usage.set(bindpoint);
|
||||
SetupTexture(bindpoint, texture, entry);
|
||||
}
|
||||
}
|
||||
|
||||
return texture_buffer_usage;
|
||||
}
|
||||
|
||||
bool RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
|
||||
void RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
|
||||
const GLShader::SamplerEntry& entry) {
|
||||
state.samplers[binding] = sampler_cache.GetSampler(texture.tsc);
|
||||
|
||||
const auto view = texture_cache.GetTextureSurface(texture.tic, entry);
|
||||
if (!view) {
|
||||
// Can occur when texture addr is null or its memory is unmapped/invalid
|
||||
state.samplers[binding] = 0;
|
||||
state.textures[binding] = 0;
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
state.textures[binding] = view->GetTexture();
|
||||
|
||||
if (view->GetSurfaceParams().IsBuffer()) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
state.samplers[binding] = sampler_cache.GetSampler(texture.tsc);
|
||||
|
||||
// Apply swizzle to textures that are not buffers.
|
||||
view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
|
||||
texture.tic.w_source);
|
||||
return false;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
|
||||
|
|
|
@ -107,16 +107,15 @@ private:
|
|||
/// Syncs all the state, shaders, render targets and textures setting before a draw call.
|
||||
void DrawPrelude();
|
||||
|
||||
/// Configures the current textures to use for the draw command. Returns shaders texture buffer
|
||||
/// usage.
|
||||
TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
||||
const Shader& shader, BaseBindings base_bindings);
|
||||
/// Configures the current textures to use for the draw command.
|
||||
void SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, const Shader& shader,
|
||||
BaseBindings base_bindings);
|
||||
|
||||
/// Configures the textures used in a compute shader. Returns texture buffer usage.
|
||||
TextureBufferUsage SetupComputeTextures(const Shader& kernel);
|
||||
/// Configures the textures used in a compute shader.
|
||||
void SetupComputeTextures(const Shader& kernel);
|
||||
|
||||
/// Configures a texture. Returns true when the texture is a texture buffer.
|
||||
bool SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
|
||||
/// Configures a texture.
|
||||
void SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
|
||||
const GLShader::SamplerEntry& entry);
|
||||
|
||||
/// Configures images in a compute shader.
|
||||
|
|
|
@ -270,7 +270,6 @@ CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramTy
|
|||
|
||||
auto base_bindings{variant.base_bindings};
|
||||
const auto primitive_mode{variant.primitive_mode};
|
||||
const auto texture_buffer_usage{variant.texture_buffer_usage};
|
||||
|
||||
std::string source = fmt::format(R"(// {}
|
||||
#version 430 core
|
||||
|
@ -317,17 +316,6 @@ CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramTy
|
|||
fmt::format("#define IMAGE_BINDING_{} {}\n", image.GetIndex(), base_bindings.image++);
|
||||
}
|
||||
|
||||
// Transform 1D textures to texture samplers by declaring its preprocessor macros.
|
||||
for (std::size_t i = 0; i < texture_buffer_usage.size(); ++i) {
|
||||
if (!texture_buffer_usage.test(i)) {
|
||||
continue;
|
||||
}
|
||||
source += fmt::format("#define SAMPLER_{}_IS_BUFFER\n", i);
|
||||
}
|
||||
if (texture_buffer_usage.any()) {
|
||||
source += '\n';
|
||||
}
|
||||
|
||||
if (program_type == ProgramType::Geometry) {
|
||||
const auto [glsl_topology, debug_name, max_vertices] =
|
||||
GetPrimitiveDescription(primitive_mode);
|
||||
|
|
|
@ -658,9 +658,11 @@ private:
|
|||
const std::string description{"layout (binding = SAMPLER_BINDING_" +
|
||||
std::to_string(sampler.GetIndex()) + ") uniform"};
|
||||
std::string sampler_type = [&]() {
|
||||
if (sampler.IsBuffer()) {
|
||||
return "samplerBuffer";
|
||||
}
|
||||
switch (sampler.GetType()) {
|
||||
case Tegra::Shader::TextureType::Texture1D:
|
||||
// Special cased, read below.
|
||||
return "sampler1D";
|
||||
case Tegra::Shader::TextureType::Texture2D:
|
||||
return "sampler2D";
|
||||
|
@ -680,19 +682,7 @@ private:
|
|||
sampler_type += "Shadow";
|
||||
}
|
||||
|
||||
if (sampler.GetType() == Tegra::Shader::TextureType::Texture1D) {
|
||||
// 1D textures can be aliased to texture buffers, hide the declarations behind a
|
||||
// preprocessor flag and use one or the other from the GPU state. This has to be
|
||||
// done because shaders don't have enough information to determine the texture type.
|
||||
EmitIfdefIsBuffer(sampler);
|
||||
code.AddLine("{} samplerBuffer {};", description, name);
|
||||
code.AddLine("#else");
|
||||
code.AddLine("{} {} {};", description, sampler_type, name);
|
||||
code.AddLine("#endif");
|
||||
} else {
|
||||
// The other texture types (2D, 3D and cubes) don't have this issue.
|
||||
code.AddLine("{} {} {};", description, sampler_type, name);
|
||||
}
|
||||
}
|
||||
if (!samplers.empty()) {
|
||||
code.AddNewLine();
|
||||
|
@ -1749,27 +1739,14 @@ private:
|
|||
expr += ", ";
|
||||
}
|
||||
|
||||
// Store a copy of the expression without the lod to be used with texture buffers
|
||||
std::string expr_buffer = expr;
|
||||
|
||||
if (meta->lod) {
|
||||
if (meta->lod && !meta->sampler.IsBuffer()) {
|
||||
expr += ", ";
|
||||
expr += Visit(meta->lod).AsInt();
|
||||
}
|
||||
expr += ')';
|
||||
expr += GetSwizzle(meta->element);
|
||||
|
||||
expr_buffer += ')';
|
||||
expr_buffer += GetSwizzle(meta->element);
|
||||
|
||||
const std::string tmp{code.GenerateTemporary()};
|
||||
EmitIfdefIsBuffer(meta->sampler);
|
||||
code.AddLine("float {} = {};", tmp, expr_buffer);
|
||||
code.AddLine("#else");
|
||||
code.AddLine("float {} = {};", tmp, expr);
|
||||
code.AddLine("#endif");
|
||||
|
||||
return {tmp, Type::Float};
|
||||
return {std::move(expr), Type::Float};
|
||||
}
|
||||
|
||||
Expression ImageLoad(Operation operation) {
|
||||
|
@ -2214,10 +2191,6 @@ private:
|
|||
return GetDeclarationWithSuffix(static_cast<u32>(image.GetIndex()), "image");
|
||||
}
|
||||
|
||||
void EmitIfdefIsBuffer(const Sampler& sampler) {
|
||||
code.AddLine("#ifdef SAMPLER_{}_IS_BUFFER", sampler.GetIndex());
|
||||
}
|
||||
|
||||
std::string GetDeclarationWithSuffix(u32 index, std::string_view name) const {
|
||||
return fmt::format("{}_{}_{}", name, index, suffix);
|
||||
}
|
||||
|
|
|
@ -28,23 +28,6 @@ using VideoCommon::Shader::KeyMap;
|
|||
|
||||
namespace {
|
||||
|
||||
struct ConstBufferKey {
|
||||
u32 cbuf;
|
||||
u32 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct BoundSamplerKey {
|
||||
u32 offset;
|
||||
Tegra::Engines::SamplerDescriptor sampler;
|
||||
};
|
||||
|
||||
struct BindlessSamplerKey {
|
||||
u32 cbuf;
|
||||
u32 offset;
|
||||
Tegra::Engines::SamplerDescriptor sampler;
|
||||
};
|
||||
|
||||
using ShaderCacheVersionHash = std::array<u8, 64>;
|
||||
|
||||
enum class TransferableEntryKind : u32 {
|
||||
|
@ -52,10 +35,28 @@ enum class TransferableEntryKind : u32 {
|
|||
Usage,
|
||||
};
|
||||
|
||||
constexpr u32 NativeVersion = 5;
|
||||
struct ConstBufferKey {
|
||||
u32 cbuf{};
|
||||
u32 offset{};
|
||||
u32 value{};
|
||||
};
|
||||
|
||||
struct BoundSamplerKey {
|
||||
u32 offset{};
|
||||
Tegra::Engines::SamplerDescriptor sampler{};
|
||||
};
|
||||
|
||||
struct BindlessSamplerKey {
|
||||
u32 cbuf{};
|
||||
u32 offset{};
|
||||
Tegra::Engines::SamplerDescriptor sampler{};
|
||||
};
|
||||
|
||||
constexpr u32 NativeVersion = 6;
|
||||
|
||||
// Making sure sizes doesn't change by accident
|
||||
static_assert(sizeof(BaseBindings) == 16);
|
||||
static_assert(sizeof(ProgramVariant) == 20);
|
||||
|
||||
ShaderCacheVersionHash GetShaderCacheVersionHash() {
|
||||
ShaderCacheVersionHash hash{};
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
@ -37,7 +36,6 @@ struct ShaderDiskCacheDump;
|
|||
|
||||
using ProgramCode = std::vector<u64>;
|
||||
using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>;
|
||||
using TextureBufferUsage = std::bitset<64>;
|
||||
|
||||
/// Allocated bindings used by an OpenGL shader program
|
||||
struct BaseBindings {
|
||||
|
@ -61,11 +59,10 @@ static_assert(std::is_trivially_copyable_v<BaseBindings>);
|
|||
struct ProgramVariant {
|
||||
BaseBindings base_bindings;
|
||||
GLenum primitive_mode{};
|
||||
TextureBufferUsage texture_buffer_usage{};
|
||||
|
||||
bool operator==(const ProgramVariant& rhs) const {
|
||||
return std::tie(base_bindings, primitive_mode, texture_buffer_usage) ==
|
||||
std::tie(rhs.base_bindings, rhs.primitive_mode, rhs.texture_buffer_usage);
|
||||
return std::tie(base_bindings, primitive_mode) ==
|
||||
std::tie(rhs.base_bindings, rhs.primitive_mode);
|
||||
}
|
||||
|
||||
bool operator!=(const ProgramVariant& rhs) const {
|
||||
|
@ -112,7 +109,6 @@ template <>
|
|||
struct hash<OpenGL::ProgramVariant> {
|
||||
std::size_t operator()(const OpenGL::ProgramVariant& variant) const noexcept {
|
||||
return std::hash<OpenGL::BaseBindings>()(variant.base_bindings) ^
|
||||
std::hash<OpenGL::TextureBufferUsage>()(variant.texture_buffer_usage) ^
|
||||
(static_cast<std::size_t>(variant.primitive_mode) << 6);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -128,8 +128,8 @@ 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}});
|
||||
const SamplerInfo info{TextureType::Texture2D, false, depth_compare};
|
||||
const auto& sampler = GetSampler(instr.sampler, info);
|
||||
|
||||
Node4 values;
|
||||
for (u32 element = 0; element < values.size(); ++element) {
|
||||
|
@ -149,7 +149,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
|
|||
// 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, {}) : GetSampler(instr.sampler, {});
|
||||
is_bindless ? GetBindlessSampler(instr.gpr8) : GetSampler(instr.sampler);
|
||||
|
||||
u32 indexer = 0;
|
||||
switch (instr.txq.query_type) {
|
||||
|
@ -185,8 +185,7 @@ 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}});
|
||||
is_bindless ? GetBindlessSampler(instr.gpr20) : GetSampler(instr.sampler);
|
||||
|
||||
std::vector<Node> coords;
|
||||
|
||||
|
@ -254,67 +253,50 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
|
|||
return pc;
|
||||
}
|
||||
|
||||
ShaderIR::SamplerInfo ShaderIR::GetSamplerInfo(std::optional<SamplerInfo> sampler_info, u32 offset,
|
||||
std::optional<u32> buffer) {
|
||||
if (sampler_info) {
|
||||
return *sampler_info;
|
||||
}
|
||||
const auto sampler =
|
||||
buffer ? locker.ObtainBindlessSampler(*buffer, offset) : locker.ObtainBoundSampler(offset);
|
||||
if (!sampler) {
|
||||
LOG_WARNING(HW_GPU, "Unknown sampler info");
|
||||
return SamplerInfo{TextureType::Texture2D, false, false, false};
|
||||
}
|
||||
return SamplerInfo{sampler->texture_type, sampler->is_array != 0, sampler->is_shadow != 0,
|
||||
sampler->is_buffer != 0};
|
||||
}
|
||||
|
||||
const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
|
||||
std::optional<SamplerInfo> sampler_info) {
|
||||
const auto offset = static_cast<u32>(sampler.index.Value());
|
||||
|
||||
TextureType type;
|
||||
bool is_array;
|
||||
bool is_shadow;
|
||||
if (sampler_info) {
|
||||
type = sampler_info->type;
|
||||
is_array = sampler_info->is_array;
|
||||
is_shadow = sampler_info->is_shadow;
|
||||
} else if (const auto sampler = locker.ObtainBoundSampler(offset)) {
|
||||
type = sampler->texture_type.Value();
|
||||
is_array = sampler->is_array.Value() != 0;
|
||||
is_shadow = sampler->is_shadow.Value() != 0;
|
||||
} else {
|
||||
LOG_WARNING(HW_GPU, "Unknown sampler info");
|
||||
type = TextureType::Texture2D;
|
||||
is_array = false;
|
||||
is_shadow = false;
|
||||
}
|
||||
const auto info = GetSamplerInfo(sampler_info, offset);
|
||||
|
||||
// If this sampler has already been used, return the existing mapping.
|
||||
const auto it =
|
||||
std::find_if(used_samplers.begin(), used_samplers.end(),
|
||||
[offset](const Sampler& entry) { return entry.GetOffset() == offset; });
|
||||
if (it != used_samplers.end()) {
|
||||
ASSERT(!it->IsBindless() && it->GetType() == type && it->IsArray() == is_array &&
|
||||
it->IsShadow() == is_shadow);
|
||||
ASSERT(!it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array &&
|
||||
it->IsShadow() == info.is_shadow && it->IsBuffer() == info.is_buffer);
|
||||
return *it;
|
||||
}
|
||||
|
||||
// Otherwise create a new mapping for this sampler
|
||||
const auto next_index = static_cast<u32>(used_samplers.size());
|
||||
return used_samplers.emplace_back(Sampler(next_index, offset, type, is_array, is_shadow));
|
||||
return used_samplers.emplace_back(next_index, offset, info.type, info.is_array, info.is_shadow,
|
||||
info.is_buffer);
|
||||
}
|
||||
|
||||
const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
|
||||
const Sampler& ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg,
|
||||
std::optional<SamplerInfo> sampler_info) {
|
||||
const Node sampler_register = GetRegister(reg);
|
||||
const auto [base_sampler, buffer, offset] =
|
||||
TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size()));
|
||||
ASSERT(base_sampler != nullptr);
|
||||
|
||||
TextureType type;
|
||||
bool is_array;
|
||||
bool is_shadow;
|
||||
if (sampler_info) {
|
||||
type = sampler_info->type;
|
||||
is_array = sampler_info->is_array;
|
||||
is_shadow = sampler_info->is_shadow;
|
||||
} else if (const auto sampler = locker.ObtainBindlessSampler(buffer, offset)) {
|
||||
type = sampler->texture_type.Value();
|
||||
is_array = sampler->is_array.Value() != 0;
|
||||
is_shadow = sampler->is_shadow.Value() != 0;
|
||||
} else {
|
||||
LOG_WARNING(HW_GPU, "Unknown sampler info");
|
||||
type = TextureType::Texture2D;
|
||||
is_array = false;
|
||||
is_shadow = false;
|
||||
}
|
||||
const auto info = GetSamplerInfo(sampler_info, offset, buffer);
|
||||
|
||||
// If this sampler has already been used, return the existing mapping.
|
||||
const auto it =
|
||||
|
@ -323,15 +305,15 @@ const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
|
|||
return entry.GetBuffer() == buffer && entry.GetOffset() == offset;
|
||||
});
|
||||
if (it != used_samplers.end()) {
|
||||
ASSERT(it->IsBindless() && it->GetType() == type && it->IsArray() == is_array &&
|
||||
it->IsShadow() == is_shadow);
|
||||
ASSERT(it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array &&
|
||||
it->IsShadow() == info.is_shadow);
|
||||
return *it;
|
||||
}
|
||||
|
||||
// Otherwise create a new mapping for this sampler
|
||||
const auto next_index = static_cast<u32>(used_samplers.size());
|
||||
return used_samplers.emplace_back(
|
||||
Sampler(next_index, offset, buffer, type, is_array, is_shadow));
|
||||
return used_samplers.emplace_back(next_index, offset, buffer, info.type, info.is_array,
|
||||
info.is_shadow, info.is_buffer);
|
||||
}
|
||||
|
||||
void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) {
|
||||
|
@ -416,17 +398,16 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
|
|||
(texture_type == TextureType::TextureCube && is_array && is_shadow),
|
||||
"This method is not supported.");
|
||||
|
||||
const SamplerInfo info{texture_type, is_array, is_shadow, false};
|
||||
const auto& sampler =
|
||||
is_bindless ? GetBindlessSampler(*bindless_reg, {{texture_type, is_array, is_shadow}})
|
||||
: GetSampler(instr.sampler, {{texture_type, is_array, is_shadow}});
|
||||
is_bindless ? GetBindlessSampler(*bindless_reg, info) : GetSampler(instr.sampler, info);
|
||||
|
||||
const bool lod_needed = process_mode == TextureProcessMode::LZ ||
|
||||
process_mode == TextureProcessMode::LL ||
|
||||
process_mode == TextureProcessMode::LLA;
|
||||
|
||||
// LOD selection (either via bias or explicit textureLod) not
|
||||
// supported in GL for sampler2DArrayShadow and
|
||||
// samplerCubeArrayShadow.
|
||||
// LOD selection (either via bias or explicit textureLod) not supported in GL for
|
||||
// sampler2DArrayShadow and samplerCubeArrayShadow.
|
||||
const bool gl_lod_supported =
|
||||
!((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && is_shadow) ||
|
||||
(texture_type == Tegra::Shader::TextureType::TextureCube && is_array && is_shadow));
|
||||
|
@ -436,8 +417,8 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
|
|||
|
||||
UNIMPLEMENTED_IF(process_mode != TextureProcessMode::None && !gl_lod_supported);
|
||||
|
||||
Node bias = {};
|
||||
Node lod = {};
|
||||
Node bias;
|
||||
Node lod;
|
||||
if (process_mode != TextureProcessMode::None && gl_lod_supported) {
|
||||
switch (process_mode) {
|
||||
case TextureProcessMode::LZ:
|
||||
|
@ -573,10 +554,9 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
|
|||
|
||||
u64 parameter_register = instr.gpr20.Value();
|
||||
|
||||
const auto& sampler =
|
||||
is_bindless
|
||||
? GetBindlessSampler(parameter_register++, {{texture_type, is_array, depth_compare}})
|
||||
: GetSampler(instr.sampler, {{texture_type, is_array, depth_compare}});
|
||||
const SamplerInfo info{texture_type, is_array, depth_compare, false};
|
||||
const auto& sampler = is_bindless ? GetBindlessSampler(parameter_register++, info)
|
||||
: GetSampler(instr.sampler, info);
|
||||
|
||||
std::vector<Node> aoffi;
|
||||
if (is_aoffi) {
|
||||
|
@ -623,7 +603,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);
|
||||
|
||||
Node4 values;
|
||||
for (u32 element = 0; element < values.size(); ++element) {
|
||||
|
@ -659,7 +639,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);
|
||||
|
||||
Node4 values;
|
||||
for (u32 element = 0; element < values.size(); ++element) {
|
||||
|
|
|
@ -225,14 +225,15 @@ class Sampler {
|
|||
public:
|
||||
/// This constructor is for bound samplers
|
||||
constexpr explicit Sampler(u32 index, u32 offset, Tegra::Shader::TextureType type,
|
||||
bool is_array, bool is_shadow)
|
||||
: index{index}, offset{offset}, type{type}, is_array{is_array}, is_shadow{is_shadow} {}
|
||||
bool is_array, bool is_shadow, bool is_buffer)
|
||||
: index{index}, offset{offset}, type{type}, is_array{is_array}, is_shadow{is_shadow},
|
||||
is_buffer{is_buffer} {}
|
||||
|
||||
/// This constructor is for bindless samplers
|
||||
constexpr explicit Sampler(u32 index, u32 offset, u32 buffer, Tegra::Shader::TextureType type,
|
||||
bool is_array, bool is_shadow)
|
||||
bool is_array, bool is_shadow, bool is_buffer)
|
||||
: index{index}, offset{offset}, buffer{buffer}, type{type}, is_array{is_array},
|
||||
is_shadow{is_shadow}, is_bindless{true} {}
|
||||
is_shadow{is_shadow}, is_buffer{is_buffer}, is_bindless{true} {}
|
||||
|
||||
constexpr u32 GetIndex() const {
|
||||
return index;
|
||||
|
@ -258,6 +259,10 @@ public:
|
|||
return is_shadow;
|
||||
}
|
||||
|
||||
constexpr bool IsBuffer() const {
|
||||
return is_buffer;
|
||||
}
|
||||
|
||||
constexpr bool IsBindless() const {
|
||||
return is_bindless;
|
||||
}
|
||||
|
@ -270,6 +275,7 @@ private:
|
|||
Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc)
|
||||
bool is_array{}; ///< Whether the texture is being sampled as an array texture or not.
|
||||
bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not.
|
||||
bool is_buffer{}; ///< Whether the texture is a texture buffer without sampler.
|
||||
bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
|
||||
};
|
||||
|
||||
|
|
|
@ -179,6 +179,7 @@ private:
|
|||
Tegra::Shader::TextureType type;
|
||||
bool is_array;
|
||||
bool is_shadow;
|
||||
bool is_buffer;
|
||||
};
|
||||
|
||||
void Decode();
|
||||
|
@ -303,13 +304,17 @@ private:
|
|||
/// Returns a predicate combiner operation
|
||||
OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation);
|
||||
|
||||
/// Queries the missing sampler info from the execution context.
|
||||
SamplerInfo GetSamplerInfo(std::optional<SamplerInfo> sampler_info, u32 offset,
|
||||
std::optional<u32> buffer = std::nullopt);
|
||||
|
||||
/// Accesses a texture sampler
|
||||
const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler,
|
||||
std::optional<SamplerInfo> sampler_info);
|
||||
std::optional<SamplerInfo> sampler_info = std::nullopt);
|
||||
|
||||
// Accesses a texture sampler for a bindless texture.
|
||||
const Sampler& GetBindlessSampler(const Tegra::Shader::Register& reg,
|
||||
std::optional<SamplerInfo> sampler_info);
|
||||
/// Accesses a texture sampler for a bindless texture.
|
||||
const Sampler& GetBindlessSampler(Tegra::Shader::Register reg,
|
||||
std::optional<SamplerInfo> sampler_info = std::nullopt);
|
||||
|
||||
/// Accesses an image.
|
||||
Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
|
||||
|
|
Loading…
Reference in a new issue