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.pull/3098/head
parent
c52f37f259
commit
32c1bc6a67
|
|
@ -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 New Issue