summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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) {
42 u16 generation = next_generation++; 42 u16 generation = next_generation++;
43 43
44 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. 44 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
45 // CTR-OS doesn't use generation 0, so skip straight to 1. 45 // Horizon OS uses zero to represent an invalid handle, so skip to 1.
46 if (next_generation >= (1 << 15)) 46 if (next_generation >= (1 << 15)) {
47 next_generation = 1; 47 next_generation = 1;
48 }
48 49
49 generations[slot] = generation; 50 generations[slot] = generation;
50 objects[slot] = std::move(obj); 51 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 @@
13namespace Kernel { 13namespace Kernel {
14 14
15enum KernelHandle : Handle { 15enum KernelHandle : Handle {
16 InvalidHandle = 0,
16 CurrentThread = 0xFFFF8000, 17 CurrentThread = 0xFFFF8000,
17 CurrentProcess = 0xFFFF8001, 18 CurrentProcess = 0xFFFF8001,
18}; 19};
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) {
44 return process; 44 return process;
45} 45}
46 46
47SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
48 return resource_limit;
49}
50
47void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { 51void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
48 program_id = metadata.GetTitleID(); 52 program_id = metadata.GetTitleID();
49 is_64bit_process = metadata.Is64BitProgram(); 53 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:
171 } 171 }
172 172
173 /// Gets the resource limit descriptor for this process 173 /// Gets the resource limit descriptor for this process
174 ResourceLimit& GetResourceLimit() { 174 SharedPtr<ResourceLimit> GetResourceLimit() const;
175 return *resource_limit;
176 }
177
178 /// Gets the resource limit descriptor for this process
179 const ResourceLimit& GetResourceLimit() const {
180 return *resource_limit;
181 }
182 175
183 /// Gets the default CPU ID for this process 176 /// Gets the default CPU ID for this process
184 u8 GetDefaultProcessorID() const { 177 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)
663 TotalMemoryUsage = 6, 663 TotalMemoryUsage = 6,
664 TotalHeapUsage = 7, 664 TotalHeapUsage = 7,
665 IsCurrentProcessBeingDebugged = 8, 665 IsCurrentProcessBeingDebugged = 8,
666 ResourceHandleLimit = 9, 666 RegisterResourceLimit = 9,
667 IdleTickCount = 10, 667 IdleTickCount = 10,
668 RandomEntropy = 11, 668 RandomEntropy = 11,
669 PerformanceCounter = 0xF0000002, 669 PerformanceCounter = 0xF0000002,
@@ -787,6 +787,33 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
787 *result = 0; 787 *result = 0;
788 return RESULT_SUCCESS; 788 return RESULT_SUCCESS;
789 789
790 case GetInfoType::RegisterResourceLimit: {
791 if (handle != 0) {
792 return ERR_INVALID_HANDLE;
793 }
794
795 if (info_sub_id != 0) {
796 return ERR_INVALID_COMBINATION;
797 }
798
799 Process* const current_process = Core::CurrentProcess();
800 HandleTable& handle_table = current_process->GetHandleTable();
801 const auto resource_limit = current_process->GetResourceLimit();
802 if (!resource_limit) {
803 *result = KernelHandle::InvalidHandle;
804 // Yes, the kernel considers this a successful operation.
805 return RESULT_SUCCESS;
806 }
807
808 const auto table_result = handle_table.Create(resource_limit);
809 if (table_result.Failed()) {
810 return table_result.Code();
811 }
812
813 *result = *table_result;
814 return RESULT_SUCCESS;
815 }
816
790 case GetInfoType::RandomEntropy: 817 case GetInfoType::RandomEntropy:
791 if (handle != 0) { 818 if (handle != 0) {
792 LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}", 819 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 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstddef>
7#include <memory>
8#include <utility>
9#include "common/assert.h"
10#include "common/logging/log.h"
11#include "common/microprofile.h"
12#include "common/vector_math.h"
13#include "core/memory.h"
14#include "core/tracer/recorder.h"
15#include "video_core/command_processor.h"
16#include "video_core/engines/fermi_2d.h"
17#include "video_core/engines/kepler_memory.h"
18#include "video_core/engines/maxwell_3d.h"
19#include "video_core/engines/maxwell_compute.h"
20#include "video_core/engines/maxwell_dma.h"
21#include "video_core/gpu.h"
22#include "video_core/renderer_base.h"
23#include "video_core/video_core.h"
24
25namespace Tegra {
26
27enum class BufferMethods {
28 BindObject = 0,
29 CountBufferMethods = 0x40,
30};
31
32MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
33
34void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
35 MICROPROFILE_SCOPE(ProcessCommandLists);
36
37 // On entering GPU code, assume all memory may be touched by the ARM core.
38 maxwell_3d->dirty_flags.OnMemoryWrite();
39
40 auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) {
41 LOG_TRACE(HW_GPU,
42 "Processing method {:08X} on subchannel {} value "
43 "{:08X} remaining params {}",
44 method, subchannel, value, remaining_params);
45
46 ASSERT(subchannel < bound_engines.size());
47
48 if (method == static_cast<u32>(BufferMethods::BindObject)) {
49 // Bind the current subchannel to the desired engine id.
50 LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
51 bound_engines[subchannel] = static_cast<EngineID>(value);
52 return;
53 }
54
55 if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
56 // TODO(Subv): Research and implement these methods.
57 LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
58 return;
59 }
60
61 const EngineID engine = bound_engines[subchannel];
62
63 switch (engine) {
64 case EngineID::FERMI_TWOD_A:
65 fermi_2d->WriteReg(method, value);
66 break;
67 case EngineID::MAXWELL_B:
68 maxwell_3d->WriteReg(method, value, remaining_params);
69 break;
70 case EngineID::MAXWELL_COMPUTE_B:
71 maxwell_compute->WriteReg(method, value);
72 break;
73 case EngineID::MAXWELL_DMA_COPY_A:
74 maxwell_dma->WriteReg(method, value);
75 break;
76 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
77 kepler_memory->WriteReg(method, value);
78 break;
79 default:
80 UNIMPLEMENTED_MSG("Unimplemented engine");
81 }
82 };
83
84 for (auto entry : commands) {
85 Tegra::GPUVAddr address = entry.Address();
86 u32 size = entry.sz;
87 const std::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address);
88 VAddr current_addr = *head_address;
89 while (current_addr < *head_address + size * sizeof(CommandHeader)) {
90 const CommandHeader header = {Memory::Read32(current_addr)};
91 current_addr += sizeof(u32);
92
93 switch (header.mode.Value()) {
94 case SubmissionMode::IncreasingOld:
95 case SubmissionMode::Increasing: {
96 // Increase the method value with each argument.
97 for (unsigned i = 0; i < header.arg_count; ++i) {
98 WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr),
99 header.arg_count - i - 1);
100 current_addr += sizeof(u32);
101 }
102 break;
103 }
104 case SubmissionMode::NonIncreasingOld:
105 case SubmissionMode::NonIncreasing: {
106 // Use the same method value for all arguments.
107 for (unsigned i = 0; i < header.arg_count; ++i) {
108 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
109 header.arg_count - i - 1);
110 current_addr += sizeof(u32);
111 }
112 break;
113 }
114 case SubmissionMode::IncreaseOnce: {
115 ASSERT(header.arg_count.Value() >= 1);
116
117 // Use the original method for the first argument and then the next method for all
118 // other arguments.
119 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
120 header.arg_count - 1);
121 current_addr += sizeof(u32);
122
123 for (unsigned i = 1; i < header.arg_count; ++i) {
124 WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr),
125 header.arg_count - i - 1);
126 current_addr += sizeof(u32);
127 }
128 break;
129 }
130 case SubmissionMode::Inline: {
131 // The register value is stored in the bits 16-28 as an immediate
132 WriteReg(header.method, header.subchannel, header.inline_data, 0);
133 break;
134 }
135 default:
136 UNIMPLEMENTED();
137 }
138 }
139 }
140}
141
142} // 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) {
141 return; 141 return;
142 } 142 }
143 143
144 if (method_call.method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
145 // TODO(Subv): Research and implement these methods.
146 LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
147 return;
148 }
149
144 const EngineID engine = bound_engines[method_call.subchannel]; 150 const EngineID engine = bound_engines[method_call.subchannel];
145 151
146 switch (engine) { 152 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:
1515 } 1515 }
1516 } 1516 }
1517 1517
1518 std::pair<size_t, std::string> ValidateAndGetCoordinateElement(
1519 const Tegra::Shader::TextureType texture_type, const bool depth_compare,
1520 const bool is_array, const bool lod_bias_enabled, size_t max_coords, size_t max_inputs) {
1521 const size_t coord_count = TextureCoordinates(texture_type);
1522
1523 size_t total_coord_count = coord_count + (is_array ? 1 : 0) + (depth_compare ? 1 : 0);
1524 const size_t total_reg_count = total_coord_count + (lod_bias_enabled ? 1 : 0);
1525 if (total_coord_count > max_coords || total_reg_count > max_inputs) {
1526 UNIMPLEMENTED_MSG("Unsupported Texture operation");
1527 total_coord_count = std::min(total_coord_count, max_coords);
1528 }
1529 // 1D.DC opengl is using a vec3 but 2nd component is ignored later.
1530 total_coord_count +=
1531 (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D)
1532 ? 1
1533 : 0;
1534
1535 constexpr std::array<const char*, 5> coord_container{
1536 {"", "float coord = (", "vec2 coord = vec2(", "vec3 coord = vec3(",
1537 "vec4 coord = vec4("}};
1538
1539 return std::pair<size_t, std::string>(coord_count, coord_container[total_coord_count]);
1540 }
1541
1542 std::string GetTextureCode(const Tegra::Shader::Instruction& instr,
1543 const Tegra::Shader::TextureType texture_type,
1544 const Tegra::Shader::TextureProcessMode process_mode,
1545 const bool depth_compare, const bool is_array,
1546 const size_t bias_offset) {
1547
1548 if ((texture_type == Tegra::Shader::TextureType::Texture3D &&
1549 (is_array || depth_compare)) ||
1550 (texture_type == Tegra::Shader::TextureType::TextureCube && is_array &&
1551 depth_compare)) {
1552 UNIMPLEMENTED_MSG("This method is not supported.");
1553 }
1554
1555 const std::string sampler =
1556 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
1557
1558 const bool lod_needed = process_mode == Tegra::Shader::TextureProcessMode::LZ ||
1559 process_mode == Tegra::Shader::TextureProcessMode::LL ||
1560 process_mode == Tegra::Shader::TextureProcessMode::LLA;
1561
1562 const bool gl_lod_supported = !(
1563 (texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) ||
1564 (texture_type == Tegra::Shader::TextureType::TextureCube && !is_array &&
1565 depth_compare));
1566
1567 const std::string read_method = lod_needed && gl_lod_supported ? "textureLod(" : "texture(";
1568 std::string texture = read_method + sampler + ", coord";
1569
1570 if (process_mode != Tegra::Shader::TextureProcessMode::None) {
1571 if (process_mode == Tegra::Shader::TextureProcessMode::LZ) {
1572 if (gl_lod_supported) {
1573 texture += ", 0";
1574 } else {
1575 // Lod 0 is emulated by a big negative bias
1576 // in scenarios that are not supported by glsl
1577 texture += ", -1000";
1578 }
1579 } else {
1580 // If present, lod or bias are always stored in the register indexed by the
1581 // gpr20
1582 // field with an offset depending on the usage of the other registers
1583 texture += ',' + regs.GetRegisterAsFloat(instr.gpr20.Value() + bias_offset);
1584 }
1585 }
1586 texture += ")";
1587 return texture;
1588 }
1589
1590 std::pair<std::string, std::string> GetTEXCode(
1591 const Instruction& instr, const Tegra::Shader::TextureType texture_type,
1592 const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
1593 const bool is_array) {
1594 const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
1595 process_mode != Tegra::Shader::TextureProcessMode::LZ);
1596
1597 const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
1598 texture_type, depth_compare, is_array, lod_bias_enabled, 4, 5);
1599 // If enabled arrays index is always stored in the gpr8 field
1600 const u64 array_register = instr.gpr8.Value();
1601 // First coordinate index is the gpr8 or gpr8 + 1 when arrays are used
1602 const u64 coord_register = array_register + (is_array ? 1 : 0);
1603
1604 std::string coord = coord_dcl;
1605 for (size_t i = 0; i < coord_count;) {
1606 coord += regs.GetRegisterAsFloat(coord_register + i);
1607 ++i;
1608 if (i != coord_count) {
1609 coord += ',';
1610 }
1611 }
1612 // 1D.DC in opengl the 2nd component is ignored.
1613 if (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D) {
1614 coord += ",0.0";
1615 }
1616 if (depth_compare) {
1617 // Depth is always stored in the register signaled by gpr20
1618 // or in the next register if lod or bias are used
1619 const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
1620 coord += ',' + regs.GetRegisterAsFloat(depth_register);
1621 }
1622 if (is_array) {
1623 coord += ',' + regs.GetRegisterAsInteger(array_register);
1624 }
1625 coord += ");";
1626 return std::make_pair(
1627 coord, GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, 0));
1628 }
1629
1630 std::pair<std::string, std::string> GetTEXSCode(
1631 const Instruction& instr, const Tegra::Shader::TextureType texture_type,
1632 const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
1633 const bool is_array) {
1634 const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
1635 process_mode != Tegra::Shader::TextureProcessMode::LZ);
1636
1637 const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
1638 texture_type, depth_compare, is_array, lod_bias_enabled, 4, 4);
1639 // If enabled arrays index is always stored in the gpr8 field
1640 const u64 array_register = instr.gpr8.Value();
1641 // First coordinate index is stored in gpr8 field or (gpr8 + 1) when arrays are used
1642 const u64 coord_register = array_register + (is_array ? 1 : 0);
1643 const u64 last_coord_register =
1644 (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2))
1645 ? static_cast<u64>(instr.gpr20.Value())
1646 : coord_register + 1;
1647
1648 std::string coord = coord_dcl;
1649 for (size_t i = 0; i < coord_count; ++i) {
1650 const bool last = (i == (coord_count - 1)) && (coord_count > 1);
1651 coord += regs.GetRegisterAsFloat(last ? last_coord_register : coord_register + i);
1652 if (!last) {
1653 coord += ',';
1654 }
1655 }
1656
1657 if (depth_compare) {
1658 // Depth is always stored in the register signaled by gpr20
1659 // or in the next register if lod or bias are used
1660 const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
1661 coord += ',' + regs.GetRegisterAsFloat(depth_register);
1662 }
1663 if (is_array) {
1664 coord += ',' + regs.GetRegisterAsInteger(array_register);
1665 }
1666 coord += ");";
1667
1668 return std::make_pair(coord,
1669 GetTextureCode(instr, texture_type, process_mode, depth_compare,
1670 is_array, (coord_count > 2 ? 1 : 0)));
1671 }
1672
1518 /** 1673 /**
1519 * Compiles a single instruction from Tegra to GLSL. 1674 * Compiles a single instruction from Tegra to GLSL.
1520 * @param offset the offset of the Tegra shader instruction. 1675 * @param offset the offset of the Tegra shader instruction.
@@ -2574,168 +2729,32 @@ private:
2574 case OpCode::Id::TEX: { 2729 case OpCode::Id::TEX: {
2575 Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; 2730 Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
2576 const bool is_array = instr.tex.array != 0; 2731 const bool is_array = instr.tex.array != 0;
2577 2732 const bool depth_compare =
2733 instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2734 const auto process_mode = instr.tex.GetTextureProcessMode();
2578 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2735 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2579 "NODEP is not implemented"); 2736 "NODEP is not implemented");
2580 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), 2737 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
2581 "AOFFI is not implemented"); 2738 "AOFFI is not implemented");
2582 2739
2583 const bool depth_compare = 2740 const auto [coord, texture] =
2584 instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2741 GetTEXCode(instr, texture_type, process_mode, depth_compare, is_array);
2585 u32 num_coordinates = TextureCoordinates(texture_type);
2586 u32 start_index = 0;
2587 std::string array_elem;
2588 if (is_array) {
2589 array_elem = regs.GetRegisterAsInteger(instr.gpr8);
2590 start_index = 1;
2591 }
2592 const auto process_mode = instr.tex.GetTextureProcessMode();
2593 u32 start_index_b = 0;
2594 std::string lod_value;
2595 if (process_mode != Tegra::Shader::TextureProcessMode::LZ &&
2596 process_mode != Tegra::Shader::TextureProcessMode::None) {
2597 start_index_b = 1;
2598 lod_value = regs.GetRegisterAsFloat(instr.gpr20);
2599 }
2600
2601 std::string depth_value;
2602 if (depth_compare) {
2603 depth_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + start_index_b);
2604 }
2605
2606 bool depth_compare_extra = false;
2607 2742
2608 const auto scope = shader.Scope(); 2743 const auto scope = shader.Scope();
2609 2744 shader.AddLine(coord);
2610 switch (num_coordinates) {
2611 case 1: {
2612 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
2613 if (is_array) {
2614 if (depth_compare) {
2615 shader.AddLine("vec3 coords = vec3(" + x + ", " + depth_value + ", " +
2616 array_elem + ");");
2617 } else {
2618 shader.AddLine("vec2 coords = vec2(" + x + ", " + array_elem + ");");
2619 }
2620 } else {
2621 if (depth_compare) {
2622 shader.AddLine("vec2 coords = vec2(" + x + ", " + depth_value + ");");
2623 } else {
2624 shader.AddLine("float coords = " + x + ';');
2625 }
2626 }
2627 break;
2628 }
2629 case 2: {
2630 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
2631 const std::string y =
2632 regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
2633 if (is_array) {
2634 if (depth_compare) {
2635 shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " +
2636 depth_value + ", " + array_elem + ");");
2637 } else {
2638 shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " +
2639 array_elem + ");");
2640 }
2641 } else {
2642 if (depth_compare) {
2643 shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " +
2644 depth_value + ");");
2645 } else {
2646 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
2647 }
2648 }
2649 break;
2650 }
2651 case 3: {
2652 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
2653 const std::string y =
2654 regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
2655 const std::string z =
2656 regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2);
2657 if (is_array) {
2658 depth_compare_extra = depth_compare;
2659 shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
2660 array_elem + ");");
2661 } else {
2662 if (depth_compare) {
2663 shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
2664 depth_value + ");");
2665 } else {
2666 shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");");
2667 }
2668 }
2669 break;
2670 }
2671 default:
2672 UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
2673 static_cast<u32>(num_coordinates));
2674
2675 // Fallback to interpreting as a 2D texture for now
2676 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2677 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2678 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
2679 texture_type = Tegra::Shader::TextureType::Texture2D;
2680 }
2681
2682 const std::string sampler =
2683 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
2684 // Add an extra scope and declare the texture coords inside to prevent
2685 // overwriting them in case they are used as outputs of the texs instruction.
2686
2687 const std::string texture = [&]() {
2688 switch (instr.tex.GetTextureProcessMode()) {
2689 case Tegra::Shader::TextureProcessMode::None:
2690 if (depth_compare_extra) {
2691 return "texture(" + sampler + ", coords, " + depth_value + ')';
2692 }
2693 return "texture(" + sampler + ", coords)";
2694 case Tegra::Shader::TextureProcessMode::LZ:
2695 if (depth_compare_extra) {
2696 return "texture(" + sampler + ", coords, " + depth_value + ')';
2697 }
2698 return "textureLod(" + sampler + ", coords, 0.0)";
2699 case Tegra::Shader::TextureProcessMode::LB:
2700 case Tegra::Shader::TextureProcessMode::LBA:
2701 // TODO: Figure if A suffix changes the equation at all.
2702 if (depth_compare_extra) {
2703 LOG_WARNING(
2704 HW_GPU,
2705 "OpenGL Limitation: can't set bias value along depth compare");
2706 return "texture(" + sampler + ", coords, " + depth_value + ')';
2707 }
2708 return "texture(" + sampler + ", coords, " + lod_value + ')';
2709 case Tegra::Shader::TextureProcessMode::LL:
2710 case Tegra::Shader::TextureProcessMode::LLA:
2711 // TODO: Figure if A suffix changes the equation at all.
2712 if (depth_compare_extra) {
2713 LOG_WARNING(
2714 HW_GPU,
2715 "OpenGL Limitation: can't set lod value along depth compare");
2716 return "texture(" + sampler + ", coords, " + depth_value + ')';
2717 }
2718 return "textureLod(" + sampler + ", coords, " + lod_value + ')';
2719 default:
2720 UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
2721 static_cast<u32>(instr.tex.GetTextureProcessMode()));
2722 if (depth_compare_extra) {
2723 return "texture(" + sampler + ", coords, " + depth_value + ')';
2724 }
2725 return "texture(" + sampler + ", coords)";
2726 }
2727 }();
2728 2745
2729 if (depth_compare) { 2746 if (depth_compare) {
2730 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); 2747 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2731 } else { 2748 } else {
2749 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2732 std::size_t dest_elem{}; 2750 std::size_t dest_elem{};
2733 for (std::size_t elem = 0; elem < 4; ++elem) { 2751 for (std::size_t elem = 0; elem < 4; ++elem) {
2734 if (!instr.tex.IsComponentEnabled(elem)) { 2752 if (!instr.tex.IsComponentEnabled(elem)) {
2735 // Skip disabled components 2753 // Skip disabled components
2736 continue; 2754 continue;
2737 } 2755 }
2738 regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); 2756 regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false,
2757 dest_elem);
2739 ++dest_elem; 2758 ++dest_elem;
2740 } 2759 }
2741 } 2760 }
@@ -2743,129 +2762,28 @@ private:
2743 } 2762 }
2744 case OpCode::Id::TEXS: { 2763 case OpCode::Id::TEXS: {
2745 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; 2764 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
2746 bool is_array{instr.texs.IsArrayTexture()}; 2765 const bool is_array{instr.texs.IsArrayTexture()};
2747 2766 const bool depth_compare =
2767 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2768 const auto process_mode = instr.texs.GetTextureProcessMode();
2748 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2769 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2749 "NODEP is not implemented"); 2770 "NODEP is not implemented");
2750 2771
2751 const auto scope = shader.Scope(); 2772 const auto scope = shader.Scope();
2752 2773
2753 const bool depth_compare = 2774 const auto [coord, texture] =
2754 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2775 GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array);
2755 u32 num_coordinates = TextureCoordinates(texture_type);
2756 const auto process_mode = instr.texs.GetTextureProcessMode();
2757 u32 lod_offset = 0;
2758 if (process_mode == Tegra::Shader::TextureProcessMode::LL) {
2759 if (num_coordinates > 2) {
2760 shader.AddLine("float lod_value = " +
2761 regs.GetRegisterAsFloat(instr.gpr20.Value() + 1) + ';');
2762 lod_offset = 2;
2763 } else {
2764 shader.AddLine("float lod_value = " + regs.GetRegisterAsFloat(instr.gpr20) +
2765 ';');
2766 lod_offset = 1;
2767 }
2768 }
2769 2776
2770 switch (num_coordinates) { 2777 shader.AddLine(coord);
2771 case 1: {
2772 shader.AddLine("float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';');
2773 break;
2774 }
2775 case 2: {
2776 if (is_array) {
2777 if (depth_compare) {
2778 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2779 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2780 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2781 const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
2782 shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
2783 index + ");");
2784 } else {
2785 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2786 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2787 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2788 shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + index +
2789 ");");
2790 }
2791 } else {
2792 if (lod_offset != 0) {
2793 if (depth_compare) {
2794 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2795 const std::string y =
2796 regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2797 const std::string z =
2798 regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset);
2799 shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z +
2800 ");");
2801 } else {
2802 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2803 const std::string y =
2804 regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2805 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
2806 }
2807 } else {
2808 if (depth_compare) {
2809 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2810 const std::string y =
2811 regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2812 const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
2813 shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z +
2814 ");");
2815 } else {
2816 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2817 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2818 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
2819 }
2820 }
2821 }
2822 break;
2823 }
2824 case 3: {
2825 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2826 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2827 const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
2828 shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");");
2829 break;
2830 }
2831 default:
2832 UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
2833 static_cast<u32>(num_coordinates));
2834 2778
2835 // Fallback to interpreting as a 2D texture for now 2779 if (!depth_compare) {
2836 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2780 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2837 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2838 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
2839 texture_type = Tegra::Shader::TextureType::Texture2D;
2840 is_array = false;
2841 }
2842 const std::string sampler =
2843 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
2844 2781
2845 std::string texture = [&]() { 2782 } else {
2846 switch (process_mode) { 2783 shader.AddLine("vec4 texture_tmp = vec4(" + texture + ");");
2847 case Tegra::Shader::TextureProcessMode::None:
2848 return "texture(" + sampler + ", coords)";
2849 case Tegra::Shader::TextureProcessMode::LZ:
2850 if (depth_compare && is_array) {
2851 return "texture(" + sampler + ", coords)";
2852 } else {
2853 return "textureLod(" + sampler + ", coords, 0.0)";
2854 }
2855 break;
2856 case Tegra::Shader::TextureProcessMode::LL:
2857 return "textureLod(" + sampler + ", coords, lod_value)";
2858 default:
2859 UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
2860 static_cast<u32>(instr.texs.GetTextureProcessMode()));
2861 return "texture(" + sampler + ", coords)";
2862 }
2863 }();
2864 if (depth_compare) {
2865 texture = "vec4(" + texture + ')';
2866 } 2784 }
2867 2785
2868 WriteTexsInstruction(instr, texture); 2786 WriteTexsInstruction(instr, "texture_tmp");
2869 break; 2787 break;
2870 } 2788 }
2871 case OpCode::Id::TLDS: { 2789 case OpCode::Id::TLDS: {
@@ -3934,4 +3852,4 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
3934 return {}; 3852 return {};
3935} 3853}
3936 3854
3937} // namespace OpenGL::GLShader::Decompiler 3855} // namespace OpenGL::GLShader::Decompiler \ No newline at end of file