summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/handle_table.cpp5
-rw-r--r--src/core/hle/kernel/handle_table.h1
-rw-r--r--src/core/hle/kernel/process.cpp4
-rw-r--r--src/core/hle/kernel/process.h9
-rw-r--r--src/core/hle/kernel/svc.cpp29
-rw-r--r--src/video_core/command_processor.cpp142
-rw-r--r--src/video_core/gpu.cpp6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp436
8 files changed, 220 insertions, 412 deletions
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 1bf79b692..c8acde5b1 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -42,9 +42,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
u16 generation = next_generation++;
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
- // CTR-OS doesn't use generation 0, so skip straight to 1.
- if (next_generation >= (1 << 15))
+ // Horizon OS uses zero to represent an invalid handle, so skip to 1.
+ if (next_generation >= (1 << 15)) {
next_generation = 1;
+ }
generations[slot] = generation;
objects[slot] = std::move(obj);
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index e3f3e3fb8..6b7927fd8 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -13,6 +13,7 @@
namespace Kernel {
enum KernelHandle : Handle {
+ InvalidHandle = 0,
CurrentThread = 0xFFFF8000,
CurrentProcess = 0xFFFF8001,
};
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 7ca538401..4ecb8c926 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -44,6 +44,10 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
return process;
}
+SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
+ return resource_limit;
+}
+
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
program_id = metadata.GetTitleID();
is_64bit_process = metadata.Is64BitProgram();
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index ada845c7f..49345aa66 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -171,14 +171,7 @@ public:
}
/// Gets the resource limit descriptor for this process
- ResourceLimit& GetResourceLimit() {
- return *resource_limit;
- }
-
- /// Gets the resource limit descriptor for this process
- const ResourceLimit& GetResourceLimit() const {
- return *resource_limit;
- }
+ SharedPtr<ResourceLimit> GetResourceLimit() const;
/// Gets the default CPU ID for this process
u8 GetDefaultProcessorID() const {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index d2d893992..812b32005 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -663,7 +663,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
TotalMemoryUsage = 6,
TotalHeapUsage = 7,
IsCurrentProcessBeingDebugged = 8,
- ResourceHandleLimit = 9,
+ RegisterResourceLimit = 9,
IdleTickCount = 10,
RandomEntropy = 11,
PerformanceCounter = 0xF0000002,
@@ -787,6 +787,33 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
*result = 0;
return RESULT_SUCCESS;
+ case GetInfoType::RegisterResourceLimit: {
+ if (handle != 0) {
+ return ERR_INVALID_HANDLE;
+ }
+
+ if (info_sub_id != 0) {
+ return ERR_INVALID_COMBINATION;
+ }
+
+ Process* const current_process = Core::CurrentProcess();
+ HandleTable& handle_table = current_process->GetHandleTable();
+ const auto resource_limit = current_process->GetResourceLimit();
+ if (!resource_limit) {
+ *result = KernelHandle::InvalidHandle;
+ // Yes, the kernel considers this a successful operation.
+ return RESULT_SUCCESS;
+ }
+
+ const auto table_result = handle_table.Create(resource_limit);
+ if (table_result.Failed()) {
+ return table_result.Code();
+ }
+
+ *result = *table_result;
+ return RESULT_SUCCESS;
+ }
+
case GetInfoType::RandomEntropy:
if (handle != 0) {
LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
deleted file mode 100644
index 8b9c548cc..000000000
--- a/src/video_core/command_processor.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2018 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <array>
-#include <cstddef>
-#include <memory>
-#include <utility>
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "common/microprofile.h"
-#include "common/vector_math.h"
-#include "core/memory.h"
-#include "core/tracer/recorder.h"
-#include "video_core/command_processor.h"
-#include "video_core/engines/fermi_2d.h"
-#include "video_core/engines/kepler_memory.h"
-#include "video_core/engines/maxwell_3d.h"
-#include "video_core/engines/maxwell_compute.h"
-#include "video_core/engines/maxwell_dma.h"
-#include "video_core/gpu.h"
-#include "video_core/renderer_base.h"
-#include "video_core/video_core.h"
-
-namespace Tegra {
-
-enum class BufferMethods {
- BindObject = 0,
- CountBufferMethods = 0x40,
-};
-
-MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
-
-void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
- MICROPROFILE_SCOPE(ProcessCommandLists);
-
- // On entering GPU code, assume all memory may be touched by the ARM core.
- maxwell_3d->dirty_flags.OnMemoryWrite();
-
- auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) {
- LOG_TRACE(HW_GPU,
- "Processing method {:08X} on subchannel {} value "
- "{:08X} remaining params {}",
- method, subchannel, value, remaining_params);
-
- ASSERT(subchannel < bound_engines.size());
-
- if (method == static_cast<u32>(BufferMethods::BindObject)) {
- // Bind the current subchannel to the desired engine id.
- LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
- bound_engines[subchannel] = static_cast<EngineID>(value);
- return;
- }
-
- if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
- // TODO(Subv): Research and implement these methods.
- LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
- return;
- }
-
- const EngineID engine = bound_engines[subchannel];
-
- switch (engine) {
- case EngineID::FERMI_TWOD_A:
- fermi_2d->WriteReg(method, value);
- break;
- case EngineID::MAXWELL_B:
- maxwell_3d->WriteReg(method, value, remaining_params);
- break;
- case EngineID::MAXWELL_COMPUTE_B:
- maxwell_compute->WriteReg(method, value);
- break;
- case EngineID::MAXWELL_DMA_COPY_A:
- maxwell_dma->WriteReg(method, value);
- break;
- case EngineID::KEPLER_INLINE_TO_MEMORY_B:
- kepler_memory->WriteReg(method, value);
- break;
- default:
- UNIMPLEMENTED_MSG("Unimplemented engine");
- }
- };
-
- for (auto entry : commands) {
- Tegra::GPUVAddr address = entry.Address();
- u32 size = entry.sz;
- const std::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address);
- VAddr current_addr = *head_address;
- while (current_addr < *head_address + size * sizeof(CommandHeader)) {
- const CommandHeader header = {Memory::Read32(current_addr)};
- current_addr += sizeof(u32);
-
- switch (header.mode.Value()) {
- case SubmissionMode::IncreasingOld:
- case SubmissionMode::Increasing: {
- // Increase the method value with each argument.
- for (unsigned i = 0; i < header.arg_count; ++i) {
- WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr),
- header.arg_count - i - 1);
- current_addr += sizeof(u32);
- }
- break;
- }
- case SubmissionMode::NonIncreasingOld:
- case SubmissionMode::NonIncreasing: {
- // Use the same method value for all arguments.
- for (unsigned i = 0; i < header.arg_count; ++i) {
- WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
- header.arg_count - i - 1);
- current_addr += sizeof(u32);
- }
- break;
- }
- case SubmissionMode::IncreaseOnce: {
- ASSERT(header.arg_count.Value() >= 1);
-
- // Use the original method for the first argument and then the next method for all
- // other arguments.
- WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
- header.arg_count - 1);
- current_addr += sizeof(u32);
-
- for (unsigned i = 1; i < header.arg_count; ++i) {
- WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr),
- header.arg_count - i - 1);
- current_addr += sizeof(u32);
- }
- break;
- }
- case SubmissionMode::Inline: {
- // The register value is stored in the bits 16-28 as an immediate
- WriteReg(header.method, header.subchannel, header.inline_data, 0);
- break;
- }
- default:
- UNIMPLEMENTED();
- }
- }
- }
-}
-
-} // namespace Tegra
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index fd1242333..88c45a423 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -141,6 +141,12 @@ void GPU::CallMethod(const MethodCall& method_call) {
return;
}
+ if (method_call.method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
+ // TODO(Subv): Research and implement these methods.
+ LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
+ return;
+ }
+
const EngineID engine = bound_engines[method_call.subchannel];
switch (engine) {
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index d235bfcd4..8d68156bf 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1515,6 +1515,161 @@ private:
}
}
+ std::pair<size_t, std::string> ValidateAndGetCoordinateElement(
+ const Tegra::Shader::TextureType texture_type, const bool depth_compare,
+ const bool is_array, const bool lod_bias_enabled, size_t max_coords, size_t max_inputs) {
+ const size_t coord_count = TextureCoordinates(texture_type);
+
+ size_t total_coord_count = coord_count + (is_array ? 1 : 0) + (depth_compare ? 1 : 0);
+ const size_t total_reg_count = total_coord_count + (lod_bias_enabled ? 1 : 0);
+ if (total_coord_count > max_coords || total_reg_count > max_inputs) {
+ UNIMPLEMENTED_MSG("Unsupported Texture operation");
+ total_coord_count = std::min(total_coord_count, max_coords);
+ }
+ // 1D.DC opengl is using a vec3 but 2nd component is ignored later.
+ total_coord_count +=
+ (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D)
+ ? 1
+ : 0;
+
+ constexpr std::array<const char*, 5> coord_container{
+ {"", "float coord = (", "vec2 coord = vec2(", "vec3 coord = vec3(",
+ "vec4 coord = vec4("}};
+
+ return std::pair<size_t, std::string>(coord_count, coord_container[total_coord_count]);
+ }
+
+ std::string GetTextureCode(const Tegra::Shader::Instruction& instr,
+ const Tegra::Shader::TextureType texture_type,
+ const Tegra::Shader::TextureProcessMode process_mode,
+ const bool depth_compare, const bool is_array,
+ const size_t bias_offset) {
+
+ if ((texture_type == Tegra::Shader::TextureType::Texture3D &&
+ (is_array || depth_compare)) ||
+ (texture_type == Tegra::Shader::TextureType::TextureCube && is_array &&
+ depth_compare)) {
+ UNIMPLEMENTED_MSG("This method is not supported.");
+ }
+
+ const std::string sampler =
+ GetSampler(instr.sampler, texture_type, is_array, depth_compare);
+
+ const bool lod_needed = process_mode == Tegra::Shader::TextureProcessMode::LZ ||
+ process_mode == Tegra::Shader::TextureProcessMode::LL ||
+ process_mode == Tegra::Shader::TextureProcessMode::LLA;
+
+ const bool gl_lod_supported = !(
+ (texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) ||
+ (texture_type == Tegra::Shader::TextureType::TextureCube && !is_array &&
+ depth_compare));
+
+ const std::string read_method = lod_needed && gl_lod_supported ? "textureLod(" : "texture(";
+ std::string texture = read_method + sampler + ", coord";
+
+ if (process_mode != Tegra::Shader::TextureProcessMode::None) {
+ if (process_mode == Tegra::Shader::TextureProcessMode::LZ) {
+ if (gl_lod_supported) {
+ texture += ", 0";
+ } else {
+ // Lod 0 is emulated by a big negative bias
+ // in scenarios that are not supported by glsl
+ texture += ", -1000";
+ }
+ } else {
+ // 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
+ texture += ',' + regs.GetRegisterAsFloat(instr.gpr20.Value() + bias_offset);
+ }
+ }
+ texture += ")";
+ return texture;
+ }
+
+ std::pair<std::string, std::string> GetTEXCode(
+ const Instruction& instr, const Tegra::Shader::TextureType texture_type,
+ const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
+ const bool is_array) {
+ const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
+ process_mode != Tegra::Shader::TextureProcessMode::LZ);
+
+ const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
+ texture_type, depth_compare, is_array, lod_bias_enabled, 4, 5);
+ // If enabled arrays index is always stored in the gpr8 field
+ const u64 array_register = instr.gpr8.Value();
+ // First coordinate index is the gpr8 or gpr8 + 1 when arrays are used
+ const u64 coord_register = array_register + (is_array ? 1 : 0);
+
+ std::string coord = coord_dcl;
+ for (size_t i = 0; i < coord_count;) {
+ coord += regs.GetRegisterAsFloat(coord_register + i);
+ ++i;
+ if (i != coord_count) {
+ coord += ',';
+ }
+ }
+ // 1D.DC in opengl the 2nd component is ignored.
+ if (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D) {
+ coord += ",0.0";
+ }
+ if (depth_compare) {
+ // Depth is always stored in the register signaled by gpr20
+ // or in the next register if lod or bias are used
+ const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
+ coord += ',' + regs.GetRegisterAsFloat(depth_register);
+ }
+ if (is_array) {
+ coord += ',' + regs.GetRegisterAsInteger(array_register);
+ }
+ coord += ");";
+ return std::make_pair(
+ coord, GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, 0));
+ }
+
+ std::pair<std::string, std::string> GetTEXSCode(
+ const Instruction& instr, const Tegra::Shader::TextureType texture_type,
+ const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
+ const bool is_array) {
+ const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
+ process_mode != Tegra::Shader::TextureProcessMode::LZ);
+
+ const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
+ texture_type, depth_compare, is_array, lod_bias_enabled, 4, 4);
+ // If enabled arrays index is always stored in the gpr8 field
+ const u64 array_register = instr.gpr8.Value();
+ // First coordinate index is stored in gpr8 field or (gpr8 + 1) when arrays are used
+ const u64 coord_register = array_register + (is_array ? 1 : 0);
+ const u64 last_coord_register =
+ (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2))
+ ? static_cast<u64>(instr.gpr20.Value())
+ : coord_register + 1;
+
+ std::string coord = coord_dcl;
+ for (size_t i = 0; i < coord_count; ++i) {
+ const bool last = (i == (coord_count - 1)) && (coord_count > 1);
+ coord += regs.GetRegisterAsFloat(last ? last_coord_register : coord_register + i);
+ if (!last) {
+ coord += ',';
+ }
+ }
+
+ if (depth_compare) {
+ // Depth is always stored in the register signaled by gpr20
+ // or in the next register if lod or bias are used
+ const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
+ coord += ',' + regs.GetRegisterAsFloat(depth_register);
+ }
+ if (is_array) {
+ coord += ',' + regs.GetRegisterAsInteger(array_register);
+ }
+ coord += ");";
+
+ return std::make_pair(coord,
+ GetTextureCode(instr, texture_type, process_mode, depth_compare,
+ is_array, (coord_count > 2 ? 1 : 0)));
+ }
+
/**
* Compiles a single instruction from Tegra to GLSL.
* @param offset the offset of the Tegra shader instruction.
@@ -2574,168 +2729,32 @@ private:
case OpCode::Id::TEX: {
Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
const bool is_array = instr.tex.array != 0;
-
+ const bool depth_compare =
+ instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
+ const auto process_mode = instr.tex.GetTextureProcessMode();
UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
"NODEP is not implemented");
UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
"AOFFI is not implemented");
- const bool depth_compare =
- instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
- u32 num_coordinates = TextureCoordinates(texture_type);
- u32 start_index = 0;
- std::string array_elem;
- if (is_array) {
- array_elem = regs.GetRegisterAsInteger(instr.gpr8);
- start_index = 1;
- }
- const auto process_mode = instr.tex.GetTextureProcessMode();
- u32 start_index_b = 0;
- std::string lod_value;
- if (process_mode != Tegra::Shader::TextureProcessMode::LZ &&
- process_mode != Tegra::Shader::TextureProcessMode::None) {
- start_index_b = 1;
- lod_value = regs.GetRegisterAsFloat(instr.gpr20);
- }
-
- std::string depth_value;
- if (depth_compare) {
- depth_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + start_index_b);
- }
-
- bool depth_compare_extra = false;
+ const auto [coord, texture] =
+ GetTEXCode(instr, texture_type, process_mode, depth_compare, is_array);
const auto scope = shader.Scope();
-
- switch (num_coordinates) {
- case 1: {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
- if (is_array) {
- if (depth_compare) {
- shader.AddLine("vec3 coords = vec3(" + x + ", " + depth_value + ", " +
- array_elem + ");");
- } else {
- shader.AddLine("vec2 coords = vec2(" + x + ", " + array_elem + ");");
- }
- } else {
- if (depth_compare) {
- shader.AddLine("vec2 coords = vec2(" + x + ", " + depth_value + ");");
- } else {
- shader.AddLine("float coords = " + x + ';');
- }
- }
- break;
- }
- case 2: {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
- if (is_array) {
- if (depth_compare) {
- shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " +
- depth_value + ", " + array_elem + ");");
- } else {
- shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " +
- array_elem + ");");
- }
- } else {
- if (depth_compare) {
- shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " +
- depth_value + ");");
- } else {
- shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
- }
- }
- break;
- }
- case 3: {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
- const std::string z =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2);
- if (is_array) {
- depth_compare_extra = depth_compare;
- shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
- array_elem + ");");
- } else {
- if (depth_compare) {
- shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
- depth_value + ");");
- } else {
- shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");");
- }
- }
- break;
- }
- default:
- UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
- static_cast<u32>(num_coordinates));
-
- // Fallback to interpreting as a 2D texture for now
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
- texture_type = Tegra::Shader::TextureType::Texture2D;
- }
-
- const std::string sampler =
- GetSampler(instr.sampler, texture_type, is_array, depth_compare);
- // Add an extra scope and declare the texture coords inside to prevent
- // overwriting them in case they are used as outputs of the texs instruction.
-
- const std::string texture = [&]() {
- switch (instr.tex.GetTextureProcessMode()) {
- case Tegra::Shader::TextureProcessMode::None:
- if (depth_compare_extra) {
- return "texture(" + sampler + ", coords, " + depth_value + ')';
- }
- return "texture(" + sampler + ", coords)";
- case Tegra::Shader::TextureProcessMode::LZ:
- if (depth_compare_extra) {
- return "texture(" + sampler + ", coords, " + depth_value + ')';
- }
- return "textureLod(" + sampler + ", coords, 0.0)";
- case Tegra::Shader::TextureProcessMode::LB:
- case Tegra::Shader::TextureProcessMode::LBA:
- // TODO: Figure if A suffix changes the equation at all.
- if (depth_compare_extra) {
- LOG_WARNING(
- HW_GPU,
- "OpenGL Limitation: can't set bias value along depth compare");
- return "texture(" + sampler + ", coords, " + depth_value + ')';
- }
- return "texture(" + sampler + ", coords, " + lod_value + ')';
- case Tegra::Shader::TextureProcessMode::LL:
- case Tegra::Shader::TextureProcessMode::LLA:
- // TODO: Figure if A suffix changes the equation at all.
- if (depth_compare_extra) {
- LOG_WARNING(
- HW_GPU,
- "OpenGL Limitation: can't set lod value along depth compare");
- return "texture(" + sampler + ", coords, " + depth_value + ')';
- }
- return "textureLod(" + sampler + ", coords, " + lod_value + ')';
- default:
- UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
- static_cast<u32>(instr.tex.GetTextureProcessMode()));
- if (depth_compare_extra) {
- return "texture(" + sampler + ", coords, " + depth_value + ')';
- }
- return "texture(" + sampler + ", coords)";
- }
- }();
+ shader.AddLine(coord);
if (depth_compare) {
regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
} else {
+ shader.AddLine("vec4 texture_tmp = " + texture + ';');
std::size_t dest_elem{};
for (std::size_t elem = 0; elem < 4; ++elem) {
if (!instr.tex.IsComponentEnabled(elem)) {
// Skip disabled components
continue;
}
- regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
+ regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false,
+ dest_elem);
++dest_elem;
}
}
@@ -2743,129 +2762,28 @@ private:
}
case OpCode::Id::TEXS: {
Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
- bool is_array{instr.texs.IsArrayTexture()};
-
+ const bool is_array{instr.texs.IsArrayTexture()};
+ const bool depth_compare =
+ instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
+ const auto process_mode = instr.texs.GetTextureProcessMode();
UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
"NODEP is not implemented");
const auto scope = shader.Scope();
- const bool depth_compare =
- instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
- u32 num_coordinates = TextureCoordinates(texture_type);
- const auto process_mode = instr.texs.GetTextureProcessMode();
- u32 lod_offset = 0;
- if (process_mode == Tegra::Shader::TextureProcessMode::LL) {
- if (num_coordinates > 2) {
- shader.AddLine("float lod_value = " +
- regs.GetRegisterAsFloat(instr.gpr20.Value() + 1) + ';');
- lod_offset = 2;
- } else {
- shader.AddLine("float lod_value = " + regs.GetRegisterAsFloat(instr.gpr20) +
- ';');
- lod_offset = 1;
- }
- }
+ const auto [coord, texture] =
+ GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array);
- switch (num_coordinates) {
- case 1: {
- shader.AddLine("float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';');
- break;
- }
- case 2: {
- if (is_array) {
- if (depth_compare) {
- const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
- const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
- shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
- index + ");");
- } else {
- const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
- shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + index +
- ");");
- }
- } else {
- if (lod_offset != 0) {
- if (depth_compare) {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string z =
- regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset);
- shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z +
- ");");
- } else {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
- }
- } else {
- if (depth_compare) {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
- shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z +
- ");");
- } else {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
- shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
- }
- }
- }
- break;
- }
- case 3: {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
- shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");");
- break;
- }
- default:
- UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
- static_cast<u32>(num_coordinates));
+ shader.AddLine(coord);
- // Fallback to interpreting as a 2D texture for now
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
- shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
- texture_type = Tegra::Shader::TextureType::Texture2D;
- is_array = false;
- }
- const std::string sampler =
- GetSampler(instr.sampler, texture_type, is_array, depth_compare);
+ if (!depth_compare) {
+ shader.AddLine("vec4 texture_tmp = " + texture + ';');
- std::string texture = [&]() {
- switch (process_mode) {
- case Tegra::Shader::TextureProcessMode::None:
- return "texture(" + sampler + ", coords)";
- case Tegra::Shader::TextureProcessMode::LZ:
- if (depth_compare && is_array) {
- return "texture(" + sampler + ", coords)";
- } else {
- return "textureLod(" + sampler + ", coords, 0.0)";
- }
- break;
- case Tegra::Shader::TextureProcessMode::LL:
- return "textureLod(" + sampler + ", coords, lod_value)";
- default:
- UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
- static_cast<u32>(instr.texs.GetTextureProcessMode()));
- return "texture(" + sampler + ", coords)";
- }
- }();
- if (depth_compare) {
- texture = "vec4(" + texture + ')';
+ } else {
+ shader.AddLine("vec4 texture_tmp = vec4(" + texture + ");");
}
- WriteTexsInstruction(instr, texture);
+ WriteTexsInstruction(instr, "texture_tmp");
break;
}
case OpCode::Id::TLDS: {
@@ -3934,4 +3852,4 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
return {};
}
-} // namespace OpenGL::GLShader::Decompiler
+} // namespace OpenGL::GLShader::Decompiler \ No newline at end of file