summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar greggameplayer2018-11-02 14:26:32 +0100
committerGravatar GitHub2018-11-02 14:26:32 +0100
commitcb8e4a46330ca23496c3a77f42d9d16dc26e0dbe (patch)
treecedafffe5a605a1ed914e1d1df1267a3cd299fc9 /src
parentImplement SurfaceTarget Texture2DArray (diff)
parentMerge pull request #1615 from lioncash/input (diff)
downloadyuzu-cb8e4a46330ca23496c3a77f42d9d16dc26e0dbe.tar.gz
yuzu-cb8e4a46330ca23496c3a77f42d9d16dc26e0dbe.tar.xz
yuzu-cb8e4a46330ca23496c3a77f42d9d16dc26e0dbe.zip
Merge branch 'master' into Texture2DArray
Diffstat (limited to '')
-rw-r--r--src/common/telemetry.h4
-rw-r--r--src/core/hle/service/acc/profile_manager.h3
-rw-r--r--src/core/hle/service/usb/usb.cpp6
-rw-r--r--src/core/telemetry_session.cpp9
-rw-r--r--src/core/telemetry_session.h6
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/engines/maxwell_3d.cpp26
-rw-r--r--src/video_core/engines/maxwell_3d.h25
-rw-r--r--src/video_core/engines/shader_bytecode.h7
-rw-r--r--src/video_core/macro_interpreter.cpp19
-rw-r--r--src/video_core/macro_interpreter.h12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp167
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h789
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp126
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp246
-rw-r--r--src/video_core/renderer_opengl/gl_state.h13
-rw-r--r--src/video_core/surface.cpp499
-rw-r--r--src/video_core/surface.h385
-rw-r--r--src/web_service/telemetry_json.cpp21
-rw-r--r--src/web_service/telemetry_json.h1
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/compatdb.cpp27
-rw-r--r--src/yuzu/compatdb.h4
-rw-r--r--src/yuzu/configuration/configure_system.cpp43
-rw-r--r--src/yuzu/util/limitable_input_dialog.cpp59
-rw-r--r--src/yuzu/util/limitable_input_dialog.h31
27 files changed, 1477 insertions, 1066 deletions
diff --git a/src/common/telemetry.h b/src/common/telemetry.h
index 8d6ab986b..854a73fae 100644
--- a/src/common/telemetry.h
+++ b/src/common/telemetry.h
@@ -153,6 +153,7 @@ struct VisitorInterface : NonCopyable {
153 153
154 /// Completion method, called once all fields have been visited 154 /// Completion method, called once all fields have been visited
155 virtual void Complete() = 0; 155 virtual void Complete() = 0;
156 virtual bool SubmitTestcase() = 0;
156}; 157};
157 158
158/** 159/**
@@ -178,6 +179,9 @@ struct NullVisitor : public VisitorInterface {
178 void Visit(const Field<std::chrono::microseconds>& /*field*/) override {} 179 void Visit(const Field<std::chrono::microseconds>& /*field*/) override {}
179 180
180 void Complete() override {} 181 void Complete() override {}
182 bool SubmitTestcase() override {
183 return false;
184 }
181}; 185};
182 186
183/// Appends build-specific information to the given FieldCollection, 187/// Appends build-specific information to the given FieldCollection,
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 1cd2e51b2..747c46c20 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -57,7 +57,8 @@ struct UUID {
57}; 57};
58static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); 58static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
59 59
60using ProfileUsername = std::array<u8, 0x20>; 60constexpr std::size_t profile_username_size = 32;
61using ProfileUsername = std::array<u8, profile_username_size>;
61using ProfileData = std::array<u8, MAX_DATA>; 62using ProfileData = std::array<u8, MAX_DATA>;
62using UserIDArray = std::array<UUID, MAX_USERS>; 63using UserIDArray = std::array<UUID, MAX_USERS>;
63 64
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index c489da071..f0a831d45 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -132,11 +132,11 @@ public:
132 // clang-format off 132 // clang-format off
133 static const FunctionInfo functions[] = { 133 static const FunctionInfo functions[] = {
134 {0, nullptr, "BindNoticeEvent"}, 134 {0, nullptr, "BindNoticeEvent"},
135 {1, nullptr, "Unknown1"}, 135 {1, nullptr, "UnbindNoticeEvent"},
136 {2, nullptr, "GetStatus"}, 136 {2, nullptr, "GetStatus"},
137 {3, nullptr, "GetNotice"}, 137 {3, nullptr, "GetNotice"},
138 {4, nullptr, "Unknown2"}, 138 {4, nullptr, "EnablePowerRequestNotice"},
139 {5, nullptr, "Unknown3"}, 139 {5, nullptr, "DisablePowerRequestNotice"},
140 {6, nullptr, "ReplyPowerRequest"}, 140 {6, nullptr, "ReplyPowerRequest"},
141 }; 141 };
142 // clang-format on 142 // clang-format on
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 0de13edd3..a3b08c740 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -184,4 +184,13 @@ TelemetrySession::~TelemetrySession() {
184 backend = nullptr; 184 backend = nullptr;
185} 185}
186 186
187bool TelemetrySession::SubmitTestcase() {
188#ifdef ENABLE_WEB_SERVICE
189 field_collection.Accept(*backend);
190 return backend->SubmitTestcase();
191#else
192 return false;
193#endif
194}
195
187} // namespace Core 196} // namespace Core
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index 2a4845797..023612b79 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -31,6 +31,12 @@ public:
31 field_collection.AddField(type, name, std::move(value)); 31 field_collection.AddField(type, name, std::move(value));
32 } 32 }
33 33
34 /**
35 * Submits a Testcase.
36 * @returns A bool indicating whether the submission succeeded
37 */
38 bool SubmitTestcase();
39
34private: 40private:
35 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session 41 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
36 std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields 42 std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index c5f7128ec..ddb1a1d69 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -53,6 +53,8 @@ add_library(video_core STATIC
53 renderer_opengl/renderer_opengl.h 53 renderer_opengl/renderer_opengl.h
54 renderer_opengl/utils.cpp 54 renderer_opengl/utils.cpp
55 renderer_opengl/utils.h 55 renderer_opengl/utils.h
56 surface.cpp
57 surface.h
56 textures/astc.cpp 58 textures/astc.cpp
57 textures/astc.h 59 textures/astc.h
58 textures/decoders.cpp 60 textures/decoders.cpp
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7357d20d1..d79c50919 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -43,15 +43,17 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
43 // Reset the current macro. 43 // Reset the current macro.
44 executing_macro = 0; 44 executing_macro = 0;
45 45
46 // The requested macro must have been uploaded already. 46 // Lookup the macro offset
47 auto macro_code = uploaded_macros.find(method); 47 const u32 entry{(method - MacroRegistersStart) >> 1};
48 if (macro_code == uploaded_macros.end()) { 48 const auto& search{macro_offsets.find(entry)};
49 LOG_ERROR(HW_GPU, "Macro {:04X} was not uploaded", method); 49 if (search == macro_offsets.end()) {
50 LOG_CRITICAL(HW_GPU, "macro not found for method 0x{:X}!", method);
51 UNREACHABLE();
50 return; 52 return;
51 } 53 }
52 54
53 // Execute the current macro. 55 // Execute the current macro.
54 macro_interpreter.Execute(macro_code->second, std::move(parameters)); 56 macro_interpreter.Execute(search->second, std::move(parameters));
55} 57}
56 58
57void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { 59void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
@@ -97,6 +99,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
97 ProcessMacroUpload(value); 99 ProcessMacroUpload(value);
98 break; 100 break;
99 } 101 }
102 case MAXWELL3D_REG_INDEX(macros.bind): {
103 ProcessMacroBind(value);
104 break;
105 }
100 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): 106 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
101 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]): 107 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
102 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]): 108 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
@@ -158,9 +164,13 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
158} 164}
159 165
160void Maxwell3D::ProcessMacroUpload(u32 data) { 166void Maxwell3D::ProcessMacroUpload(u32 data) {
161 // Store the uploaded macro code to interpret them when they're called. 167 ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
162 auto& macro = uploaded_macros[regs.macros.entry * 2 + MacroRegistersStart]; 168 "upload_address exceeded macro_memory size!");
163 macro.push_back(data); 169 macro_memory[regs.macros.upload_address++] = data;
170}
171
172void Maxwell3D::ProcessMacroBind(u32 data) {
173 macro_offsets[regs.macros.entry] = data;
164} 174}
165 175
166void Maxwell3D::ProcessQueryGet() { 176void Maxwell3D::ProcessQueryGet() {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 443affc36..50873813e 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -475,12 +475,13 @@ public:
475 INSERT_PADDING_WORDS(0x45); 475 INSERT_PADDING_WORDS(0x45);
476 476
477 struct { 477 struct {
478 INSERT_PADDING_WORDS(1); 478 u32 upload_address;
479 u32 data; 479 u32 data;
480 u32 entry; 480 u32 entry;
481 u32 bind;
481 } macros; 482 } macros;
482 483
483 INSERT_PADDING_WORDS(0x189); 484 INSERT_PADDING_WORDS(0x188);
484 485
485 u32 tfb_enabled; 486 u32 tfb_enabled;
486 487
@@ -994,12 +995,25 @@ public:
994 /// Returns the texture information for a specific texture in a specific shader stage. 995 /// Returns the texture information for a specific texture in a specific shader stage.
995 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const; 996 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
996 997
998 /// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
999 /// we've seen used.
1000 using MacroMemory = std::array<u32, 0x40000>;
1001
1002 /// Gets a reference to macro memory.
1003 const MacroMemory& GetMacroMemory() const {
1004 return macro_memory;
1005 }
1006
997private: 1007private:
998 void InitializeRegisterDefaults(); 1008 void InitializeRegisterDefaults();
999 1009
1000 VideoCore::RasterizerInterface& rasterizer; 1010 VideoCore::RasterizerInterface& rasterizer;
1001 1011
1002 std::unordered_map<u32, std::vector<u32>> uploaded_macros; 1012 /// Start offsets of each macro in macro_memory
1013 std::unordered_map<u32, u32> macro_offsets;
1014
1015 /// Memory for macro code
1016 MacroMemory macro_memory;
1003 1017
1004 /// Macro method that is currently being executed / being fed parameters. 1018 /// Macro method that is currently being executed / being fed parameters.
1005 u32 executing_macro = 0; 1019 u32 executing_macro = 0;
@@ -1022,9 +1036,12 @@ private:
1022 */ 1036 */
1023 void CallMacroMethod(u32 method, std::vector<u32> parameters); 1037 void CallMacroMethod(u32 method, std::vector<u32> parameters);
1024 1038
1025 /// Handles writes to the macro uploading registers. 1039 /// Handles writes to the macro uploading register.
1026 void ProcessMacroUpload(u32 data); 1040 void ProcessMacroUpload(u32 data);
1027 1041
1042 /// Handles writes to the macro bind register.
1043 void ProcessMacroBind(u32 data);
1044
1028 /// Handles a write to the CLEAR_BUFFERS register. 1045 /// Handles a write to the CLEAR_BUFFERS register.
1029 void ProcessClearBuffers(); 1046 void ProcessClearBuffers();
1030 1047
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index b84da512f..83a6fd875 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -578,6 +578,10 @@ union Instruction {
578 } fmul32; 578 } fmul32;
579 579
580 union { 580 union {
581 BitField<52, 1, u64> generates_cc;
582 } op_32;
583
584 union {
581 BitField<48, 1, u64> is_signed; 585 BitField<48, 1, u64> is_signed;
582 } shift; 586 } shift;
583 587
@@ -1231,6 +1235,7 @@ union Instruction {
1231 BitField<60, 1, u64> is_b_gpr; 1235 BitField<60, 1, u64> is_b_gpr;
1232 BitField<59, 1, u64> is_c_gpr; 1236 BitField<59, 1, u64> is_c_gpr;
1233 BitField<20, 24, s64> smem_imm; 1237 BitField<20, 24, s64> smem_imm;
1238 BitField<0, 5, ControlCode> flow_control_code;
1234 1239
1235 Attribute attribute; 1240 Attribute attribute;
1236 Sampler sampler; 1241 Sampler sampler;
@@ -1658,4 +1663,4 @@ private:
1658 } 1663 }
1659}; 1664};
1660 1665
1661} // namespace Tegra::Shader \ No newline at end of file 1666} // namespace Tegra::Shader
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index f6af132fb..335a8d407 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -11,7 +11,7 @@ namespace Tegra {
11 11
12MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {} 12MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
13 13
14void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> parameters) { 14void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
15 Reset(); 15 Reset();
16 registers[1] = parameters[0]; 16 registers[1] = parameters[0];
17 this->parameters = std::move(parameters); 17 this->parameters = std::move(parameters);
@@ -19,7 +19,7 @@ void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> pa
19 // Execute the code until we hit an exit condition. 19 // Execute the code until we hit an exit condition.
20 bool keep_executing = true; 20 bool keep_executing = true;
21 while (keep_executing) { 21 while (keep_executing) {
22 keep_executing = Step(code, false); 22 keep_executing = Step(offset, false);
23 } 23 }
24 24
25 // Assert the the macro used all the input parameters 25 // Assert the the macro used all the input parameters
@@ -37,10 +37,10 @@ void MacroInterpreter::Reset() {
37 next_parameter_index = 1; 37 next_parameter_index = 1;
38} 38}
39 39
40bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) { 40bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
41 u32 base_address = pc; 41 u32 base_address = pc;
42 42
43 Opcode opcode = GetOpcode(code); 43 Opcode opcode = GetOpcode(offset);
44 pc += 4; 44 pc += 4;
45 45
46 // Update the program counter if we were delayed 46 // Update the program counter if we were delayed
@@ -108,7 +108,7 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
108 108
109 delayed_pc = base_address + opcode.GetBranchTarget(); 109 delayed_pc = base_address + opcode.GetBranchTarget();
110 // Execute one more instruction due to the delay slot. 110 // Execute one more instruction due to the delay slot.
111 return Step(code, true); 111 return Step(offset, true);
112 } 112 }
113 break; 113 break;
114 } 114 }
@@ -121,17 +121,18 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
121 // Exit has a delay slot, execute the next instruction 121 // Exit has a delay slot, execute the next instruction
122 // Note: Executing an exit during a branch delay slot will cause the instruction at the 122 // Note: Executing an exit during a branch delay slot will cause the instruction at the
123 // branch target to be executed before exiting. 123 // branch target to be executed before exiting.
124 Step(code, true); 124 Step(offset, true);
125 return false; 125 return false;
126 } 126 }
127 127
128 return true; 128 return true;
129} 129}
130 130
131MacroInterpreter::Opcode MacroInterpreter::GetOpcode(const std::vector<u32>& code) const { 131MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
132 const auto& macro_memory{maxwell3d.GetMacroMemory()};
132 ASSERT((pc % sizeof(u32)) == 0); 133 ASSERT((pc % sizeof(u32)) == 0);
133 ASSERT(pc < code.size() * sizeof(u32)); 134 ASSERT((pc + offset) < macro_memory.size() * sizeof(u32));
134 return {code[pc / sizeof(u32)]}; 135 return {macro_memory[offset + pc / sizeof(u32)]};
135} 136}
136 137
137u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const { 138u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const {
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
index 773684bde..62d1ce289 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -22,10 +22,10 @@ public:
22 22
23 /** 23 /**
24 * Executes the macro code with the specified input parameters. 24 * Executes the macro code with the specified input parameters.
25 * @param code The macro byte code to execute 25 * @param offset Offset to start execution at.
26 * @param parameters The parameters of the macro 26 * @param parameters The parameters of the macro.
27 */ 27 */
28 void Execute(const std::vector<u32>& code, std::vector<u32> parameters); 28 void Execute(u32 offset, std::vector<u32> parameters);
29 29
30private: 30private:
31 enum class Operation : u32 { 31 enum class Operation : u32 {
@@ -110,11 +110,11 @@ private:
110 /** 110 /**
111 * Executes a single macro instruction located at the current program counter. Returns whether 111 * Executes a single macro instruction located at the current program counter. Returns whether
112 * the interpreter should keep running. 112 * the interpreter should keep running.
113 * @param code The macro code to execute. 113 * @param offset Offset to start execution at.
114 * @param is_delay_slot Whether the current step is being executed due to a delay slot in a 114 * @param is_delay_slot Whether the current step is being executed due to a delay slot in a
115 * previous instruction. 115 * previous instruction.
116 */ 116 */
117 bool Step(const std::vector<u32>& code, bool is_delay_slot); 117 bool Step(u32 offset, bool is_delay_slot);
118 118
119 /// Calculates the result of an ALU operation. src_a OP src_b; 119 /// Calculates the result of an ALU operation. src_a OP src_b;
120 u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const; 120 u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
@@ -127,7 +127,7 @@ private:
127 bool EvaluateBranchCondition(BranchCondition cond, u32 value) const; 127 bool EvaluateBranchCondition(BranchCondition cond, u32 value) const;
128 128
129 /// Reads an opcode at the current program counter location. 129 /// Reads an opcode at the current program counter location.
130 Opcode GetOpcode(const std::vector<u32>& code) const; 130 Opcode GetOpcode(u32 offset) const;
131 131
132 /// Returns the specified register's value. Register 0 is hardcoded to always return 0. 132 /// Returns the specified register's value. Register 0 is hardcoded to always return 0.
133 u32 GetRegister(u32 register_id) const; 133 u32 GetRegister(u32 register_id) const;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index bf381271e..a0527fe57 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -30,8 +30,8 @@
30namespace OpenGL { 30namespace OpenGL {
31 31
32using Maxwell = Tegra::Engines::Maxwell3D::Regs; 32using Maxwell = Tegra::Engines::Maxwell3D::Regs;
33using PixelFormat = SurfaceParams::PixelFormat; 33using PixelFormat = VideoCore::Surface::PixelFormat;
34using SurfaceType = SurfaceParams::SurfaceType; 34using SurfaceType = VideoCore::Surface::SurfaceType;
35 35
36MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192)); 36MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192));
37MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192)); 37MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192));
@@ -104,7 +104,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
104 } 104 }
105 105
106 ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported"); 106 ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
107 107 OpenGLState::ApplyDefaultState();
108 // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0 108 // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
109 state.clip_distance[0] = true; 109 state.clip_distance[0] = true;
110 110
@@ -115,8 +115,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
115 state.draw.shader_program = 0; 115 state.draw.shader_program = 0;
116 state.Apply(); 116 state.Apply();
117 117
118 glEnable(GL_BLEND);
119
120 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); 118 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
121 119
122 LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); 120 LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
@@ -703,7 +701,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
703 701
704 // Verify that the cached surface is the same size and format as the requested framebuffer 702 // Verify that the cached surface is the same size and format as the requested framebuffer
705 const auto& params{surface->GetSurfaceParams()}; 703 const auto& params{surface->GetSurfaceParams()};
706 const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)}; 704 const auto& pixel_format{
705 VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
707 ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); 706 ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
708 ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); 707 ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
709 ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different"); 708 ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different");
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 513d82e39..0582b069c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -17,15 +17,20 @@
17#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
18#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 18#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
19#include "video_core/renderer_opengl/utils.h" 19#include "video_core/renderer_opengl/utils.h"
20#include "video_core/surface.h"
20#include "video_core/textures/astc.h" 21#include "video_core/textures/astc.h"
21#include "video_core/textures/decoders.h" 22#include "video_core/textures/decoders.h"
22#include "video_core/utils.h" 23#include "video_core/utils.h"
23 24
24namespace OpenGL { 25namespace OpenGL {
25 26
26using SurfaceType = SurfaceParams::SurfaceType; 27using VideoCore::Surface::ComponentTypeFromDepthFormat;
27using PixelFormat = SurfaceParams::PixelFormat; 28using VideoCore::Surface::ComponentTypeFromRenderTarget;
28using ComponentType = SurfaceParams::ComponentType; 29using VideoCore::Surface::ComponentTypeFromTexture;
30using VideoCore::Surface::PixelFormatFromDepthFormat;
31using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
32using VideoCore::Surface::PixelFormatFromTextureFormat;
33using VideoCore::Surface::SurfaceTargetFromTextureType;
29 34
30struct FormatTuple { 35struct FormatTuple {
31 GLint internal_format; 36 GLint internal_format;
@@ -35,46 +40,6 @@ struct FormatTuple {
35 bool compressed; 40 bool compressed;
36}; 41};
37 42
38static bool IsPixelFormatASTC(PixelFormat format) {
39 switch (format) {
40 case PixelFormat::ASTC_2D_4X4:
41 case PixelFormat::ASTC_2D_5X4:
42 case PixelFormat::ASTC_2D_8X8:
43 case PixelFormat::ASTC_2D_8X5:
44 case PixelFormat::ASTC_2D_4X4_SRGB:
45 case PixelFormat::ASTC_2D_5X4_SRGB:
46 case PixelFormat::ASTC_2D_8X8_SRGB:
47 case PixelFormat::ASTC_2D_8X5_SRGB:
48 return true;
49 default:
50 return false;
51 }
52}
53
54static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
55 switch (format) {
56 case PixelFormat::ASTC_2D_4X4:
57 return {4, 4};
58 case PixelFormat::ASTC_2D_5X4:
59 return {5, 4};
60 case PixelFormat::ASTC_2D_8X8:
61 return {8, 8};
62 case PixelFormat::ASTC_2D_8X5:
63 return {8, 5};
64 case PixelFormat::ASTC_2D_4X4_SRGB:
65 return {4, 4};
66 case PixelFormat::ASTC_2D_5X4_SRGB:
67 return {5, 4};
68 case PixelFormat::ASTC_2D_8X8_SRGB:
69 return {8, 8};
70 case PixelFormat::ASTC_2D_8X5_SRGB:
71 return {8, 5};
72 default:
73 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
74 UNREACHABLE();
75 }
76}
77
78void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) { 43void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
79 auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()}; 44 auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
80 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)}; 45 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)};
@@ -267,7 +232,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
267 return params; 232 return params;
268} 233}
269 234
270static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{ 235static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{
271 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U 236 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
272 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S 237 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
273 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI 238 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI
@@ -355,19 +320,19 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
355 ComponentType::Float, false}, // Z32FS8 320 ComponentType::Float, false}, // Z32FS8
356}}; 321}};
357 322
358static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) { 323static GLenum SurfaceTargetToGL(SurfaceTarget target) {
359 switch (target) { 324 switch (target) {
360 case SurfaceParams::SurfaceTarget::Texture1D: 325 case SurfaceTarget::Texture1D:
361 return GL_TEXTURE_1D; 326 return GL_TEXTURE_1D;
362 case SurfaceParams::SurfaceTarget::Texture2D: 327 case SurfaceTarget::Texture2D:
363 return GL_TEXTURE_2D; 328 return GL_TEXTURE_2D;
364 case SurfaceParams::SurfaceTarget::Texture3D: 329 case SurfaceTarget::Texture3D:
365 return GL_TEXTURE_3D; 330 return GL_TEXTURE_3D;
366 case SurfaceParams::SurfaceTarget::Texture1DArray: 331 case SurfaceTarget::Texture1DArray:
367 return GL_TEXTURE_1D_ARRAY; 332 return GL_TEXTURE_1D_ARRAY;
368 case SurfaceParams::SurfaceTarget::Texture2DArray: 333 case SurfaceTarget::Texture2DArray:
369 return GL_TEXTURE_2D_ARRAY; 334 return GL_TEXTURE_2D_ARRAY;
370 case SurfaceParams::SurfaceTarget::TextureCubemap: 335 case SurfaceTarget::TextureCubemap:
371 return GL_TEXTURE_CUBE_MAP; 336 return GL_TEXTURE_CUBE_MAP;
372 } 337 }
373 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); 338 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
@@ -392,31 +357,10 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
392 return {0, actual_height, MipWidth(mip_level), 0}; 357 return {0, actual_height, MipWidth(mip_level), 0};
393} 358}
394 359
395/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
396static bool IsFormatBCn(PixelFormat format) {
397 switch (format) {
398 case PixelFormat::DXT1:
399 case PixelFormat::DXT23:
400 case PixelFormat::DXT45:
401 case PixelFormat::DXN1:
402 case PixelFormat::DXN2SNORM:
403 case PixelFormat::DXN2UNORM:
404 case PixelFormat::BC7U:
405 case PixelFormat::BC6H_UF16:
406 case PixelFormat::BC6H_SF16:
407 case PixelFormat::DXT1_SRGB:
408 case PixelFormat::DXT23_SRGB:
409 case PixelFormat::DXT45_SRGB:
410 case PixelFormat::BC7U_SRGB:
411 return true;
412 }
413 return false;
414}
415
416template <bool morton_to_gl, PixelFormat format> 360template <bool morton_to_gl, PixelFormat format>
417void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer, 361void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
418 std::size_t gl_buffer_size, VAddr addr) { 362 std::size_t gl_buffer_size, VAddr addr) {
419 constexpr u32 bytes_per_pixel = SurfaceParams::GetBytesPerPixel(format); 363 constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
420 364
421 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual 365 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
422 // pixel values. 366 // pixel values.
@@ -435,7 +379,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
435} 379}
436 380
437using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr), 381using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
438 SurfaceParams::MaxPixelFormat>; 382 VideoCore::Surface::MaxPixelFormat>;
439 383
440static constexpr GLConversionArray morton_to_gl_fns = { 384static constexpr GLConversionArray morton_to_gl_fns = {
441 // clang-format off 385 // clang-format off
@@ -575,7 +519,7 @@ static constexpr GLConversionArray gl_to_morton_fns = {
575void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, 519void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
576 std::vector<u8>& gl_buffer, u32 mip_level) { 520 std::vector<u8>& gl_buffer, u32 mip_level) {
577 u32 depth = params.MipDepth(mip_level); 521 u32 depth = params.MipDepth(mip_level);
578 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { 522 if (params.target == SurfaceTarget::Texture2D) {
579 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented. 523 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
580 depth = 1U; 524 depth = 1U;
581 } 525 }
@@ -622,13 +566,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
622 566
623 if (src_params.type == SurfaceType::ColorTexture) { 567 if (src_params.type == SurfaceType::ColorTexture) {
624 switch (src_params.target) { 568 switch (src_params.target) {
625 case SurfaceParams::SurfaceTarget::Texture2D: 569 case SurfaceTarget::Texture2D:
626 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, 570 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
627 GL_TEXTURE_2D, src_surface->Texture().handle, 0); 571 GL_TEXTURE_2D, src_surface->Texture().handle, 0);
628 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 572 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
629 0, 0); 573 0, 0);
630 break; 574 break;
631 case SurfaceParams::SurfaceTarget::TextureCubemap: 575 case SurfaceTarget::TextureCubemap:
632 glFramebufferTexture2D( 576 glFramebufferTexture2D(
633 GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, 577 GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
634 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 578 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
@@ -637,12 +581,12 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
637 GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 581 GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
638 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); 582 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
639 break; 583 break;
640 case SurfaceParams::SurfaceTarget::Texture2DArray: 584 case SurfaceTarget::Texture2DArray:
641 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, 585 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
642 src_surface->Texture().handle, 0, 0); 586 src_surface->Texture().handle, 0, 0);
643 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); 587 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
644 break; 588 break;
645 case SurfaceParams::SurfaceTarget::Texture3D: 589 case SurfaceTarget::Texture3D:
646 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, 590 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
647 SurfaceTargetToGL(src_params.target), 591 SurfaceTargetToGL(src_params.target),
648 src_surface->Texture().handle, 0, 0); 592 src_surface->Texture().handle, 0, 0);
@@ -658,13 +602,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
658 } 602 }
659 603
660 switch (dst_params.target) { 604 switch (dst_params.target) {
661 case SurfaceParams::SurfaceTarget::Texture2D: 605 case SurfaceTarget::Texture2D:
662 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, 606 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
663 GL_TEXTURE_2D, dst_surface->Texture().handle, 0); 607 GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
664 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 608 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
665 0, 0); 609 0, 0);
666 break; 610 break;
667 case SurfaceParams::SurfaceTarget::TextureCubemap: 611 case SurfaceTarget::TextureCubemap:
668 glFramebufferTexture2D( 612 glFramebufferTexture2D(
669 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, 613 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
670 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 614 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
@@ -673,13 +617,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
673 GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 617 GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
674 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); 618 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
675 break; 619 break;
676 case SurfaceParams::SurfaceTarget::Texture2DArray: 620 case SurfaceTarget::Texture2DArray:
677 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, 621 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
678 dst_surface->Texture().handle, 0, 0); 622 dst_surface->Texture().handle, 0, 0);
679 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); 623 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
680 break; 624 break;
681 625
682 case SurfaceParams::SurfaceTarget::Texture3D: 626 case SurfaceTarget::Texture3D:
683 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, 627 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
684 SurfaceTargetToGL(dst_params.target), 628 SurfaceTargetToGL(dst_params.target),
685 dst_surface->Texture().handle, 0, 0); 629 dst_surface->Texture().handle, 0, 0);
@@ -800,21 +744,21 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
800 UNREACHABLE(); 744 UNREACHABLE();
801 } else { 745 } else {
802 switch (dst_params.target) { 746 switch (dst_params.target) {
803 case SurfaceParams::SurfaceTarget::Texture1D: 747 case SurfaceTarget::Texture1D:
804 glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format, 748 glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format,
805 dest_format.type, nullptr); 749 dest_format.type, nullptr);
806 break; 750 break;
807 case SurfaceParams::SurfaceTarget::Texture2D: 751 case SurfaceTarget::Texture2D:
808 glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height, 752 glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height,
809 dest_format.format, dest_format.type, nullptr); 753 dest_format.format, dest_format.type, nullptr);
810 break; 754 break;
811 case SurfaceParams::SurfaceTarget::Texture3D: 755 case SurfaceTarget::Texture3D:
812 case SurfaceParams::SurfaceTarget::Texture2DArray: 756 case SurfaceTarget::Texture2DArray:
813 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height, 757 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height,
814 static_cast<GLsizei>(dst_params.depth), dest_format.format, 758 static_cast<GLsizei>(dst_params.depth), dest_format.format,
815 dest_format.type, nullptr); 759 dest_format.type, nullptr);
816 break; 760 break;
817 case SurfaceParams::SurfaceTarget::TextureCubemap: 761 case SurfaceTarget::TextureCubemap:
818 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 762 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0,
819 static_cast<GLint>(cubemap_face), width, height, 1, 763 static_cast<GLint>(cubemap_face), width, height, 1,
820 dest_format.format, dest_format.type, nullptr); 764 dest_format.format, dest_format.type, nullptr);
@@ -851,17 +795,17 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
851 if (!format_tuple.compressed) { 795 if (!format_tuple.compressed) {
852 // Only pre-create the texture for non-compressed textures. 796 // Only pre-create the texture for non-compressed textures.
853 switch (params.target) { 797 switch (params.target) {
854 case SurfaceParams::SurfaceTarget::Texture1D: 798 case SurfaceTarget::Texture1D:
855 glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level, 799 glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
856 format_tuple.internal_format, rect.GetWidth()); 800 format_tuple.internal_format, rect.GetWidth());
857 break; 801 break;
858 case SurfaceParams::SurfaceTarget::Texture2D: 802 case SurfaceTarget::Texture2D:
859 case SurfaceParams::SurfaceTarget::TextureCubemap: 803 case SurfaceTarget::TextureCubemap:
860 glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level, 804 glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
861 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight()); 805 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
862 break; 806 break;
863 case SurfaceParams::SurfaceTarget::Texture3D: 807 case SurfaceTarget::Texture3D:
864 case SurfaceParams::SurfaceTarget::Texture2DArray: 808 case SurfaceTarget::Texture2DArray:
865 glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level, 809 glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
866 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(), 810 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
867 params.depth); 811 params.depth);
@@ -916,7 +860,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
916 860
917 S8Z24 s8z24_pixel{}; 861 S8Z24 s8z24_pixel{};
918 Z24S8 z24s8_pixel{}; 862 Z24S8 z24s8_pixel{};
919 constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::S8Z24)}; 863 constexpr auto bpp{GetBytesPerPixel(PixelFormat::S8Z24)};
920 for (std::size_t y = 0; y < height; ++y) { 864 for (std::size_t y = 0; y < height; ++y) {
921 for (std::size_t x = 0; x < width; ++x) { 865 for (std::size_t x = 0; x < width; ++x) {
922 const std::size_t offset{bpp * (y * width + x)}; 866 const std::size_t offset{bpp * (y * width + x)};
@@ -936,7 +880,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
936} 880}
937 881
938static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { 882static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
939 constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::G8R8U)}; 883 constexpr auto bpp{GetBytesPerPixel(PixelFormat::G8R8U)};
940 for (std::size_t y = 0; y < height; ++y) { 884 for (std::size_t y = 0; y < height; ++y) {
941 for (std::size_t x = 0; x < width; ++x) { 885 for (std::size_t x = 0; x < width; ++x) {
942 const std::size_t offset{bpp * (y * width + x)}; 886 const std::size_t offset{bpp * (y * width + x)};
@@ -1042,7 +986,7 @@ void CachedSurface::FlushGLBuffer() {
1042 986
1043 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 987 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
1044 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 988 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
1045 ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); 989 ASSERT(params.width * GetBytesPerPixel(params.pixel_format) % 4 == 0);
1046 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); 990 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
1047 ASSERT(!tuple.compressed); 991 ASSERT(!tuple.compressed);
1048 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 992 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
@@ -1074,7 +1018,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1074 std::size_t buffer_offset = 1018 std::size_t buffer_offset =
1075 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) + 1019 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
1076 static_cast<std::size_t>(x0)) * 1020 static_cast<std::size_t>(x0)) *
1077 SurfaceParams::GetBytesPerPixel(params.pixel_format); 1021 GetBytesPerPixel(params.pixel_format);
1078 1022
1079 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 1023 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
1080 const GLuint target_tex = texture.handle; 1024 const GLuint target_tex = texture.handle;
@@ -1090,35 +1034,34 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1090 cur_state.Apply(); 1034 cur_state.Apply();
1091 1035
1092 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 1036 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
1093 ASSERT(params.MipWidth(mip_map) * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 1037 ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0);
1094 0);
1095 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map))); 1038 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
1096 1039
1097 GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false)); 1040 GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
1098 glActiveTexture(GL_TEXTURE0); 1041 glActiveTexture(GL_TEXTURE0);
1099 if (tuple.compressed) { 1042 if (tuple.compressed) {
1100 switch (params.target) { 1043 switch (params.target) {
1101 case SurfaceParams::SurfaceTarget::Texture2D: 1044 case SurfaceTarget::Texture2D:
1102 glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, 1045 glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1103 static_cast<GLsizei>(params.MipWidth(mip_map)), 1046 static_cast<GLsizei>(params.MipWidth(mip_map)),
1104 static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size, 1047 static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
1105 &gl_buffer[mip_map][buffer_offset]); 1048 &gl_buffer[mip_map][buffer_offset]);
1106 break; 1049 break;
1107 case SurfaceParams::SurfaceTarget::Texture3D: 1050 case SurfaceTarget::Texture3D:
1108 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, 1051 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1109 static_cast<GLsizei>(params.MipWidth(mip_map)), 1052 static_cast<GLsizei>(params.MipWidth(mip_map)),
1110 static_cast<GLsizei>(params.MipHeight(mip_map)), 1053 static_cast<GLsizei>(params.MipHeight(mip_map)),
1111 static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size, 1054 static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
1112 &gl_buffer[mip_map][buffer_offset]); 1055 &gl_buffer[mip_map][buffer_offset]);
1113 break; 1056 break;
1114 case SurfaceParams::SurfaceTarget::Texture2DArray: 1057 case SurfaceTarget::Texture2DArray:
1115 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, 1058 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1116 static_cast<GLsizei>(params.MipWidth(mip_map)), 1059 static_cast<GLsizei>(params.MipWidth(mip_map)),
1117 static_cast<GLsizei>(params.MipHeight(mip_map)), 1060 static_cast<GLsizei>(params.MipHeight(mip_map)),
1118 static_cast<GLsizei>(params.depth), 0, image_size, 1061 static_cast<GLsizei>(params.depth), 0, image_size,
1119 &gl_buffer[mip_map][buffer_offset]); 1062 &gl_buffer[mip_map][buffer_offset]);
1120 break; 1063 break;
1121 case SurfaceParams::SurfaceTarget::TextureCubemap: { 1064 case SurfaceTarget::TextureCubemap: {
1122 GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map)); 1065 GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
1123 for (std::size_t face = 0; face < params.depth; ++face) { 1066 for (std::size_t face = 0; face < params.depth; ++face) {
1124 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 1067 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
@@ -1143,30 +1086,30 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1143 } else { 1086 } else {
1144 1087
1145 switch (params.target) { 1088 switch (params.target) {
1146 case SurfaceParams::SurfaceTarget::Texture1D: 1089 case SurfaceTarget::Texture1D:
1147 glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0, 1090 glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
1148 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, 1091 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
1149 &gl_buffer[mip_map][buffer_offset]); 1092 &gl_buffer[mip_map][buffer_offset]);
1150 break; 1093 break;
1151 case SurfaceParams::SurfaceTarget::Texture2D: 1094 case SurfaceTarget::Texture2D:
1152 glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 1095 glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
1153 static_cast<GLsizei>(rect.GetWidth()), 1096 static_cast<GLsizei>(rect.GetWidth()),
1154 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1097 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1155 &gl_buffer[mip_map][buffer_offset]); 1098 &gl_buffer[mip_map][buffer_offset]);
1156 break; 1099 break;
1157 case SurfaceParams::SurfaceTarget::Texture3D: 1100 case SurfaceTarget::Texture3D:
1158 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, 1101 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1159 static_cast<GLsizei>(rect.GetWidth()), 1102 static_cast<GLsizei>(rect.GetWidth()),
1160 static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map), 1103 static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
1161 tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]); 1104 tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
1162 break; 1105 break;
1163 case SurfaceParams::SurfaceTarget::Texture2DArray: 1106 case SurfaceTarget::Texture2DArray:
1164 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, 1107 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1165 static_cast<GLsizei>(rect.GetWidth()), 1108 static_cast<GLsizei>(rect.GetWidth()),
1166 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, 1109 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
1167 tuple.type, &gl_buffer[mip_map][buffer_offset]); 1110 tuple.type, &gl_buffer[mip_map][buffer_offset]);
1168 break; 1111 break;
1169 case SurfaceParams::SurfaceTarget::TextureCubemap: { 1112 case SurfaceTarget::TextureCubemap: {
1170 std::size_t start = buffer_offset; 1113 std::size_t start = buffer_offset;
1171 for (std::size_t face = 0; face < params.depth; ++face) { 1114 for (std::size_t face = 0; face < params.depth; ++face) {
1172 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map, 1115 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
@@ -1341,8 +1284,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1341 // For compatible surfaces, we can just do fast glCopyImageSubData based copy 1284 // For compatible surfaces, we can just do fast glCopyImageSubData based copy
1342 if (old_params.target == new_params.target && old_params.type == new_params.type && 1285 if (old_params.target == new_params.target && old_params.type == new_params.type &&
1343 old_params.depth == new_params.depth && old_params.depth == 1 && 1286 old_params.depth == new_params.depth && old_params.depth == 1 &&
1344 SurfaceParams::GetFormatBpp(old_params.pixel_format) == 1287 GetFormatBpp(old_params.pixel_format) == GetFormatBpp(new_params.pixel_format)) {
1345 SurfaceParams::GetFormatBpp(new_params.pixel_format)) {
1346 FastCopySurface(old_surface, new_surface); 1288 FastCopySurface(old_surface, new_surface);
1347 return new_surface; 1289 return new_surface;
1348 } 1290 }
@@ -1355,13 +1297,14 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1355 const bool is_blit{old_params.pixel_format == new_params.pixel_format}; 1297 const bool is_blit{old_params.pixel_format == new_params.pixel_format};
1356 1298
1357 switch (new_params.target) { 1299 switch (new_params.target) {
1358 case SurfaceParams::SurfaceTarget::Texture2D: 1300 case SurfaceTarget::Texture2D:
1359 if (is_blit) { 1301 if (is_blit) {
1360 BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle); 1302 BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
1361 } else { 1303 } else {
1362 CopySurface(old_surface, new_surface, copy_pbo.handle); 1304 CopySurface(old_surface, new_surface, copy_pbo.handle);
1363 } 1305 }
1364 break; 1306 break;
1307
1365 case SurfaceParams::SurfaceTarget::TextureCubemap: 1308 case SurfaceParams::SurfaceTarget::TextureCubemap:
1366 case SurfaceParams::SurfaceTarget::Texture3D: 1309 case SurfaceParams::SurfaceTarget::Texture3D:
1367 case SurfaceParams::SurfaceTarget::Texture2DArray: 1310 case SurfaceParams::SurfaceTarget::Texture2DArray:
@@ -1374,7 +1317,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1374 } 1317 }
1375 1318
1376 return new_surface; 1319 return new_surface;
1377} // namespace OpenGL 1320}
1378 1321
1379Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const { 1322Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const {
1380 return TryGet(addr); 1323 return TryGet(addr);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index e72f4f2d2..f255f4419 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <map> 8#include <map>
9#include <memory> 9#include <memory>
10#include <string>
10#include <vector> 11#include <vector>
11 12
12#include "common/alignment.h" 13#include "common/alignment.h"
@@ -18,6 +19,7 @@
18#include "video_core/rasterizer_cache.h" 19#include "video_core/rasterizer_cache.h"
19#include "video_core/renderer_opengl/gl_resource_manager.h" 20#include "video_core/renderer_opengl/gl_resource_manager.h"
20#include "video_core/renderer_opengl/gl_shader_gen.h" 21#include "video_core/renderer_opengl/gl_shader_gen.h"
22#include "video_core/surface.h"
21#include "video_core/textures/decoders.h" 23#include "video_core/textures/decoders.h"
22#include "video_core/textures/texture.h" 24#include "video_core/textures/texture.h"
23 25
@@ -27,135 +29,12 @@ class CachedSurface;
27using Surface = std::shared_ptr<CachedSurface>; 29using Surface = std::shared_ptr<CachedSurface>;
28using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; 30using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
29 31
30struct SurfaceParams { 32using SurfaceTarget = VideoCore::Surface::SurfaceTarget;
31 enum class PixelFormat { 33using SurfaceType = VideoCore::Surface::SurfaceType;
32 ABGR8U = 0, 34using PixelFormat = VideoCore::Surface::PixelFormat;
33 ABGR8S = 1, 35using ComponentType = VideoCore::Surface::ComponentType;
34 ABGR8UI = 2,
35 B5G6R5U = 3,
36 A2B10G10R10U = 4,
37 A1B5G5R5U = 5,
38 R8U = 6,
39 R8UI = 7,
40 RGBA16F = 8,
41 RGBA16U = 9,
42 RGBA16UI = 10,
43 R11FG11FB10F = 11,
44 RGBA32UI = 12,
45 DXT1 = 13,
46 DXT23 = 14,
47 DXT45 = 15,
48 DXN1 = 16, // This is also known as BC4
49 DXN2UNORM = 17,
50 DXN2SNORM = 18,
51 BC7U = 19,
52 BC6H_UF16 = 20,
53 BC6H_SF16 = 21,
54 ASTC_2D_4X4 = 22,
55 G8R8U = 23,
56 G8R8S = 24,
57 BGRA8 = 25,
58 RGBA32F = 26,
59 RG32F = 27,
60 R32F = 28,
61 R16F = 29,
62 R16U = 30,
63 R16S = 31,
64 R16UI = 32,
65 R16I = 33,
66 RG16 = 34,
67 RG16F = 35,
68 RG16UI = 36,
69 RG16I = 37,
70 RG16S = 38,
71 RGB32F = 39,
72 RGBA8_SRGB = 40,
73 RG8U = 41,
74 RG8S = 42,
75 RG32UI = 43,
76 R32UI = 44,
77 ASTC_2D_8X8 = 45,
78 ASTC_2D_8X5 = 46,
79 ASTC_2D_5X4 = 47,
80 BGRA8_SRGB = 48,
81 DXT1_SRGB = 49,
82 DXT23_SRGB = 50,
83 DXT45_SRGB = 51,
84 BC7U_SRGB = 52,
85 ASTC_2D_4X4_SRGB = 53,
86 ASTC_2D_8X8_SRGB = 54,
87 ASTC_2D_8X5_SRGB = 55,
88 ASTC_2D_5X4_SRGB = 56,
89
90 MaxColorFormat,
91
92 // Depth formats
93 Z32F = 57,
94 Z16 = 58,
95
96 MaxDepthFormat,
97
98 // DepthStencil formats
99 Z24S8 = 59,
100 S8Z24 = 60,
101 Z32FS8 = 61,
102
103 MaxDepthStencilFormat,
104
105 Max = MaxDepthStencilFormat,
106 Invalid = 255,
107 };
108
109 static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
110
111 enum class ComponentType {
112 Invalid = 0,
113 SNorm = 1,
114 UNorm = 2,
115 SInt = 3,
116 UInt = 4,
117 Float = 5,
118 };
119
120 enum class SurfaceType {
121 ColorTexture = 0,
122 Depth = 1,
123 DepthStencil = 2,
124 Fill = 3,
125 Invalid = 4,
126 };
127
128 enum class SurfaceTarget {
129 Texture1D,
130 Texture2D,
131 Texture3D,
132 Texture1DArray,
133 Texture2DArray,
134 TextureCubemap,
135 };
136
137 static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
138 switch (texture_type) {
139 case Tegra::Texture::TextureType::Texture1D:
140 return SurfaceTarget::Texture1D;
141 case Tegra::Texture::TextureType::Texture2D:
142 case Tegra::Texture::TextureType::Texture2DNoMipmap:
143 return SurfaceTarget::Texture2D;
144 case Tegra::Texture::TextureType::Texture3D:
145 return SurfaceTarget::Texture3D;
146 case Tegra::Texture::TextureType::TextureCubemap:
147 return SurfaceTarget::TextureCubemap;
148 case Tegra::Texture::TextureType::Texture1DArray:
149 return SurfaceTarget::Texture1DArray;
150 case Tegra::Texture::TextureType::Texture2DArray:
151 return SurfaceTarget::Texture2DArray;
152 default:
153 LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
154 UNREACHABLE();
155 return SurfaceTarget::Texture2D;
156 }
157 }
158 36
37struct SurfaceParams {
159 static std::string SurfaceTargetName(SurfaceTarget target) { 38 static std::string SurfaceTargetName(SurfaceTarget target) {
160 switch (target) { 39 switch (target) {
161 case SurfaceTarget::Texture1D: 40 case SurfaceTarget::Texture1D:
@@ -177,660 +56,8 @@ struct SurfaceParams {
177 } 56 }
178 } 57 }
179 58
180 static bool SurfaceTargetIsLayered(SurfaceTarget target) {
181 switch (target) {
182 case SurfaceTarget::Texture1D:
183 case SurfaceTarget::Texture2D:
184 case SurfaceTarget::Texture3D:
185 return false;
186 case SurfaceTarget::Texture1DArray:
187 case SurfaceTarget::Texture2DArray:
188 case SurfaceTarget::TextureCubemap:
189 return true;
190 default:
191 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
192 UNREACHABLE();
193 return false;
194 }
195 }
196
197 /**
198 * Gets the compression factor for the specified PixelFormat. This applies to just the
199 * "compressed width" and "compressed height", not the overall compression factor of a
200 * compressed image. This is used for maintaining proper surface sizes for compressed
201 * texture formats.
202 */
203 static constexpr u32 GetCompressionFactor(PixelFormat format) {
204 if (format == PixelFormat::Invalid)
205 return 0;
206
207 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
208 1, // ABGR8U
209 1, // ABGR8S
210 1, // ABGR8UI
211 1, // B5G6R5U
212 1, // A2B10G10R10U
213 1, // A1B5G5R5U
214 1, // R8U
215 1, // R8UI
216 1, // RGBA16F
217 1, // RGBA16U
218 1, // RGBA16UI
219 1, // R11FG11FB10F
220 1, // RGBA32UI
221 4, // DXT1
222 4, // DXT23
223 4, // DXT45
224 4, // DXN1
225 4, // DXN2UNORM
226 4, // DXN2SNORM
227 4, // BC7U
228 4, // BC6H_UF16
229 4, // BC6H_SF16
230 4, // ASTC_2D_4X4
231 1, // G8R8U
232 1, // G8R8S
233 1, // BGRA8
234 1, // RGBA32F
235 1, // RG32F
236 1, // R32F
237 1, // R16F
238 1, // R16U
239 1, // R16S
240 1, // R16UI
241 1, // R16I
242 1, // RG16
243 1, // RG16F
244 1, // RG16UI
245 1, // RG16I
246 1, // RG16S
247 1, // RGB32F
248 1, // RGBA8_SRGB
249 1, // RG8U
250 1, // RG8S
251 1, // RG32UI
252 1, // R32UI
253 4, // ASTC_2D_8X8
254 4, // ASTC_2D_8X5
255 4, // ASTC_2D_5X4
256 1, // BGRA8_SRGB
257 4, // DXT1_SRGB
258 4, // DXT23_SRGB
259 4, // DXT45_SRGB
260 4, // BC7U_SRGB
261 4, // ASTC_2D_4X4_SRGB
262 4, // ASTC_2D_8X8_SRGB
263 4, // ASTC_2D_8X5_SRGB
264 4, // ASTC_2D_5X4_SRGB
265 1, // Z32F
266 1, // Z16
267 1, // Z24S8
268 1, // S8Z24
269 1, // Z32FS8
270 }};
271
272 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
273 return compression_factor_table[static_cast<std::size_t>(format)];
274 }
275
276 static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
277 if (format == PixelFormat::Invalid)
278 return 0;
279 constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
280 1, // ABGR8U
281 1, // ABGR8S
282 1, // ABGR8UI
283 1, // B5G6R5U
284 1, // A2B10G10R10U
285 1, // A1B5G5R5U
286 1, // R8U
287 1, // R8UI
288 1, // RGBA16F
289 1, // RGBA16U
290 1, // RGBA16UI
291 1, // R11FG11FB10F
292 1, // RGBA32UI
293 4, // DXT1
294 4, // DXT23
295 4, // DXT45
296 4, // DXN1
297 4, // DXN2UNORM
298 4, // DXN2SNORM
299 4, // BC7U
300 4, // BC6H_UF16
301 4, // BC6H_SF16
302 4, // ASTC_2D_4X4
303 1, // G8R8U
304 1, // G8R8S
305 1, // BGRA8
306 1, // RGBA32F
307 1, // RG32F
308 1, // R32F
309 1, // R16F
310 1, // R16U
311 1, // R16S
312 1, // R16UI
313 1, // R16I
314 1, // RG16
315 1, // RG16F
316 1, // RG16UI
317 1, // RG16I
318 1, // RG16S
319 1, // RGB32F
320 1, // RGBA8_SRGB
321 1, // RG8U
322 1, // RG8S
323 1, // RG32UI
324 1, // R32UI
325 8, // ASTC_2D_8X8
326 5, // ASTC_2D_8X5
327 4, // ASTC_2D_5X4
328 1, // BGRA8_SRGB
329 4, // DXT1_SRGB
330 4, // DXT23_SRGB
331 4, // DXT45_SRGB
332 4, // BC7U_SRGB
333 4, // ASTC_2D_4X4_SRGB
334 8, // ASTC_2D_8X8_SRGB
335 5, // ASTC_2D_8X5_SRGB
336 4, // ASTC_2D_5X4_SRGB
337 1, // Z32F
338 1, // Z16
339 1, // Z24S8
340 1, // S8Z24
341 1, // Z32FS8
342 }};
343 ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
344 return block_height_table[static_cast<std::size_t>(format)];
345 }
346
347 static constexpr u32 GetFormatBpp(PixelFormat format) {
348 if (format == PixelFormat::Invalid)
349 return 0;
350
351 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
352 32, // ABGR8U
353 32, // ABGR8S
354 32, // ABGR8UI
355 16, // B5G6R5U
356 32, // A2B10G10R10U
357 16, // A1B5G5R5U
358 8, // R8U
359 8, // R8UI
360 64, // RGBA16F
361 64, // RGBA16U
362 64, // RGBA16UI
363 32, // R11FG11FB10F
364 128, // RGBA32UI
365 64, // DXT1
366 128, // DXT23
367 128, // DXT45
368 64, // DXN1
369 128, // DXN2UNORM
370 128, // DXN2SNORM
371 128, // BC7U
372 128, // BC6H_UF16
373 128, // BC6H_SF16
374 32, // ASTC_2D_4X4
375 16, // G8R8U
376 16, // G8R8S
377 32, // BGRA8
378 128, // RGBA32F
379 64, // RG32F
380 32, // R32F
381 16, // R16F
382 16, // R16U
383 16, // R16S
384 16, // R16UI
385 16, // R16I
386 32, // RG16
387 32, // RG16F
388 32, // RG16UI
389 32, // RG16I
390 32, // RG16S
391 96, // RGB32F
392 32, // RGBA8_SRGB
393 16, // RG8U
394 16, // RG8S
395 64, // RG32UI
396 32, // R32UI
397 16, // ASTC_2D_8X8
398 16, // ASTC_2D_8X5
399 32, // ASTC_2D_5X4
400 32, // BGRA8_SRGB
401 64, // DXT1_SRGB
402 128, // DXT23_SRGB
403 128, // DXT45_SRGB
404 128, // BC7U
405 32, // ASTC_2D_4X4_SRGB
406 16, // ASTC_2D_8X8_SRGB
407 16, // ASTC_2D_8X5_SRGB
408 32, // ASTC_2D_5X4_SRGB
409 32, // Z32F
410 16, // Z16
411 32, // Z24S8
412 32, // S8Z24
413 64, // Z32FS8
414 }};
415
416 ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
417 return bpp_table[static_cast<std::size_t>(format)];
418 }
419
420 u32 GetFormatBpp() const { 59 u32 GetFormatBpp() const {
421 return GetFormatBpp(pixel_format); 60 return VideoCore::Surface::GetFormatBpp(pixel_format);
422 }
423
424 static PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
425 switch (format) {
426 case Tegra::DepthFormat::S8_Z24_UNORM:
427 return PixelFormat::S8Z24;
428 case Tegra::DepthFormat::Z24_S8_UNORM:
429 return PixelFormat::Z24S8;
430 case Tegra::DepthFormat::Z32_FLOAT:
431 return PixelFormat::Z32F;
432 case Tegra::DepthFormat::Z16_UNORM:
433 return PixelFormat::Z16;
434 case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
435 return PixelFormat::Z32FS8;
436 default:
437 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
438 UNREACHABLE();
439 }
440 }
441
442 static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
443 switch (format) {
444 // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
445 // gamma.
446 case Tegra::RenderTargetFormat::RGBA8_SRGB:
447 return PixelFormat::RGBA8_SRGB;
448 case Tegra::RenderTargetFormat::RGBA8_UNORM:
449 return PixelFormat::ABGR8U;
450 case Tegra::RenderTargetFormat::RGBA8_SNORM:
451 return PixelFormat::ABGR8S;
452 case Tegra::RenderTargetFormat::RGBA8_UINT:
453 return PixelFormat::ABGR8UI;
454 case Tegra::RenderTargetFormat::BGRA8_SRGB:
455 return PixelFormat::BGRA8_SRGB;
456 case Tegra::RenderTargetFormat::BGRA8_UNORM:
457 return PixelFormat::BGRA8;
458 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
459 return PixelFormat::A2B10G10R10U;
460 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
461 return PixelFormat::RGBA16F;
462 case Tegra::RenderTargetFormat::RGBA16_UNORM:
463 return PixelFormat::RGBA16U;
464 case Tegra::RenderTargetFormat::RGBA16_UINT:
465 return PixelFormat::RGBA16UI;
466 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
467 return PixelFormat::RGBA32F;
468 case Tegra::RenderTargetFormat::RG32_FLOAT:
469 return PixelFormat::RG32F;
470 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
471 return PixelFormat::R11FG11FB10F;
472 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
473 return PixelFormat::B5G6R5U;
474 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
475 return PixelFormat::A1B5G5R5U;
476 case Tegra::RenderTargetFormat::RGBA32_UINT:
477 return PixelFormat::RGBA32UI;
478 case Tegra::RenderTargetFormat::R8_UNORM:
479 return PixelFormat::R8U;
480 case Tegra::RenderTargetFormat::R8_UINT:
481 return PixelFormat::R8UI;
482 case Tegra::RenderTargetFormat::RG16_FLOAT:
483 return PixelFormat::RG16F;
484 case Tegra::RenderTargetFormat::RG16_UINT:
485 return PixelFormat::RG16UI;
486 case Tegra::RenderTargetFormat::RG16_SINT:
487 return PixelFormat::RG16I;
488 case Tegra::RenderTargetFormat::RG16_UNORM:
489 return PixelFormat::RG16;
490 case Tegra::RenderTargetFormat::RG16_SNORM:
491 return PixelFormat::RG16S;
492 case Tegra::RenderTargetFormat::RG8_UNORM:
493 return PixelFormat::RG8U;
494 case Tegra::RenderTargetFormat::RG8_SNORM:
495 return PixelFormat::RG8S;
496 case Tegra::RenderTargetFormat::R16_FLOAT:
497 return PixelFormat::R16F;
498 case Tegra::RenderTargetFormat::R16_UNORM:
499 return PixelFormat::R16U;
500 case Tegra::RenderTargetFormat::R16_SNORM:
501 return PixelFormat::R16S;
502 case Tegra::RenderTargetFormat::R16_UINT:
503 return PixelFormat::R16UI;
504 case Tegra::RenderTargetFormat::R16_SINT:
505 return PixelFormat::R16I;
506 case Tegra::RenderTargetFormat::R32_FLOAT:
507 return PixelFormat::R32F;
508 case Tegra::RenderTargetFormat::R32_UINT:
509 return PixelFormat::R32UI;
510 case Tegra::RenderTargetFormat::RG32_UINT:
511 return PixelFormat::RG32UI;
512 default:
513 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
514 UNREACHABLE();
515 }
516 }
517
518 static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
519 Tegra::Texture::ComponentType component_type,
520 bool is_srgb) {
521 // TODO(Subv): Properly implement this
522 switch (format) {
523 case Tegra::Texture::TextureFormat::A8R8G8B8:
524 if (is_srgb) {
525 return PixelFormat::RGBA8_SRGB;
526 }
527 switch (component_type) {
528 case Tegra::Texture::ComponentType::UNORM:
529 return PixelFormat::ABGR8U;
530 case Tegra::Texture::ComponentType::SNORM:
531 return PixelFormat::ABGR8S;
532 case Tegra::Texture::ComponentType::UINT:
533 return PixelFormat::ABGR8UI;
534 }
535 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
536 static_cast<u32>(component_type));
537 UNREACHABLE();
538 case Tegra::Texture::TextureFormat::B5G6R5:
539 switch (component_type) {
540 case Tegra::Texture::ComponentType::UNORM:
541 return PixelFormat::B5G6R5U;
542 }
543 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
544 static_cast<u32>(component_type));
545 UNREACHABLE();
546 case Tegra::Texture::TextureFormat::A2B10G10R10:
547 switch (component_type) {
548 case Tegra::Texture::ComponentType::UNORM:
549 return PixelFormat::A2B10G10R10U;
550 }
551 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
552 static_cast<u32>(component_type));
553 UNREACHABLE();
554 case Tegra::Texture::TextureFormat::A1B5G5R5:
555 switch (component_type) {
556 case Tegra::Texture::ComponentType::UNORM:
557 return PixelFormat::A1B5G5R5U;
558 }
559 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
560 static_cast<u32>(component_type));
561 UNREACHABLE();
562 case Tegra::Texture::TextureFormat::R8:
563 switch (component_type) {
564 case Tegra::Texture::ComponentType::UNORM:
565 return PixelFormat::R8U;
566 case Tegra::Texture::ComponentType::UINT:
567 return PixelFormat::R8UI;
568 }
569 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
570 static_cast<u32>(component_type));
571 UNREACHABLE();
572 case Tegra::Texture::TextureFormat::G8R8:
573 switch (component_type) {
574 case Tegra::Texture::ComponentType::UNORM:
575 return PixelFormat::G8R8U;
576 case Tegra::Texture::ComponentType::SNORM:
577 return PixelFormat::G8R8S;
578 }
579 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
580 static_cast<u32>(component_type));
581 UNREACHABLE();
582 case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
583 switch (component_type) {
584 case Tegra::Texture::ComponentType::UNORM:
585 return PixelFormat::RGBA16U;
586 case Tegra::Texture::ComponentType::FLOAT:
587 return PixelFormat::RGBA16F;
588 }
589 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
590 static_cast<u32>(component_type));
591 UNREACHABLE();
592 case Tegra::Texture::TextureFormat::BF10GF11RF11:
593 switch (component_type) {
594 case Tegra::Texture::ComponentType::FLOAT:
595 return PixelFormat::R11FG11FB10F;
596 }
597 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
598 static_cast<u32>(component_type));
599 UNREACHABLE();
600 case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
601 switch (component_type) {
602 case Tegra::Texture::ComponentType::FLOAT:
603 return PixelFormat::RGBA32F;
604 case Tegra::Texture::ComponentType::UINT:
605 return PixelFormat::RGBA32UI;
606 }
607 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
608 static_cast<u32>(component_type));
609 UNREACHABLE();
610 case Tegra::Texture::TextureFormat::R32_G32:
611 switch (component_type) {
612 case Tegra::Texture::ComponentType::FLOAT:
613 return PixelFormat::RG32F;
614 case Tegra::Texture::ComponentType::UINT:
615 return PixelFormat::RG32UI;
616 }
617 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
618 static_cast<u32>(component_type));
619 UNREACHABLE();
620 case Tegra::Texture::TextureFormat::R32_G32_B32:
621 switch (component_type) {
622 case Tegra::Texture::ComponentType::FLOAT:
623 return PixelFormat::RGB32F;
624 }
625 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
626 static_cast<u32>(component_type));
627 UNREACHABLE();
628 case Tegra::Texture::TextureFormat::R16:
629 switch (component_type) {
630 case Tegra::Texture::ComponentType::FLOAT:
631 return PixelFormat::R16F;
632 case Tegra::Texture::ComponentType::UNORM:
633 return PixelFormat::R16U;
634 case Tegra::Texture::ComponentType::SNORM:
635 return PixelFormat::R16S;
636 case Tegra::Texture::ComponentType::UINT:
637 return PixelFormat::R16UI;
638 case Tegra::Texture::ComponentType::SINT:
639 return PixelFormat::R16I;
640 }
641 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
642 static_cast<u32>(component_type));
643 UNREACHABLE();
644 case Tegra::Texture::TextureFormat::R32:
645 switch (component_type) {
646 case Tegra::Texture::ComponentType::FLOAT:
647 return PixelFormat::R32F;
648 case Tegra::Texture::ComponentType::UINT:
649 return PixelFormat::R32UI;
650 }
651 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
652 static_cast<u32>(component_type));
653 UNREACHABLE();
654 case Tegra::Texture::TextureFormat::ZF32:
655 return PixelFormat::Z32F;
656 case Tegra::Texture::TextureFormat::Z16:
657 return PixelFormat::Z16;
658 case Tegra::Texture::TextureFormat::Z24S8:
659 return PixelFormat::Z24S8;
660 case Tegra::Texture::TextureFormat::DXT1:
661 return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
662 case Tegra::Texture::TextureFormat::DXT23:
663 return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
664 case Tegra::Texture::TextureFormat::DXT45:
665 return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
666 case Tegra::Texture::TextureFormat::DXN1:
667 return PixelFormat::DXN1;
668 case Tegra::Texture::TextureFormat::DXN2:
669 switch (component_type) {
670 case Tegra::Texture::ComponentType::UNORM:
671 return PixelFormat::DXN2UNORM;
672 case Tegra::Texture::ComponentType::SNORM:
673 return PixelFormat::DXN2SNORM;
674 }
675 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
676 static_cast<u32>(component_type));
677 UNREACHABLE();
678 case Tegra::Texture::TextureFormat::BC7U:
679 return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
680 case Tegra::Texture::TextureFormat::BC6H_UF16:
681 return PixelFormat::BC6H_UF16;
682 case Tegra::Texture::TextureFormat::BC6H_SF16:
683 return PixelFormat::BC6H_SF16;
684 case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
685 return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
686 case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
687 return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
688 case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
689 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
690 case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
691 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
692 case Tegra::Texture::TextureFormat::R16_G16:
693 switch (component_type) {
694 case Tegra::Texture::ComponentType::FLOAT:
695 return PixelFormat::RG16F;
696 case Tegra::Texture::ComponentType::UNORM:
697 return PixelFormat::RG16;
698 case Tegra::Texture::ComponentType::SNORM:
699 return PixelFormat::RG16S;
700 case Tegra::Texture::ComponentType::UINT:
701 return PixelFormat::RG16UI;
702 case Tegra::Texture::ComponentType::SINT:
703 return PixelFormat::RG16I;
704 }
705 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
706 static_cast<u32>(component_type));
707 UNREACHABLE();
708 default:
709 LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}",
710 static_cast<u32>(format), static_cast<u32>(component_type));
711 UNREACHABLE();
712 }
713 }
714
715 static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
716 // TODO(Subv): Implement more component types
717 switch (type) {
718 case Tegra::Texture::ComponentType::UNORM:
719 return ComponentType::UNorm;
720 case Tegra::Texture::ComponentType::FLOAT:
721 return ComponentType::Float;
722 case Tegra::Texture::ComponentType::SNORM:
723 return ComponentType::SNorm;
724 case Tegra::Texture::ComponentType::UINT:
725 return ComponentType::UInt;
726 case Tegra::Texture::ComponentType::SINT:
727 return ComponentType::SInt;
728 default:
729 LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
730 UNREACHABLE();
731 }
732 }
733
734 static ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
735 // TODO(Subv): Implement more render targets
736 switch (format) {
737 case Tegra::RenderTargetFormat::RGBA8_UNORM:
738 case Tegra::RenderTargetFormat::RGBA8_SRGB:
739 case Tegra::RenderTargetFormat::BGRA8_UNORM:
740 case Tegra::RenderTargetFormat::BGRA8_SRGB:
741 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
742 case Tegra::RenderTargetFormat::R8_UNORM:
743 case Tegra::RenderTargetFormat::RG16_UNORM:
744 case Tegra::RenderTargetFormat::R16_UNORM:
745 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
746 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
747 case Tegra::RenderTargetFormat::RG8_UNORM:
748 case Tegra::RenderTargetFormat::RGBA16_UNORM:
749 return ComponentType::UNorm;
750 case Tegra::RenderTargetFormat::RGBA8_SNORM:
751 case Tegra::RenderTargetFormat::RG16_SNORM:
752 case Tegra::RenderTargetFormat::R16_SNORM:
753 case Tegra::RenderTargetFormat::RG8_SNORM:
754 return ComponentType::SNorm;
755 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
756 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
757 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
758 case Tegra::RenderTargetFormat::RG32_FLOAT:
759 case Tegra::RenderTargetFormat::RG16_FLOAT:
760 case Tegra::RenderTargetFormat::R16_FLOAT:
761 case Tegra::RenderTargetFormat::R32_FLOAT:
762 return ComponentType::Float;
763 case Tegra::RenderTargetFormat::RGBA32_UINT:
764 case Tegra::RenderTargetFormat::RGBA16_UINT:
765 case Tegra::RenderTargetFormat::RG16_UINT:
766 case Tegra::RenderTargetFormat::R8_UINT:
767 case Tegra::RenderTargetFormat::R16_UINT:
768 case Tegra::RenderTargetFormat::RG32_UINT:
769 case Tegra::RenderTargetFormat::R32_UINT:
770 case Tegra::RenderTargetFormat::RGBA8_UINT:
771 return ComponentType::UInt;
772 case Tegra::RenderTargetFormat::RG16_SINT:
773 case Tegra::RenderTargetFormat::R16_SINT:
774 return ComponentType::SInt;
775 default:
776 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
777 UNREACHABLE();
778 }
779 }
780
781 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
782 switch (format) {
783 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
784 return PixelFormat::ABGR8U;
785 default:
786 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
787 UNREACHABLE();
788 }
789 }
790
791 static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
792 switch (format) {
793 case Tegra::DepthFormat::Z16_UNORM:
794 case Tegra::DepthFormat::S8_Z24_UNORM:
795 case Tegra::DepthFormat::Z24_S8_UNORM:
796 return ComponentType::UNorm;
797 case Tegra::DepthFormat::Z32_FLOAT:
798 case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
799 return ComponentType::Float;
800 default:
801 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
802 UNREACHABLE();
803 }
804 }
805
806 static SurfaceType GetFormatType(PixelFormat pixel_format) {
807 if (static_cast<std::size_t>(pixel_format) <
808 static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
809 return SurfaceType::ColorTexture;
810 }
811
812 if (static_cast<std::size_t>(pixel_format) <
813 static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
814 return SurfaceType::Depth;
815 }
816
817 if (static_cast<std::size_t>(pixel_format) <
818 static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
819 return SurfaceType::DepthStencil;
820 }
821
822 // TODO(Subv): Implement the other formats
823 ASSERT(false);
824
825 return SurfaceType::Invalid;
826 }
827
828 /// Returns the sizer in bytes of the specified pixel format
829 static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
830 if (pixel_format == SurfaceParams::PixelFormat::Invalid) {
831 return 0;
832 }
833 return GetFormatBpp(pixel_format) / CHAR_BIT;
834 } 61 }
835 62
836 /// Returns the rectangle corresponding to this surface 63 /// Returns the rectangle corresponding to this surface
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index d1f6ffe40..09b003c59 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -373,6 +373,7 @@ public:
373 if (sets_cc) { 373 if (sets_cc) {
374 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; 374 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
375 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); 375 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
376 LOG_WARNING(HW_GPU, "Control Codes Imcomplete.");
376 } 377 }
377 } 378 }
378 379
@@ -1525,6 +1526,10 @@ private:
1525 1526
1526 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, 1527 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
1527 instr.alu.saturate_d, 0, true); 1528 instr.alu.saturate_d, 0, true);
1529 if (instr.generates_cc) {
1530 LOG_CRITICAL(HW_GPU, "FMUL Generates an unhandled Control Code");
1531 UNREACHABLE();
1532 }
1528 break; 1533 break;
1529 } 1534 }
1530 case OpCode::Id::FADD_C: 1535 case OpCode::Id::FADD_C:
@@ -1535,6 +1540,10 @@ private:
1535 1540
1536 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, 1541 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
1537 instr.alu.saturate_d, 0, true); 1542 instr.alu.saturate_d, 0, true);
1543 if (instr.generates_cc) {
1544 LOG_CRITICAL(HW_GPU, "FADD Generates an unhandled Control Code");
1545 UNREACHABLE();
1546 }
1538 break; 1547 break;
1539 } 1548 }
1540 case OpCode::Id::MUFU: { 1549 case OpCode::Id::MUFU: {
@@ -1588,6 +1597,10 @@ private:
1588 '(' + condition + ") ? min(" + parameters + ") : max(" + 1597 '(' + condition + ") ? min(" + parameters + ") : max(" +
1589 parameters + ')', 1598 parameters + ')',
1590 1, 1, false, 0, true); 1599 1, 1, false, 0, true);
1600 if (instr.generates_cc) {
1601 LOG_CRITICAL(HW_GPU, "FMNMX Generates an unhandled Control Code");
1602 UNREACHABLE();
1603 }
1591 break; 1604 break;
1592 } 1605 }
1593 case OpCode::Id::RRO_C: 1606 case OpCode::Id::RRO_C:
@@ -1618,6 +1631,10 @@ private:
1618 regs.GetRegisterAsFloat(instr.gpr8) + " * " + 1631 regs.GetRegisterAsFloat(instr.gpr8) + " * " +
1619 GetImmediate32(instr), 1632 GetImmediate32(instr),
1620 1, 1, instr.fmul32.saturate, 0, true); 1633 1, 1, instr.fmul32.saturate, 0, true);
1634 if (instr.op_32.generates_cc) {
1635 LOG_CRITICAL(HW_GPU, "FMUL32 Generates an unhandled Control Code");
1636 UNREACHABLE();
1637 }
1621 break; 1638 break;
1622 } 1639 }
1623 case OpCode::Id::FADD32I: { 1640 case OpCode::Id::FADD32I: {
@@ -1641,6 +1658,10 @@ private:
1641 } 1658 }
1642 1659
1643 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true); 1660 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true);
1661 if (instr.op_32.generates_cc) {
1662 LOG_CRITICAL(HW_GPU, "FADD32 Generates an unhandled Control Code");
1663 UNREACHABLE();
1664 }
1644 break; 1665 break;
1645 } 1666 }
1646 } 1667 }
@@ -1661,6 +1682,10 @@ private:
1661 std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')'; 1682 std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
1662 1683
1663 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1); 1684 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1);
1685 if (instr.generates_cc) {
1686 LOG_CRITICAL(HW_GPU, "BFE Generates an unhandled Control Code");
1687 UNREACHABLE();
1688 }
1664 break; 1689 break;
1665 } 1690 }
1666 default: { 1691 default: {
@@ -1698,12 +1723,20 @@ private:
1698 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift 1723 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift
1699 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')', 1724 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')',
1700 1, 1); 1725 1, 1);
1726 if (instr.generates_cc) {
1727 LOG_CRITICAL(HW_GPU, "SHR Generates an unhandled Control Code");
1728 UNREACHABLE();
1729 }
1701 break; 1730 break;
1702 } 1731 }
1703 case OpCode::Id::SHL_C: 1732 case OpCode::Id::SHL_C:
1704 case OpCode::Id::SHL_R: 1733 case OpCode::Id::SHL_R:
1705 case OpCode::Id::SHL_IMM: 1734 case OpCode::Id::SHL_IMM:
1706 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); 1735 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
1736 if (instr.generates_cc) {
1737 LOG_CRITICAL(HW_GPU, "SHL Generates an unhandled Control Code");
1738 UNREACHABLE();
1739 }
1707 break; 1740 break;
1708 default: { 1741 default: {
1709 LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName()); 1742 LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName());
@@ -1723,6 +1756,10 @@ private:
1723 1756
1724 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, 1757 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
1725 instr.iadd32i.saturate != 0); 1758 instr.iadd32i.saturate != 0);
1759 if (instr.op_32.generates_cc) {
1760 LOG_CRITICAL(HW_GPU, "IADD32 Generates an unhandled Control Code");
1761 UNREACHABLE();
1762 }
1726 break; 1763 break;
1727 case OpCode::Id::LOP32I: { 1764 case OpCode::Id::LOP32I: {
1728 if (instr.alu.lop32i.invert_a) 1765 if (instr.alu.lop32i.invert_a)
@@ -1734,6 +1771,10 @@ private:
1734 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b, 1771 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
1735 Tegra::Shader::PredicateResultMode::None, 1772 Tegra::Shader::PredicateResultMode::None,
1736 Tegra::Shader::Pred::UnusedIndex); 1773 Tegra::Shader::Pred::UnusedIndex);
1774 if (instr.op_32.generates_cc) {
1775 LOG_CRITICAL(HW_GPU, "LOP32I Generates an unhandled Control Code");
1776 UNREACHABLE();
1777 }
1737 break; 1778 break;
1738 } 1779 }
1739 default: { 1780 default: {
@@ -1770,6 +1811,10 @@ private:
1770 1811
1771 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, 1812 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
1772 instr.alu.saturate_d); 1813 instr.alu.saturate_d);
1814 if (instr.generates_cc) {
1815 LOG_CRITICAL(HW_GPU, "IADD Generates an unhandled Control Code");
1816 UNREACHABLE();
1817 }
1773 break; 1818 break;
1774 } 1819 }
1775 case OpCode::Id::IADD3_C: 1820 case OpCode::Id::IADD3_C:
@@ -1831,6 +1876,11 @@ private:
1831 } 1876 }
1832 1877
1833 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1); 1878 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1);
1879
1880 if (instr.generates_cc) {
1881 LOG_CRITICAL(HW_GPU, "IADD3 Generates an unhandled Control Code");
1882 UNREACHABLE();
1883 }
1834 break; 1884 break;
1835 } 1885 }
1836 case OpCode::Id::ISCADD_C: 1886 case OpCode::Id::ISCADD_C:
@@ -1846,6 +1896,10 @@ private:
1846 1896
1847 regs.SetRegisterToInteger(instr.gpr0, true, 0, 1897 regs.SetRegisterToInteger(instr.gpr0, true, 0,
1848 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); 1898 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
1899 if (instr.generates_cc) {
1900 LOG_CRITICAL(HW_GPU, "ISCADD Generates an unhandled Control Code");
1901 UNREACHABLE();
1902 }
1849 break; 1903 break;
1850 } 1904 }
1851 case OpCode::Id::POPC_C: 1905 case OpCode::Id::POPC_C:
@@ -1877,6 +1931,10 @@ private:
1877 1931
1878 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b, 1932 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
1879 instr.alu.lop.pred_result_mode, instr.alu.lop.pred48); 1933 instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
1934 if (instr.generates_cc) {
1935 LOG_CRITICAL(HW_GPU, "LOP Generates an unhandled Control Code");
1936 UNREACHABLE();
1937 }
1880 break; 1938 break;
1881 } 1939 }
1882 case OpCode::Id::LOP3_C: 1940 case OpCode::Id::LOP3_C:
@@ -1892,6 +1950,10 @@ private:
1892 } 1950 }
1893 1951
1894 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut); 1952 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut);
1953 if (instr.generates_cc) {
1954 LOG_CRITICAL(HW_GPU, "LOP3 Generates an unhandled Control Code");
1955 UNREACHABLE();
1956 }
1895 break; 1957 break;
1896 } 1958 }
1897 case OpCode::Id::IMNMX_C: 1959 case OpCode::Id::IMNMX_C:
@@ -1906,6 +1968,10 @@ private:
1906 '(' + condition + ") ? min(" + parameters + ") : max(" + 1968 '(' + condition + ") ? min(" + parameters + ") : max(" +
1907 parameters + ')', 1969 parameters + ')',
1908 1, 1); 1970 1, 1);
1971 if (instr.generates_cc) {
1972 LOG_CRITICAL(HW_GPU, "IMNMX Generates an unhandled Control Code");
1973 UNREACHABLE();
1974 }
1909 break; 1975 break;
1910 } 1976 }
1911 case OpCode::Id::LEA_R2: 1977 case OpCode::Id::LEA_R2:
@@ -2107,6 +2173,10 @@ private:
2107 2173
2108 regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')', 2174 regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')',
2109 1, 1, instr.alu.saturate_d, 0, true); 2175 1, 1, instr.alu.saturate_d, 0, true);
2176 if (instr.generates_cc) {
2177 LOG_CRITICAL(HW_GPU, "FFMA Generates an unhandled Control Code");
2178 UNREACHABLE();
2179 }
2110 2180
2111 break; 2181 break;
2112 } 2182 }
@@ -2212,6 +2282,11 @@ private:
2212 } 2282 }
2213 2283
2214 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 2284 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
2285
2286 if (instr.generates_cc) {
2287 LOG_CRITICAL(HW_GPU, "I2F Generates an unhandled Control Code");
2288 UNREACHABLE();
2289 }
2215 break; 2290 break;
2216 } 2291 }
2217 case OpCode::Id::F2F_R: { 2292 case OpCode::Id::F2F_R: {
@@ -2250,6 +2325,11 @@ private:
2250 } 2325 }
2251 2326
2252 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d); 2327 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
2328
2329 if (instr.generates_cc) {
2330 LOG_CRITICAL(HW_GPU, "F2F Generates an unhandled Control Code");
2331 UNREACHABLE();
2332 }
2253 break; 2333 break;
2254 } 2334 }
2255 case OpCode::Id::F2I_R: 2335 case OpCode::Id::F2I_R:
@@ -2299,6 +2379,10 @@ private:
2299 2379
2300 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, 2380 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
2301 1, false, 0, instr.conversion.dest_size); 2381 1, false, 0, instr.conversion.dest_size);
2382 if (instr.generates_cc) {
2383 LOG_CRITICAL(HW_GPU, "F2I Generates an unhandled Control Code");
2384 UNREACHABLE();
2385 }
2302 break; 2386 break;
2303 } 2387 }
2304 default: { 2388 default: {
@@ -3107,6 +3191,11 @@ private:
3107 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1); 3191 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
3108 } 3192 }
3109 3193
3194 if (instr.generates_cc) {
3195 LOG_CRITICAL(HW_GPU, "PSET Generates an unhandled Control Code");
3196 UNREACHABLE();
3197 }
3198
3110 break; 3199 break;
3111 } 3200 }
3112 case OpCode::Type::PredicateSetPredicate: { 3201 case OpCode::Type::PredicateSetPredicate: {
@@ -3372,6 +3461,10 @@ private:
3372 } 3461 }
3373 3462
3374 regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1); 3463 regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
3464 if (instr.generates_cc) {
3465 LOG_CRITICAL(HW_GPU, "XMAD Generates an unhandled Control Code");
3466 UNREACHABLE();
3467 }
3375 break; 3468 break;
3376 } 3469 }
3377 default: { 3470 default: {
@@ -3381,6 +3474,12 @@ private:
3381 EmitFragmentOutputsWrite(); 3474 EmitFragmentOutputsWrite();
3382 } 3475 }
3383 3476
3477 const Tegra::Shader::ControlCode cc = instr.flow_control_code;
3478 if (cc != Tegra::Shader::ControlCode::T) {
3479 LOG_CRITICAL(HW_GPU, "EXIT Control Code used: {}", static_cast<u32>(cc));
3480 UNREACHABLE();
3481 }
3482
3384 switch (instr.flow.cond) { 3483 switch (instr.flow.cond) {
3385 case Tegra::Shader::FlowCondition::Always: 3484 case Tegra::Shader::FlowCondition::Always:
3386 shader.AddLine("return true;"); 3485 shader.AddLine("return true;");
@@ -3410,6 +3509,11 @@ private:
3410 3509
3411 // Enclose "discard" in a conditional, so that GLSL compilation does not complain 3510 // Enclose "discard" in a conditional, so that GLSL compilation does not complain
3412 // about unexecuted instructions that may follow this. 3511 // about unexecuted instructions that may follow this.
3512 const Tegra::Shader::ControlCode cc = instr.flow_control_code;
3513 if (cc != Tegra::Shader::ControlCode::T) {
3514 LOG_CRITICAL(HW_GPU, "KIL Control Code used: {}", static_cast<u32>(cc));
3515 UNREACHABLE();
3516 }
3413 shader.AddLine("if (true) {"); 3517 shader.AddLine("if (true) {");
3414 ++shader.scope; 3518 ++shader.scope;
3415 shader.AddLine("discard;"); 3519 shader.AddLine("discard;");
@@ -3467,6 +3571,11 @@ private:
3467 case OpCode::Id::BRA: { 3571 case OpCode::Id::BRA: {
3468 ASSERT_MSG(instr.bra.constant_buffer == 0, 3572 ASSERT_MSG(instr.bra.constant_buffer == 0,
3469 "BRA with constant buffers are not implemented"); 3573 "BRA with constant buffers are not implemented");
3574 const Tegra::Shader::ControlCode cc = instr.flow_control_code;
3575 if (cc != Tegra::Shader::ControlCode::T) {
3576 LOG_CRITICAL(HW_GPU, "BRA Control Code used: {}", static_cast<u32>(cc));
3577 UNREACHABLE();
3578 }
3470 const u32 target = offset + instr.bra.GetBranchTarget(); 3579 const u32 target = offset + instr.bra.GetBranchTarget();
3471 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); 3580 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
3472 break; 3581 break;
@@ -3507,13 +3616,21 @@ private:
3507 } 3616 }
3508 case OpCode::Id::SYNC: { 3617 case OpCode::Id::SYNC: {
3509 // The SYNC opcode jumps to the address previously set by the SSY opcode 3618 // The SYNC opcode jumps to the address previously set by the SSY opcode
3510 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); 3619 const Tegra::Shader::ControlCode cc = instr.flow_control_code;
3620 if (cc != Tegra::Shader::ControlCode::T) {
3621 LOG_CRITICAL(HW_GPU, "SYNC Control Code used: {}", static_cast<u32>(cc));
3622 UNREACHABLE();
3623 }
3511 EmitPopFromFlowStack(); 3624 EmitPopFromFlowStack();
3512 break; 3625 break;
3513 } 3626 }
3514 case OpCode::Id::BRK: { 3627 case OpCode::Id::BRK: {
3515 // The BRK opcode jumps to the address previously set by the PBK opcode 3628 // The BRK opcode jumps to the address previously set by the PBK opcode
3516 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); 3629 const Tegra::Shader::ControlCode cc = instr.flow_control_code;
3630 if (cc != Tegra::Shader::ControlCode::T) {
3631 LOG_CRITICAL(HW_GPU, "BRK Control Code used: {}", static_cast<u32>(cc));
3632 UNREACHABLE();
3633 }
3517 EmitPopFromFlowStack(); 3634 EmitPopFromFlowStack();
3518 break; 3635 break;
3519 } 3636 }
@@ -3543,6 +3660,11 @@ private:
3543 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, 3660 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
3544 instr.vmad.saturate == 1, 0, Register::Size::Word, 3661 instr.vmad.saturate == 1, 0, Register::Size::Word,
3545 instr.vmad.cc); 3662 instr.vmad.cc);
3663 if (instr.generates_cc) {
3664 LOG_CRITICAL(HW_GPU, "VMAD Generates an unhandled Control Code");
3665 UNREACHABLE();
3666 }
3667
3546 break; 3668 break;
3547 } 3669 }
3548 case OpCode::Id::VSETP: { 3670 case OpCode::Id::VSETP: {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index d8a43cc94..b6b426f34 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -89,7 +89,18 @@ OpenGLState::OpenGLState() {
89 point.size = 1; 89 point.size = 1;
90} 90}
91 91
92void OpenGLState::Apply() const { 92void OpenGLState::ApplyDefaultState() {
93 glDisable(GL_FRAMEBUFFER_SRGB);
94 glDisable(GL_CULL_FACE);
95 glDisable(GL_DEPTH_TEST);
96 glDisable(GL_PRIMITIVE_RESTART);
97 glDisable(GL_STENCIL_TEST);
98 glEnable(GL_BLEND);
99 glDisable(GL_COLOR_LOGIC_OP);
100 glDisable(GL_SCISSOR_TEST);
101}
102
103void OpenGLState::ApplySRgb() const {
93 // sRGB 104 // sRGB
94 if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) { 105 if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) {
95 if (framebuffer_srgb.enabled) { 106 if (framebuffer_srgb.enabled) {
@@ -100,96 +111,122 @@ void OpenGLState::Apply() const {
100 glDisable(GL_FRAMEBUFFER_SRGB); 111 glDisable(GL_FRAMEBUFFER_SRGB);
101 } 112 }
102 } 113 }
114}
115
116void OpenGLState::ApplyCulling() const {
103 // Culling 117 // Culling
104 if (cull.enabled != cur_state.cull.enabled) { 118 const bool cull_changed = cull.enabled != cur_state.cull.enabled;
119 if (cull_changed) {
105 if (cull.enabled) { 120 if (cull.enabled) {
106 glEnable(GL_CULL_FACE); 121 glEnable(GL_CULL_FACE);
107 } else { 122 } else {
108 glDisable(GL_CULL_FACE); 123 glDisable(GL_CULL_FACE);
109 } 124 }
110 } 125 }
126 if (cull.enabled) {
127 if (cull_changed || cull.mode != cur_state.cull.mode) {
128 glCullFace(cull.mode);
129 }
111 130
112 if (cull.mode != cur_state.cull.mode) { 131 if (cull_changed || cull.front_face != cur_state.cull.front_face) {
113 glCullFace(cull.mode); 132 glFrontFace(cull.front_face);
114 } 133 }
115
116 if (cull.front_face != cur_state.cull.front_face) {
117 glFrontFace(cull.front_face);
118 } 134 }
135}
119 136
137void OpenGLState::ApplyDepth() const {
120 // Depth test 138 // Depth test
121 if (depth.test_enabled != cur_state.depth.test_enabled) { 139 const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
140 if (depth_test_changed) {
122 if (depth.test_enabled) { 141 if (depth.test_enabled) {
123 glEnable(GL_DEPTH_TEST); 142 glEnable(GL_DEPTH_TEST);
124 } else { 143 } else {
125 glDisable(GL_DEPTH_TEST); 144 glDisable(GL_DEPTH_TEST);
126 } 145 }
127 } 146 }
128 147 if (depth.test_enabled &&
129 if (depth.test_func != cur_state.depth.test_func) { 148 (depth_test_changed || depth.test_func != cur_state.depth.test_func)) {
130 glDepthFunc(depth.test_func); 149 glDepthFunc(depth.test_func);
131 } 150 }
132
133 // Depth mask 151 // Depth mask
134 if (depth.write_mask != cur_state.depth.write_mask) { 152 if (depth.write_mask != cur_state.depth.write_mask) {
135 glDepthMask(depth.write_mask); 153 glDepthMask(depth.write_mask);
136 } 154 }
137
138 // Depth range 155 // Depth range
139 if (depth.depth_range_near != cur_state.depth.depth_range_near || 156 if (depth.depth_range_near != cur_state.depth.depth_range_near ||
140 depth.depth_range_far != cur_state.depth.depth_range_far) { 157 depth.depth_range_far != cur_state.depth.depth_range_far) {
141 glDepthRange(depth.depth_range_near, depth.depth_range_far); 158 glDepthRange(depth.depth_range_near, depth.depth_range_far);
142 } 159 }
160}
143 161
144 // Primitive restart 162void OpenGLState::ApplyPrimitiveRestart() const {
145 if (primitive_restart.enabled != cur_state.primitive_restart.enabled) { 163 const bool primitive_restart_changed =
164 primitive_restart.enabled != cur_state.primitive_restart.enabled;
165 if (primitive_restart_changed) {
146 if (primitive_restart.enabled) { 166 if (primitive_restart.enabled) {
147 glEnable(GL_PRIMITIVE_RESTART); 167 glEnable(GL_PRIMITIVE_RESTART);
148 } else { 168 } else {
149 glDisable(GL_PRIMITIVE_RESTART); 169 glDisable(GL_PRIMITIVE_RESTART);
150 } 170 }
151 } 171 }
152 if (primitive_restart.index != cur_state.primitive_restart.index) { 172 if (primitive_restart_changed ||
173 (primitive_restart.enabled &&
174 primitive_restart.index != cur_state.primitive_restart.index)) {
153 glPrimitiveRestartIndex(primitive_restart.index); 175 glPrimitiveRestartIndex(primitive_restart.index);
154 } 176 }
177}
155 178
156 // Color mask 179void OpenGLState::ApplyStencilTest() const {
157 if (color_mask.red_enabled != cur_state.color_mask.red_enabled || 180 const bool stencil_test_changed = stencil.test_enabled != cur_state.stencil.test_enabled;
158 color_mask.green_enabled != cur_state.color_mask.green_enabled || 181 if (stencil_test_changed) {
159 color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
160 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
161 glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
162 color_mask.alpha_enabled);
163 }
164
165 // Stencil test
166 if (stencil.test_enabled != cur_state.stencil.test_enabled) {
167 if (stencil.test_enabled) { 182 if (stencil.test_enabled) {
168 glEnable(GL_STENCIL_TEST); 183 glEnable(GL_STENCIL_TEST);
169 } else { 184 } else {
170 glDisable(GL_STENCIL_TEST); 185 glDisable(GL_STENCIL_TEST);
171 } 186 }
172 } 187 }
173 auto config_stencil = [](GLenum face, const auto& config, const auto& prev_config) { 188 if (stencil.test_enabled) {
174 if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref || 189 auto config_stencil = [stencil_test_changed](GLenum face, const auto& config,
175 config.test_mask != prev_config.test_mask) { 190 const auto& prev_config) {
176 glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); 191 if (stencil_test_changed || config.test_func != prev_config.test_func ||
177 } 192 config.test_ref != prev_config.test_ref ||
178 if (config.action_depth_fail != prev_config.action_depth_fail || 193 config.test_mask != prev_config.test_mask) {
179 config.action_depth_pass != prev_config.action_depth_pass || 194 glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
180 config.action_stencil_fail != prev_config.action_stencil_fail) { 195 }
181 glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, 196 if (stencil_test_changed || config.action_depth_fail != prev_config.action_depth_fail ||
182 config.action_depth_pass); 197 config.action_depth_pass != prev_config.action_depth_pass ||
183 } 198 config.action_stencil_fail != prev_config.action_stencil_fail) {
184 if (config.write_mask != prev_config.write_mask) { 199 glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
185 glStencilMaskSeparate(face, config.write_mask); 200 config.action_depth_pass);
201 }
202 if (config.write_mask != prev_config.write_mask) {
203 glStencilMaskSeparate(face, config.write_mask);
204 }
205 };
206 config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
207 config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
208 }
209}
210
211void OpenGLState::ApplyScissorTest() const {
212 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
213 if (scissor_changed) {
214 if (scissor.enabled) {
215 glEnable(GL_SCISSOR_TEST);
216 } else {
217 glDisable(GL_SCISSOR_TEST);
186 } 218 }
187 }; 219 }
188 config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front); 220 if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x ||
189 config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); 221 scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width ||
222 scissor.height != cur_state.scissor.height) {
223 glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
224 }
225}
190 226
191 // Blending 227void OpenGLState::ApplyBlending() const {
192 if (blend.enabled != cur_state.blend.enabled) { 228 const bool blend_changed = blend.enabled != cur_state.blend.enabled;
229 if (blend_changed) {
193 if (blend.enabled) { 230 if (blend.enabled) {
194 ASSERT(!logic_op.enabled); 231 ASSERT(!logic_op.enabled);
195 glEnable(GL_BLEND); 232 glEnable(GL_BLEND);
@@ -197,29 +234,32 @@ void OpenGLState::Apply() const {
197 glDisable(GL_BLEND); 234 glDisable(GL_BLEND);
198 } 235 }
199 } 236 }
237 if (blend.enabled) {
238 if (blend_changed || blend.color.red != cur_state.blend.color.red ||
239 blend.color.green != cur_state.blend.color.green ||
240 blend.color.blue != cur_state.blend.color.blue ||
241 blend.color.alpha != cur_state.blend.color.alpha) {
242 glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha);
243 }
200 244
201 if (blend.color.red != cur_state.blend.color.red || 245 if (blend_changed || blend.src_rgb_func != cur_state.blend.src_rgb_func ||
202 blend.color.green != cur_state.blend.color.green || 246 blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
203 blend.color.blue != cur_state.blend.color.blue || 247 blend.src_a_func != cur_state.blend.src_a_func ||
204 blend.color.alpha != cur_state.blend.color.alpha) { 248 blend.dst_a_func != cur_state.blend.dst_a_func) {
205 glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); 249 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
206 } 250 blend.dst_a_func);
207 251 }
208 if (blend.src_rgb_func != cur_state.blend.src_rgb_func ||
209 blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
210 blend.src_a_func != cur_state.blend.src_a_func ||
211 blend.dst_a_func != cur_state.blend.dst_a_func) {
212 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
213 blend.dst_a_func);
214 }
215 252
216 if (blend.rgb_equation != cur_state.blend.rgb_equation || 253 if (blend_changed || blend.rgb_equation != cur_state.blend.rgb_equation ||
217 blend.a_equation != cur_state.blend.a_equation) { 254 blend.a_equation != cur_state.blend.a_equation) {
218 glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); 255 glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
256 }
219 } 257 }
258}
220 259
221 // Logic Operation 260void OpenGLState::ApplyLogicOp() const {
222 if (logic_op.enabled != cur_state.logic_op.enabled) { 261 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
262 if (logic_op_changed) {
223 if (logic_op.enabled) { 263 if (logic_op.enabled) {
224 ASSERT(!blend.enabled); 264 ASSERT(!blend.enabled);
225 glEnable(GL_COLOR_LOGIC_OP); 265 glEnable(GL_COLOR_LOGIC_OP);
@@ -228,11 +268,13 @@ void OpenGLState::Apply() const {
228 } 268 }
229 } 269 }
230 270
231 if (logic_op.operation != cur_state.logic_op.operation) { 271 if (logic_op.enabled &&
272 (logic_op_changed || logic_op.operation != cur_state.logic_op.operation)) {
232 glLogicOp(logic_op.operation); 273 glLogicOp(logic_op.operation);
233 } 274 }
275}
234 276
235 // Textures 277void OpenGLState::ApplyTextures() const {
236 for (std::size_t i = 0; i < std::size(texture_units); ++i) { 278 for (std::size_t i = 0; i < std::size(texture_units); ++i) {
237 const auto& texture_unit = texture_units[i]; 279 const auto& texture_unit = texture_units[i];
238 const auto& cur_state_texture_unit = cur_state.texture_units[i]; 280 const auto& cur_state_texture_unit = cur_state.texture_units[i];
@@ -251,28 +293,29 @@ void OpenGLState::Apply() const {
251 glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); 293 glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
252 } 294 }
253 } 295 }
296}
254 297
255 // Samplers 298void OpenGLState::ApplySamplers() const {
256 { 299 bool has_delta{};
257 bool has_delta{}; 300 std::size_t first{}, last{};
258 std::size_t first{}, last{}; 301 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
259 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers; 302 for (std::size_t i = 0; i < std::size(samplers); ++i) {
260 for (std::size_t i = 0; i < std::size(samplers); ++i) { 303 samplers[i] = texture_units[i].sampler;
261 samplers[i] = texture_units[i].sampler; 304 if (samplers[i] != cur_state.texture_units[i].sampler) {
262 if (samplers[i] != cur_state.texture_units[i].sampler) { 305 if (!has_delta) {
263 if (!has_delta) { 306 first = i;
264 first = i; 307 has_delta = true;
265 has_delta = true;
266 }
267 last = i;
268 } 308 }
269 } 309 last = i;
270 if (has_delta) {
271 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
272 samplers.data());
273 } 310 }
274 } 311 }
312 if (has_delta) {
313 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
314 samplers.data());
315 }
316}
275 317
318void OpenGLState::Apply() const {
276 // Framebuffer 319 // Framebuffer
277 if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { 320 if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
278 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); 321 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
@@ -305,27 +348,12 @@ void OpenGLState::Apply() const {
305 if (draw.program_pipeline != cur_state.draw.program_pipeline) { 348 if (draw.program_pipeline != cur_state.draw.program_pipeline) {
306 glBindProgramPipeline(draw.program_pipeline); 349 glBindProgramPipeline(draw.program_pipeline);
307 } 350 }
308 351 // Viewport
309 // Scissor test
310 if (scissor.enabled != cur_state.scissor.enabled) {
311 if (scissor.enabled) {
312 glEnable(GL_SCISSOR_TEST);
313 } else {
314 glDisable(GL_SCISSOR_TEST);
315 }
316 }
317
318 if (scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
319 scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height) {
320 glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
321 }
322
323 if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y || 352 if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
324 viewport.width != cur_state.viewport.width || 353 viewport.width != cur_state.viewport.width ||
325 viewport.height != cur_state.viewport.height) { 354 viewport.height != cur_state.viewport.height) {
326 glViewport(viewport.x, viewport.y, viewport.width, viewport.height); 355 glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
327 } 356 }
328
329 // Clip distance 357 // Clip distance
330 for (std::size_t i = 0; i < clip_distance.size(); ++i) { 358 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
331 if (clip_distance[i] != cur_state.clip_distance[i]) { 359 if (clip_distance[i] != cur_state.clip_distance[i]) {
@@ -336,12 +364,28 @@ void OpenGLState::Apply() const {
336 } 364 }
337 } 365 }
338 } 366 }
339 367 // Color mask
368 if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
369 color_mask.green_enabled != cur_state.color_mask.green_enabled ||
370 color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
371 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
372 glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
373 color_mask.alpha_enabled);
374 }
340 // Point 375 // Point
341 if (point.size != cur_state.point.size) { 376 if (point.size != cur_state.point.size) {
342 glPointSize(point.size); 377 glPointSize(point.size);
343 } 378 }
344 379 ApplyScissorTest();
380 ApplyStencilTest();
381 ApplySRgb();
382 ApplyCulling();
383 ApplyDepth();
384 ApplyPrimitiveRestart();
385 ApplyBlending();
386 ApplyLogicOp();
387 ApplyTextures();
388 ApplySamplers();
345 cur_state = *this; 389 cur_state = *this;
346} 390}
347 391
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 9e2c573b5..fe648aff6 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -173,7 +173,8 @@ public:
173 } 173 }
174 /// Apply this state as the current OpenGL state 174 /// Apply this state as the current OpenGL state
175 void Apply() const; 175 void Apply() const;
176 176 /// Set the initial OpenGL state
177 static void ApplyDefaultState();
177 /// Resets any references to the given resource 178 /// Resets any references to the given resource
178 OpenGLState& UnbindTexture(GLuint handle); 179 OpenGLState& UnbindTexture(GLuint handle);
179 OpenGLState& ResetSampler(GLuint handle); 180 OpenGLState& ResetSampler(GLuint handle);
@@ -188,6 +189,16 @@ private:
188 // Workaround for sRGB problems caused by 189 // Workaround for sRGB problems caused by
189 // QT not supporting srgb output 190 // QT not supporting srgb output
190 static bool s_rgb_used; 191 static bool s_rgb_used;
192 void ApplySRgb() const;
193 void ApplyCulling() const;
194 void ApplyDepth() const;
195 void ApplyPrimitiveRestart() const;
196 void ApplyStencilTest() const;
197 void ApplyScissorTest() const;
198 void ApplyBlending() const;
199 void ApplyLogicOp() const;
200 void ApplyTextures() const;
201 void ApplySamplers() const;
191}; 202};
192 203
193} // namespace OpenGL 204} // namespace OpenGL
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
new file mode 100644
index 000000000..d9a97e30b
--- /dev/null
+++ b/src/video_core/surface.cpp
@@ -0,0 +1,499 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "common/math_util.h"
7#include "video_core/surface.h"
8
9namespace VideoCore::Surface {
10
11SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
12 switch (texture_type) {
13 case Tegra::Texture::TextureType::Texture1D:
14 return SurfaceTarget::Texture1D;
15 case Tegra::Texture::TextureType::Texture2D:
16 case Tegra::Texture::TextureType::Texture2DNoMipmap:
17 return SurfaceTarget::Texture2D;
18 case Tegra::Texture::TextureType::Texture3D:
19 return SurfaceTarget::Texture3D;
20 case Tegra::Texture::TextureType::TextureCubemap:
21 return SurfaceTarget::TextureCubemap;
22 case Tegra::Texture::TextureType::Texture1DArray:
23 return SurfaceTarget::Texture1DArray;
24 case Tegra::Texture::TextureType::Texture2DArray:
25 return SurfaceTarget::Texture2DArray;
26 default:
27 LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
28 UNREACHABLE();
29 return SurfaceTarget::Texture2D;
30 }
31}
32
33bool SurfaceTargetIsLayered(SurfaceTarget target) {
34 switch (target) {
35 case SurfaceTarget::Texture1D:
36 case SurfaceTarget::Texture2D:
37 case SurfaceTarget::Texture3D:
38 return false;
39 case SurfaceTarget::Texture1DArray:
40 case SurfaceTarget::Texture2DArray:
41 case SurfaceTarget::TextureCubemap:
42 return true;
43 default:
44 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
45 UNREACHABLE();
46 return false;
47 }
48}
49
50PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
51 switch (format) {
52 case Tegra::DepthFormat::S8_Z24_UNORM:
53 return PixelFormat::S8Z24;
54 case Tegra::DepthFormat::Z24_S8_UNORM:
55 return PixelFormat::Z24S8;
56 case Tegra::DepthFormat::Z32_FLOAT:
57 return PixelFormat::Z32F;
58 case Tegra::DepthFormat::Z16_UNORM:
59 return PixelFormat::Z16;
60 case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
61 return PixelFormat::Z32FS8;
62 default:
63 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
64 UNREACHABLE();
65 }
66}
67
68PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
69 switch (format) {
70 // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
71 // gamma.
72 case Tegra::RenderTargetFormat::RGBA8_SRGB:
73 return PixelFormat::RGBA8_SRGB;
74 case Tegra::RenderTargetFormat::RGBA8_UNORM:
75 return PixelFormat::ABGR8U;
76 case Tegra::RenderTargetFormat::RGBA8_SNORM:
77 return PixelFormat::ABGR8S;
78 case Tegra::RenderTargetFormat::RGBA8_UINT:
79 return PixelFormat::ABGR8UI;
80 case Tegra::RenderTargetFormat::BGRA8_SRGB:
81 return PixelFormat::BGRA8_SRGB;
82 case Tegra::RenderTargetFormat::BGRA8_UNORM:
83 return PixelFormat::BGRA8;
84 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
85 return PixelFormat::A2B10G10R10U;
86 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
87 return PixelFormat::RGBA16F;
88 case Tegra::RenderTargetFormat::RGBA16_UNORM:
89 return PixelFormat::RGBA16U;
90 case Tegra::RenderTargetFormat::RGBA16_UINT:
91 return PixelFormat::RGBA16UI;
92 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
93 return PixelFormat::RGBA32F;
94 case Tegra::RenderTargetFormat::RG32_FLOAT:
95 return PixelFormat::RG32F;
96 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
97 return PixelFormat::R11FG11FB10F;
98 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
99 return PixelFormat::B5G6R5U;
100 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
101 return PixelFormat::A1B5G5R5U;
102 case Tegra::RenderTargetFormat::RGBA32_UINT:
103 return PixelFormat::RGBA32UI;
104 case Tegra::RenderTargetFormat::R8_UNORM:
105 return PixelFormat::R8U;
106 case Tegra::RenderTargetFormat::R8_UINT:
107 return PixelFormat::R8UI;
108 case Tegra::RenderTargetFormat::RG16_FLOAT:
109 return PixelFormat::RG16F;
110 case Tegra::RenderTargetFormat::RG16_UINT:
111 return PixelFormat::RG16UI;
112 case Tegra::RenderTargetFormat::RG16_SINT:
113 return PixelFormat::RG16I;
114 case Tegra::RenderTargetFormat::RG16_UNORM:
115 return PixelFormat::RG16;
116 case Tegra::RenderTargetFormat::RG16_SNORM:
117 return PixelFormat::RG16S;
118 case Tegra::RenderTargetFormat::RG8_UNORM:
119 return PixelFormat::RG8U;
120 case Tegra::RenderTargetFormat::RG8_SNORM:
121 return PixelFormat::RG8S;
122 case Tegra::RenderTargetFormat::R16_FLOAT:
123 return PixelFormat::R16F;
124 case Tegra::RenderTargetFormat::R16_UNORM:
125 return PixelFormat::R16U;
126 case Tegra::RenderTargetFormat::R16_SNORM:
127 return PixelFormat::R16S;
128 case Tegra::RenderTargetFormat::R16_UINT:
129 return PixelFormat::R16UI;
130 case Tegra::RenderTargetFormat::R16_SINT:
131 return PixelFormat::R16I;
132 case Tegra::RenderTargetFormat::R32_FLOAT:
133 return PixelFormat::R32F;
134 case Tegra::RenderTargetFormat::R32_UINT:
135 return PixelFormat::R32UI;
136 case Tegra::RenderTargetFormat::RG32_UINT:
137 return PixelFormat::RG32UI;
138 default:
139 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
140 UNREACHABLE();
141 }
142}
143
144PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
145 Tegra::Texture::ComponentType component_type,
146 bool is_srgb) {
147 // TODO(Subv): Properly implement this
148 switch (format) {
149 case Tegra::Texture::TextureFormat::A8R8G8B8:
150 if (is_srgb) {
151 return PixelFormat::RGBA8_SRGB;
152 }
153 switch (component_type) {
154 case Tegra::Texture::ComponentType::UNORM:
155 return PixelFormat::ABGR8U;
156 case Tegra::Texture::ComponentType::SNORM:
157 return PixelFormat::ABGR8S;
158 case Tegra::Texture::ComponentType::UINT:
159 return PixelFormat::ABGR8UI;
160 }
161 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
162 UNREACHABLE();
163 case Tegra::Texture::TextureFormat::B5G6R5:
164 switch (component_type) {
165 case Tegra::Texture::ComponentType::UNORM:
166 return PixelFormat::B5G6R5U;
167 }
168 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
169 UNREACHABLE();
170 case Tegra::Texture::TextureFormat::A2B10G10R10:
171 switch (component_type) {
172 case Tegra::Texture::ComponentType::UNORM:
173 return PixelFormat::A2B10G10R10U;
174 }
175 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
176 UNREACHABLE();
177 case Tegra::Texture::TextureFormat::A1B5G5R5:
178 switch (component_type) {
179 case Tegra::Texture::ComponentType::UNORM:
180 return PixelFormat::A1B5G5R5U;
181 }
182 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
183 UNREACHABLE();
184 case Tegra::Texture::TextureFormat::R8:
185 switch (component_type) {
186 case Tegra::Texture::ComponentType::UNORM:
187 return PixelFormat::R8U;
188 case Tegra::Texture::ComponentType::UINT:
189 return PixelFormat::R8UI;
190 }
191 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
192 UNREACHABLE();
193 case Tegra::Texture::TextureFormat::G8R8:
194 switch (component_type) {
195 case Tegra::Texture::ComponentType::UNORM:
196 return PixelFormat::G8R8U;
197 case Tegra::Texture::ComponentType::SNORM:
198 return PixelFormat::G8R8S;
199 }
200 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
201 UNREACHABLE();
202 case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
203 switch (component_type) {
204 case Tegra::Texture::ComponentType::UNORM:
205 return PixelFormat::RGBA16U;
206 case Tegra::Texture::ComponentType::FLOAT:
207 return PixelFormat::RGBA16F;
208 }
209 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
210 UNREACHABLE();
211 case Tegra::Texture::TextureFormat::BF10GF11RF11:
212 switch (component_type) {
213 case Tegra::Texture::ComponentType::FLOAT:
214 return PixelFormat::R11FG11FB10F;
215 }
216 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
217 UNREACHABLE();
218 case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
219 switch (component_type) {
220 case Tegra::Texture::ComponentType::FLOAT:
221 return PixelFormat::RGBA32F;
222 case Tegra::Texture::ComponentType::UINT:
223 return PixelFormat::RGBA32UI;
224 }
225 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
226 UNREACHABLE();
227 case Tegra::Texture::TextureFormat::R32_G32:
228 switch (component_type) {
229 case Tegra::Texture::ComponentType::FLOAT:
230 return PixelFormat::RG32F;
231 case Tegra::Texture::ComponentType::UINT:
232 return PixelFormat::RG32UI;
233 }
234 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
235 UNREACHABLE();
236 case Tegra::Texture::TextureFormat::R32_G32_B32:
237 switch (component_type) {
238 case Tegra::Texture::ComponentType::FLOAT:
239 return PixelFormat::RGB32F;
240 }
241 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
242 UNREACHABLE();
243 case Tegra::Texture::TextureFormat::R16:
244 switch (component_type) {
245 case Tegra::Texture::ComponentType::FLOAT:
246 return PixelFormat::R16F;
247 case Tegra::Texture::ComponentType::UNORM:
248 return PixelFormat::R16U;
249 case Tegra::Texture::ComponentType::SNORM:
250 return PixelFormat::R16S;
251 case Tegra::Texture::ComponentType::UINT:
252 return PixelFormat::R16UI;
253 case Tegra::Texture::ComponentType::SINT:
254 return PixelFormat::R16I;
255 }
256 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
257 UNREACHABLE();
258 case Tegra::Texture::TextureFormat::R32:
259 switch (component_type) {
260 case Tegra::Texture::ComponentType::FLOAT:
261 return PixelFormat::R32F;
262 case Tegra::Texture::ComponentType::UINT:
263 return PixelFormat::R32UI;
264 }
265 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
266 UNREACHABLE();
267 case Tegra::Texture::TextureFormat::ZF32:
268 return PixelFormat::Z32F;
269 case Tegra::Texture::TextureFormat::Z16:
270 return PixelFormat::Z16;
271 case Tegra::Texture::TextureFormat::Z24S8:
272 return PixelFormat::Z24S8;
273 case Tegra::Texture::TextureFormat::DXT1:
274 return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
275 case Tegra::Texture::TextureFormat::DXT23:
276 return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
277 case Tegra::Texture::TextureFormat::DXT45:
278 return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
279 case Tegra::Texture::TextureFormat::DXN1:
280 return PixelFormat::DXN1;
281 case Tegra::Texture::TextureFormat::DXN2:
282 switch (component_type) {
283 case Tegra::Texture::ComponentType::UNORM:
284 return PixelFormat::DXN2UNORM;
285 case Tegra::Texture::ComponentType::SNORM:
286 return PixelFormat::DXN2SNORM;
287 }
288 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
289 UNREACHABLE();
290 case Tegra::Texture::TextureFormat::BC7U:
291 return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
292 case Tegra::Texture::TextureFormat::BC6H_UF16:
293 return PixelFormat::BC6H_UF16;
294 case Tegra::Texture::TextureFormat::BC6H_SF16:
295 return PixelFormat::BC6H_SF16;
296 case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
297 return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
298 case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
299 return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
300 case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
301 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
302 case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
303 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
304 case Tegra::Texture::TextureFormat::R16_G16:
305 switch (component_type) {
306 case Tegra::Texture::ComponentType::FLOAT:
307 return PixelFormat::RG16F;
308 case Tegra::Texture::ComponentType::UNORM:
309 return PixelFormat::RG16;
310 case Tegra::Texture::ComponentType::SNORM:
311 return PixelFormat::RG16S;
312 case Tegra::Texture::ComponentType::UINT:
313 return PixelFormat::RG16UI;
314 case Tegra::Texture::ComponentType::SINT:
315 return PixelFormat::RG16I;
316 }
317 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
318 UNREACHABLE();
319 default:
320 LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", static_cast<u32>(format),
321 static_cast<u32>(component_type));
322 UNREACHABLE();
323 }
324}
325
326ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
327 // TODO(Subv): Implement more component types
328 switch (type) {
329 case Tegra::Texture::ComponentType::UNORM:
330 return ComponentType::UNorm;
331 case Tegra::Texture::ComponentType::FLOAT:
332 return ComponentType::Float;
333 case Tegra::Texture::ComponentType::SNORM:
334 return ComponentType::SNorm;
335 case Tegra::Texture::ComponentType::UINT:
336 return ComponentType::UInt;
337 case Tegra::Texture::ComponentType::SINT:
338 return ComponentType::SInt;
339 default:
340 LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
341 UNREACHABLE();
342 }
343}
344
345ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
346 // TODO(Subv): Implement more render targets
347 switch (format) {
348 case Tegra::RenderTargetFormat::RGBA8_UNORM:
349 case Tegra::RenderTargetFormat::RGBA8_SRGB:
350 case Tegra::RenderTargetFormat::BGRA8_UNORM:
351 case Tegra::RenderTargetFormat::BGRA8_SRGB:
352 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
353 case Tegra::RenderTargetFormat::R8_UNORM:
354 case Tegra::RenderTargetFormat::RG16_UNORM:
355 case Tegra::RenderTargetFormat::R16_UNORM:
356 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
357 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
358 case Tegra::RenderTargetFormat::RG8_UNORM:
359 case Tegra::RenderTargetFormat::RGBA16_UNORM:
360 return ComponentType::UNorm;
361 case Tegra::RenderTargetFormat::RGBA8_SNORM:
362 case Tegra::RenderTargetFormat::RG16_SNORM:
363 case Tegra::RenderTargetFormat::R16_SNORM:
364 case Tegra::RenderTargetFormat::RG8_SNORM:
365 return ComponentType::SNorm;
366 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
367 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
368 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
369 case Tegra::RenderTargetFormat::RG32_FLOAT:
370 case Tegra::RenderTargetFormat::RG16_FLOAT:
371 case Tegra::RenderTargetFormat::R16_FLOAT:
372 case Tegra::RenderTargetFormat::R32_FLOAT:
373 return ComponentType::Float;
374 case Tegra::RenderTargetFormat::RGBA32_UINT:
375 case Tegra::RenderTargetFormat::RGBA16_UINT:
376 case Tegra::RenderTargetFormat::RG16_UINT:
377 case Tegra::RenderTargetFormat::R8_UINT:
378 case Tegra::RenderTargetFormat::R16_UINT:
379 case Tegra::RenderTargetFormat::RG32_UINT:
380 case Tegra::RenderTargetFormat::R32_UINT:
381 case Tegra::RenderTargetFormat::RGBA8_UINT:
382 return ComponentType::UInt;
383 case Tegra::RenderTargetFormat::RG16_SINT:
384 case Tegra::RenderTargetFormat::R16_SINT:
385 return ComponentType::SInt;
386 default:
387 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
388 UNREACHABLE();
389 }
390}
391
392PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
393 switch (format) {
394 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
395 return PixelFormat::ABGR8U;
396 default:
397 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
398 UNREACHABLE();
399 }
400}
401
402ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
403 switch (format) {
404 case Tegra::DepthFormat::Z16_UNORM:
405 case Tegra::DepthFormat::S8_Z24_UNORM:
406 case Tegra::DepthFormat::Z24_S8_UNORM:
407 return ComponentType::UNorm;
408 case Tegra::DepthFormat::Z32_FLOAT:
409 case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
410 return ComponentType::Float;
411 default:
412 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
413 UNREACHABLE();
414 }
415}
416
417SurfaceType GetFormatType(PixelFormat pixel_format) {
418 if (static_cast<std::size_t>(pixel_format) <
419 static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
420 return SurfaceType::ColorTexture;
421 }
422
423 if (static_cast<std::size_t>(pixel_format) <
424 static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
425 return SurfaceType::Depth;
426 }
427
428 if (static_cast<std::size_t>(pixel_format) <
429 static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
430 return SurfaceType::DepthStencil;
431 }
432
433 // TODO(Subv): Implement the other formats
434 ASSERT(false);
435
436 return SurfaceType::Invalid;
437}
438
439bool IsPixelFormatASTC(PixelFormat format) {
440 switch (format) {
441 case PixelFormat::ASTC_2D_4X4:
442 case PixelFormat::ASTC_2D_5X4:
443 case PixelFormat::ASTC_2D_8X8:
444 case PixelFormat::ASTC_2D_8X5:
445 case PixelFormat::ASTC_2D_4X4_SRGB:
446 case PixelFormat::ASTC_2D_5X4_SRGB:
447 case PixelFormat::ASTC_2D_8X8_SRGB:
448 case PixelFormat::ASTC_2D_8X5_SRGB:
449 return true;
450 default:
451 return false;
452 }
453}
454
455std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
456 switch (format) {
457 case PixelFormat::ASTC_2D_4X4:
458 return {4, 4};
459 case PixelFormat::ASTC_2D_5X4:
460 return {5, 4};
461 case PixelFormat::ASTC_2D_8X8:
462 return {8, 8};
463 case PixelFormat::ASTC_2D_8X5:
464 return {8, 5};
465 case PixelFormat::ASTC_2D_4X4_SRGB:
466 return {4, 4};
467 case PixelFormat::ASTC_2D_5X4_SRGB:
468 return {5, 4};
469 case PixelFormat::ASTC_2D_8X8_SRGB:
470 return {8, 8};
471 case PixelFormat::ASTC_2D_8X5_SRGB:
472 return {8, 5};
473 default:
474 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
475 UNREACHABLE();
476 }
477}
478
479bool IsFormatBCn(PixelFormat format) {
480 switch (format) {
481 case PixelFormat::DXT1:
482 case PixelFormat::DXT23:
483 case PixelFormat::DXT45:
484 case PixelFormat::DXN1:
485 case PixelFormat::DXN2SNORM:
486 case PixelFormat::DXN2UNORM:
487 case PixelFormat::BC7U:
488 case PixelFormat::BC6H_UF16:
489 case PixelFormat::BC6H_SF16:
490 case PixelFormat::DXT1_SRGB:
491 case PixelFormat::DXT23_SRGB:
492 case PixelFormat::DXT45_SRGB:
493 case PixelFormat::BC7U_SRGB:
494 return true;
495 }
496 return false;
497}
498
499} // namespace VideoCore::Surface
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
new file mode 100644
index 000000000..3232e437f
--- /dev/null
+++ b/src/video_core/surface.h
@@ -0,0 +1,385 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <climits>
8#include <utility>
9#include "common/assert.h"
10#include "common/common_types.h"
11#include "common/logging/log.h"
12#include "video_core/gpu.h"
13#include "video_core/textures/texture.h"
14
15namespace VideoCore::Surface {
16
17enum class PixelFormat {
18 ABGR8U = 0,
19 ABGR8S = 1,
20 ABGR8UI = 2,
21 B5G6R5U = 3,
22 A2B10G10R10U = 4,
23 A1B5G5R5U = 5,
24 R8U = 6,
25 R8UI = 7,
26 RGBA16F = 8,
27 RGBA16U = 9,
28 RGBA16UI = 10,
29 R11FG11FB10F = 11,
30 RGBA32UI = 12,
31 DXT1 = 13,
32 DXT23 = 14,
33 DXT45 = 15,
34 DXN1 = 16, // This is also known as BC4
35 DXN2UNORM = 17,
36 DXN2SNORM = 18,
37 BC7U = 19,
38 BC6H_UF16 = 20,
39 BC6H_SF16 = 21,
40 ASTC_2D_4X4 = 22,
41 G8R8U = 23,
42 G8R8S = 24,
43 BGRA8 = 25,
44 RGBA32F = 26,
45 RG32F = 27,
46 R32F = 28,
47 R16F = 29,
48 R16U = 30,
49 R16S = 31,
50 R16UI = 32,
51 R16I = 33,
52 RG16 = 34,
53 RG16F = 35,
54 RG16UI = 36,
55 RG16I = 37,
56 RG16S = 38,
57 RGB32F = 39,
58 RGBA8_SRGB = 40,
59 RG8U = 41,
60 RG8S = 42,
61 RG32UI = 43,
62 R32UI = 44,
63 ASTC_2D_8X8 = 45,
64 ASTC_2D_8X5 = 46,
65 ASTC_2D_5X4 = 47,
66 BGRA8_SRGB = 48,
67 DXT1_SRGB = 49,
68 DXT23_SRGB = 50,
69 DXT45_SRGB = 51,
70 BC7U_SRGB = 52,
71 ASTC_2D_4X4_SRGB = 53,
72 ASTC_2D_8X8_SRGB = 54,
73 ASTC_2D_8X5_SRGB = 55,
74 ASTC_2D_5X4_SRGB = 56,
75
76 MaxColorFormat,
77
78 // Depth formats
79 Z32F = 57,
80 Z16 = 58,
81
82 MaxDepthFormat,
83
84 // DepthStencil formats
85 Z24S8 = 59,
86 S8Z24 = 60,
87 Z32FS8 = 61,
88
89 MaxDepthStencilFormat,
90
91 Max = MaxDepthStencilFormat,
92 Invalid = 255,
93};
94
95static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
96
97enum class ComponentType {
98 Invalid = 0,
99 SNorm = 1,
100 UNorm = 2,
101 SInt = 3,
102 UInt = 4,
103 Float = 5,
104};
105
106enum class SurfaceType {
107 ColorTexture = 0,
108 Depth = 1,
109 DepthStencil = 2,
110 Fill = 3,
111 Invalid = 4,
112};
113
114enum class SurfaceTarget {
115 Texture1D,
116 Texture2D,
117 Texture3D,
118 Texture1DArray,
119 Texture2DArray,
120 TextureCubemap,
121};
122
123/**
124 * Gets the compression factor for the specified PixelFormat. This applies to just the
125 * "compressed width" and "compressed height", not the overall compression factor of a
126 * compressed image. This is used for maintaining proper surface sizes for compressed
127 * texture formats.
128 */
129static constexpr u32 GetCompressionFactor(PixelFormat format) {
130 if (format == PixelFormat::Invalid)
131 return 0;
132
133 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
134 1, // ABGR8U
135 1, // ABGR8S
136 1, // ABGR8UI
137 1, // B5G6R5U
138 1, // A2B10G10R10U
139 1, // A1B5G5R5U
140 1, // R8U
141 1, // R8UI
142 1, // RGBA16F
143 1, // RGBA16U
144 1, // RGBA16UI
145 1, // R11FG11FB10F
146 1, // RGBA32UI
147 4, // DXT1
148 4, // DXT23
149 4, // DXT45
150 4, // DXN1
151 4, // DXN2UNORM
152 4, // DXN2SNORM
153 4, // BC7U
154 4, // BC6H_UF16
155 4, // BC6H_SF16
156 4, // ASTC_2D_4X4
157 1, // G8R8U
158 1, // G8R8S
159 1, // BGRA8
160 1, // RGBA32F
161 1, // RG32F
162 1, // R32F
163 1, // R16F
164 1, // R16U
165 1, // R16S
166 1, // R16UI
167 1, // R16I
168 1, // RG16
169 1, // RG16F
170 1, // RG16UI
171 1, // RG16I
172 1, // RG16S
173 1, // RGB32F
174 1, // RGBA8_SRGB
175 1, // RG8U
176 1, // RG8S
177 1, // RG32UI
178 1, // R32UI
179 4, // ASTC_2D_8X8
180 4, // ASTC_2D_8X5
181 4, // ASTC_2D_5X4
182 1, // BGRA8_SRGB
183 4, // DXT1_SRGB
184 4, // DXT23_SRGB
185 4, // DXT45_SRGB
186 4, // BC7U_SRGB
187 4, // ASTC_2D_4X4_SRGB
188 4, // ASTC_2D_8X8_SRGB
189 4, // ASTC_2D_8X5_SRGB
190 4, // ASTC_2D_5X4_SRGB
191 1, // Z32F
192 1, // Z16
193 1, // Z24S8
194 1, // S8Z24
195 1, // Z32FS8
196 }};
197
198 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
199 return compression_factor_table[static_cast<std::size_t>(format)];
200}
201
202static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
203 if (format == PixelFormat::Invalid)
204 return 0;
205
206 constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
207 1, // ABGR8U
208 1, // ABGR8S
209 1, // ABGR8UI
210 1, // B5G6R5U
211 1, // A2B10G10R10U
212 1, // A1B5G5R5U
213 1, // R8U
214 1, // R8UI
215 1, // RGBA16F
216 1, // RGBA16U
217 1, // RGBA16UI
218 1, // R11FG11FB10F
219 1, // RGBA32UI
220 4, // DXT1
221 4, // DXT23
222 4, // DXT45
223 4, // DXN1
224 4, // DXN2UNORM
225 4, // DXN2SNORM
226 4, // BC7U
227 4, // BC6H_UF16
228 4, // BC6H_SF16
229 4, // ASTC_2D_4X4
230 1, // G8R8U
231 1, // G8R8S
232 1, // BGRA8
233 1, // RGBA32F
234 1, // RG32F
235 1, // R32F
236 1, // R16F
237 1, // R16U
238 1, // R16S
239 1, // R16UI
240 1, // R16I
241 1, // RG16
242 1, // RG16F
243 1, // RG16UI
244 1, // RG16I
245 1, // RG16S
246 1, // RGB32F
247 1, // RGBA8_SRGB
248 1, // RG8U
249 1, // RG8S
250 1, // RG32UI
251 1, // R32UI
252 8, // ASTC_2D_8X8
253 5, // ASTC_2D_8X5
254 4, // ASTC_2D_5X4
255 1, // BGRA8_SRGB
256 4, // DXT1_SRGB
257 4, // DXT23_SRGB
258 4, // DXT45_SRGB
259 4, // BC7U_SRGB
260 4, // ASTC_2D_4X4_SRGB
261 8, // ASTC_2D_8X8_SRGB
262 5, // ASTC_2D_8X5_SRGB
263 4, // ASTC_2D_5X4_SRGB
264 1, // Z32F
265 1, // Z16
266 1, // Z24S8
267 1, // S8Z24
268 1, // Z32FS8
269 }};
270
271 ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
272 return block_height_table[static_cast<std::size_t>(format)];
273}
274
275static constexpr u32 GetFormatBpp(PixelFormat format) {
276 if (format == PixelFormat::Invalid)
277 return 0;
278
279 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
280 32, // ABGR8U
281 32, // ABGR8S
282 32, // ABGR8UI
283 16, // B5G6R5U
284 32, // A2B10G10R10U
285 16, // A1B5G5R5U
286 8, // R8U
287 8, // R8UI
288 64, // RGBA16F
289 64, // RGBA16U
290 64, // RGBA16UI
291 32, // R11FG11FB10F
292 128, // RGBA32UI
293 64, // DXT1
294 128, // DXT23
295 128, // DXT45
296 64, // DXN1
297 128, // DXN2UNORM
298 128, // DXN2SNORM
299 128, // BC7U
300 128, // BC6H_UF16
301 128, // BC6H_SF16
302 32, // ASTC_2D_4X4
303 16, // G8R8U
304 16, // G8R8S
305 32, // BGRA8
306 128, // RGBA32F
307 64, // RG32F
308 32, // R32F
309 16, // R16F
310 16, // R16U
311 16, // R16S
312 16, // R16UI
313 16, // R16I
314 32, // RG16
315 32, // RG16F
316 32, // RG16UI
317 32, // RG16I
318 32, // RG16S
319 96, // RGB32F
320 32, // RGBA8_SRGB
321 16, // RG8U
322 16, // RG8S
323 64, // RG32UI
324 32, // R32UI
325 16, // ASTC_2D_8X8
326 16, // ASTC_2D_8X5
327 32, // ASTC_2D_5X4
328 32, // BGRA8_SRGB
329 64, // DXT1_SRGB
330 128, // DXT23_SRGB
331 128, // DXT45_SRGB
332 128, // BC7U
333 32, // ASTC_2D_4X4_SRGB
334 16, // ASTC_2D_8X8_SRGB
335 16, // ASTC_2D_8X5_SRGB
336 32, // ASTC_2D_5X4_SRGB
337 32, // Z32F
338 16, // Z16
339 32, // Z24S8
340 32, // S8Z24
341 64, // Z32FS8
342 }};
343
344 ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
345 return bpp_table[static_cast<std::size_t>(format)];
346}
347
348/// Returns the sizer in bytes of the specified pixel format
349static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
350 if (pixel_format == PixelFormat::Invalid) {
351 return 0;
352 }
353 return GetFormatBpp(pixel_format) / CHAR_BIT;
354}
355
356SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type);
357
358bool SurfaceTargetIsLayered(SurfaceTarget target);
359
360PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format);
361
362PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format);
363
364PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
365 Tegra::Texture::ComponentType component_type,
366 bool is_srgb);
367
368ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type);
369
370ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format);
371
372PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format);
373
374ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format);
375
376SurfaceType GetFormatType(PixelFormat pixel_format);
377
378bool IsPixelFormatASTC(PixelFormat format);
379
380std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
381
382/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
383bool IsFormatBCn(PixelFormat format);
384
385} // namespace VideoCore::Surface
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp
index 0a8f2bd9e..9156ce802 100644
--- a/src/web_service/telemetry_json.cpp
+++ b/src/web_service/telemetry_json.cpp
@@ -102,16 +102,27 @@ void TelemetryJson::Complete() {
102 impl->SerializeSection(Telemetry::FieldType::App, "App"); 102 impl->SerializeSection(Telemetry::FieldType::App, "App");
103 impl->SerializeSection(Telemetry::FieldType::Session, "Session"); 103 impl->SerializeSection(Telemetry::FieldType::Session, "Session");
104 impl->SerializeSection(Telemetry::FieldType::Performance, "Performance"); 104 impl->SerializeSection(Telemetry::FieldType::Performance, "Performance");
105 impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
106 impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig"); 105 impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
107 impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem"); 106 impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
108 107
109 auto content = impl->TopSection().dump(); 108 auto content = impl->TopSection().dump();
110 // Send the telemetry async but don't handle the errors since they were written to the log 109 // Send the telemetry async but don't handle the errors since they were written to the log
111 Common::DetachedTasks::AddTask( 110 Common::DetachedTasks::AddTask([host{impl->host}, content]() {
112 [host{impl->host}, username{impl->username}, token{impl->token}, content]() { 111 Client{host, "", ""}.PostJson("/telemetry", content, true);
113 Client{host, username, token}.PostJson("/telemetry", content, true); 112 });
114 }); 113}
114
115bool TelemetryJson::SubmitTestcase() {
116 impl->SerializeSection(Telemetry::FieldType::App, "App");
117 impl->SerializeSection(Telemetry::FieldType::Session, "Session");
118 impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
119 impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
120
121 auto content = impl->TopSection().dump();
122 Client client(impl->host, impl->username, impl->token);
123 auto value = client.PostJson("/gamedb/testcase", content, false);
124
125 return value.result_code == Common::WebResult::Code::Success;
115} 126}
116 127
117} // namespace WebService 128} // namespace WebService
diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h
index 93371414a..dfd202829 100644
--- a/src/web_service/telemetry_json.h
+++ b/src/web_service/telemetry_json.h
@@ -35,6 +35,7 @@ public:
35 void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override; 35 void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override;
36 36
37 void Complete() override; 37 void Complete() override;
38 bool SubmitTestcase() override;
38 39
39private: 40private:
40 struct Impl; 41 struct Impl;
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 9379d9110..f9ca2948e 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -56,6 +56,8 @@ add_executable(yuzu
56 main.h 56 main.h
57 ui_settings.cpp 57 ui_settings.cpp
58 ui_settings.h 58 ui_settings.h
59 util/limitable_input_dialog.cpp
60 util/limitable_input_dialog.h
59 util/spinbox.cpp 61 util/spinbox.cpp
60 util/spinbox.h 62 util/spinbox.h
61 util/util.cpp 63 util/util.cpp
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index 91e754274..5f0896f84 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -5,6 +5,7 @@
5#include <QButtonGroup> 5#include <QButtonGroup>
6#include <QMessageBox> 6#include <QMessageBox>
7#include <QPushButton> 7#include <QPushButton>
8#include <QtConcurrent/qtconcurrentrun.h>
8#include "common/logging/log.h" 9#include "common/logging/log.h"
9#include "common/telemetry.h" 10#include "common/telemetry.h"
10#include "core/core.h" 11#include "core/core.h"
@@ -23,6 +24,8 @@ CompatDB::CompatDB(QWidget* parent)
23 connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext); 24 connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext);
24 connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext); 25 connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext);
25 connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); 26 connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit);
27 connect(&testcase_watcher, &QFutureWatcher<bool>::finished, this,
28 &CompatDB::OnTestcaseSubmitted);
26} 29}
27 30
28CompatDB::~CompatDB() = default; 31CompatDB::~CompatDB() = default;
@@ -48,18 +51,38 @@ void CompatDB::Submit() {
48 } 51 }
49 break; 52 break;
50 case CompatDBPage::Final: 53 case CompatDBPage::Final:
54 back();
51 LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); 55 LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
52 Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility", 56 Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility",
53 compatibility->checkedId()); 57 compatibility->checkedId());
54 // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a 58
55 // workaround 59 button(NextButton)->setEnabled(false);
60 button(NextButton)->setText(tr("Submitting"));
56 button(QWizard::CancelButton)->setVisible(false); 61 button(QWizard::CancelButton)->setVisible(false);
62
63 testcase_watcher.setFuture(QtConcurrent::run(
64 [this]() { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); }));
57 break; 65 break;
58 default: 66 default:
59 LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); 67 LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
60 } 68 }
61} 69}
62 70
71void CompatDB::OnTestcaseSubmitted() {
72 if (!testcase_watcher.result()) {
73 QMessageBox::critical(this, tr("Communication error"),
74 tr("An error occured while sending the Testcase"));
75 button(NextButton)->setEnabled(true);
76 button(NextButton)->setText(tr("Next"));
77 button(QWizard::CancelButton)->setVisible(true);
78 } else {
79 next();
80 // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
81 // workaround
82 button(QWizard::CancelButton)->setVisible(false);
83 }
84}
85
63void CompatDB::EnableNext() { 86void CompatDB::EnableNext() {
64 button(NextButton)->setEnabled(true); 87 button(NextButton)->setEnabled(true);
65} 88}
diff --git a/src/yuzu/compatdb.h b/src/yuzu/compatdb.h
index ca0dd11d6..5381f67f7 100644
--- a/src/yuzu/compatdb.h
+++ b/src/yuzu/compatdb.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <QFutureWatcher>
8#include <QWizard> 9#include <QWizard>
9 10
10namespace Ui { 11namespace Ui {
@@ -19,8 +20,11 @@ public:
19 ~CompatDB(); 20 ~CompatDB();
20 21
21private: 22private:
23 QFutureWatcher<bool> testcase_watcher;
24
22 std::unique_ptr<Ui::CompatDB> ui; 25 std::unique_ptr<Ui::CompatDB> ui;
23 26
24 void Submit(); 27 void Submit();
28 void OnTestcaseSubmitted();
25 void EnableNext(); 29 void EnableNext();
26}; 30};
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 1b8aa7de2..b4b4a4a56 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -6,20 +6,20 @@
6#include <QFileDialog> 6#include <QFileDialog>
7#include <QGraphicsItem> 7#include <QGraphicsItem>
8#include <QGraphicsScene> 8#include <QGraphicsScene>
9#include <QInputDialog> 9#include <QHeaderView>
10#include <QMessageBox> 10#include <QMessageBox>
11#include <QStandardItemModel> 11#include <QStandardItemModel>
12#include <QTreeView> 12#include <QTreeView>
13#include <QVBoxLayout> 13#include <QVBoxLayout>
14#include "common/common_paths.h" 14#include "common/assert.h"
15#include "common/logging/backend.h" 15#include "common/file_util.h"
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/core.h" 17#include "core/core.h"
18#include "core/hle/service/acc/profile_manager.h" 18#include "core/hle/service/acc/profile_manager.h"
19#include "core/settings.h" 19#include "core/settings.h"
20#include "ui_configure_system.h" 20#include "ui_configure_system.h"
21#include "yuzu/configuration/configure_system.h" 21#include "yuzu/configuration/configure_system.h"
22#include "yuzu/main.h" 22#include "yuzu/util/limitable_input_dialog.h"
23 23
24namespace { 24namespace {
25constexpr std::array<int, 12> days_in_month = {{ 25constexpr std::array<int, 12> days_in_month = {{
@@ -83,6 +83,12 @@ QPixmap GetIcon(Service::Account::UUID uuid) {
83 83
84 return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 84 return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
85} 85}
86
87QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_text) {
88 return LimitableInputDialog::GetText(parent, ConfigureSystem::tr("Enter Username"),
89 description_text, 1,
90 static_cast<int>(Service::Account::profile_username_size));
91}
86} // Anonymous namespace 92} // Anonymous namespace
87 93
88ConfigureSystem::ConfigureSystem(QWidget* parent) 94ConfigureSystem::ConfigureSystem(QWidget* parent)
@@ -244,15 +250,13 @@ void ConfigureSystem::SelectUser(const QModelIndex& index) {
244} 250}
245 251
246void ConfigureSystem::AddUser() { 252void ConfigureSystem::AddUser() {
247 const auto uuid = Service::Account::UUID::Generate();
248
249 bool ok = false;
250 const auto username = 253 const auto username =
251 QInputDialog::getText(this, tr("Enter Username"), tr("Enter a username for the new user:"), 254 GetProfileUsernameFromUser(this, tr("Enter a username for the new user:"));
252 QLineEdit::Normal, QString(), &ok); 255 if (username.isEmpty()) {
253 if (!ok)
254 return; 256 return;
257 }
255 258
259 const auto uuid = Service::Account::UUID::Generate();
256 profile_manager->CreateNewUser(uuid, username.toStdString()); 260 profile_manager->CreateNewUser(uuid, username.toStdString());
257 261
258 item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); 262 item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
@@ -267,23 +271,14 @@ void ConfigureSystem::RenameUser() {
267 if (!profile_manager->GetProfileBase(*uuid, profile)) 271 if (!profile_manager->GetProfileBase(*uuid, profile))
268 return; 272 return;
269 273
270 bool ok = false; 274 const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:"));
271 const auto old_username = GetAccountUsername(*profile_manager, *uuid); 275 if (new_username.isEmpty()) {
272 const auto new_username =
273 QInputDialog::getText(this, tr("Enter Username"), tr("Enter a new username:"),
274 QLineEdit::Normal, old_username, &ok);
275
276 if (!ok)
277 return; 276 return;
277 }
278 278
279 std::fill(profile.username.begin(), profile.username.end(), '\0');
280 const auto username_std = new_username.toStdString(); 279 const auto username_std = new_username.toStdString();
281 if (username_std.size() > profile.username.size()) { 280 std::fill(profile.username.begin(), profile.username.end(), '\0');
282 std::copy_n(username_std.begin(), std::min(profile.username.size(), username_std.size()), 281 std::copy(username_std.begin(), username_std.end(), profile.username.begin());
283 profile.username.begin());
284 } else {
285 std::copy(username_std.begin(), username_std.end(), profile.username.begin());
286 }
287 282
288 profile_manager->SetProfileBase(*uuid, profile); 283 profile_manager->SetProfileBase(*uuid, profile);
289 284
diff --git a/src/yuzu/util/limitable_input_dialog.cpp b/src/yuzu/util/limitable_input_dialog.cpp
new file mode 100644
index 000000000..edd78e579
--- /dev/null
+++ b/src/yuzu/util/limitable_input_dialog.cpp
@@ -0,0 +1,59 @@
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 <QDialogButtonBox>
6#include <QLabel>
7#include <QLineEdit>
8#include <QPushButton>
9#include <QVBoxLayout>
10#include "yuzu/util/limitable_input_dialog.h"
11
12LimitableInputDialog::LimitableInputDialog(QWidget* parent) : QDialog{parent} {
13 CreateUI();
14 ConnectEvents();
15}
16
17LimitableInputDialog::~LimitableInputDialog() = default;
18
19void LimitableInputDialog::CreateUI() {
20 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
21
22 text_label = new QLabel(this);
23 text_entry = new QLineEdit(this);
24 buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
25
26 auto* const layout = new QVBoxLayout;
27 layout->addWidget(text_label);
28 layout->addWidget(text_entry);
29 layout->addWidget(buttons);
30
31 setLayout(layout);
32}
33
34void LimitableInputDialog::ConnectEvents() {
35 connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
36 connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
37}
38
39QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, const QString& text,
40 int min_character_limit, int max_character_limit) {
41 Q_ASSERT(min_character_limit <= max_character_limit);
42
43 LimitableInputDialog dialog{parent};
44 dialog.setWindowTitle(title);
45 dialog.text_label->setText(text);
46 dialog.text_entry->setMaxLength(max_character_limit);
47
48 auto* const ok_button = dialog.buttons->button(QDialogButtonBox::Ok);
49 ok_button->setEnabled(false);
50 connect(dialog.text_entry, &QLineEdit::textEdited, [&](const QString& new_text) {
51 ok_button->setEnabled(new_text.length() >= min_character_limit);
52 });
53
54 if (dialog.exec() != QDialog::Accepted) {
55 return {};
56 }
57
58 return dialog.text_entry->text();
59}
diff --git a/src/yuzu/util/limitable_input_dialog.h b/src/yuzu/util/limitable_input_dialog.h
new file mode 100644
index 000000000..164ad7301
--- /dev/null
+++ b/src/yuzu/util/limitable_input_dialog.h
@@ -0,0 +1,31 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDialog>
8
9class QDialogButtonBox;
10class QLabel;
11class QLineEdit;
12
13/// A QDialog that functions similarly to QInputDialog, however, it allows
14/// restricting the minimum and total number of characters that can be entered.
15class LimitableInputDialog final : public QDialog {
16 Q_OBJECT
17public:
18 explicit LimitableInputDialog(QWidget* parent = nullptr);
19 ~LimitableInputDialog() override;
20
21 static QString GetText(QWidget* parent, const QString& title, const QString& text,
22 int min_character_limit, int max_character_limit);
23
24private:
25 void CreateUI();
26 void ConnectEvents();
27
28 QLabel* text_label;
29 QLineEdit* text_entry;
30 QDialogButtonBox* buttons;
31};