diff --git a/src/common/telemetry.h b/src/common/telemetry.h
index 8d6ab986b2ed757ce8c5954fba451032cfcf4344..854a73fae7bad120ff671e49f2f5c6b3a11b89bc 100644
--- a/src/common/telemetry.h
+++ b/src/common/telemetry.h
@@ -153,6 +153,7 @@ struct VisitorInterface : NonCopyable {
 
     /// Completion method, called once all fields have been visited
     virtual void Complete() = 0;
+    virtual bool SubmitTestcase() = 0;
 };
 
 /**
@@ -178,6 +179,9 @@ struct NullVisitor : public VisitorInterface {
     void Visit(const Field<std::chrono::microseconds>& /*field*/) override {}
 
     void Complete() override {}
+    bool SubmitTestcase() override {
+        return false;
+    }
 };
 
 /// 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 1cd2e51b26efd063f1906b9e7b10e9780104ffab..747c46c204ee4d26d2e36ce28206900408ef8488 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 {
 };
 static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
 
-using ProfileUsername = std::array<u8, 0x20>;
+constexpr std::size_t profile_username_size = 32;
+using ProfileUsername = std::array<u8, profile_username_size>;
 using ProfileData = std::array<u8, MAX_DATA>;
 using UserIDArray = std::array<UUID, MAX_USERS>;
 
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index c489da071621538f13bfa802c98919e3b6a5e4e4..f0a831d45968e0d225a4516b0f79265197cb53bc 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -132,11 +132,11 @@ public:
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, nullptr, "BindNoticeEvent"},
-            {1, nullptr, "Unknown1"},
+            {1, nullptr, "UnbindNoticeEvent"},
             {2, nullptr, "GetStatus"},
             {3, nullptr, "GetNotice"},
-            {4, nullptr, "Unknown2"},
-            {5, nullptr, "Unknown3"},
+            {4, nullptr, "EnablePowerRequestNotice"},
+            {5, nullptr, "DisablePowerRequestNotice"},
             {6, nullptr, "ReplyPowerRequest"},
         };
         // clang-format on
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 0de13edd3583506eb55cf9eb7f654a3b19d83e83..a3b08c740d990238b9836ba8a7567417a9e39a71 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -184,4 +184,13 @@ TelemetrySession::~TelemetrySession() {
     backend = nullptr;
 }
 
+bool TelemetrySession::SubmitTestcase() {
+#ifdef ENABLE_WEB_SERVICE
+    field_collection.Accept(*backend);
+    return backend->SubmitTestcase();
+#else
+    return false;
+#endif
+}
+
 } // namespace Core
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index 2a4845797c462f50fc5de18f41a250a4fa89a3dd..023612b79e38ec82b218947868da1b9ba243c60e 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -31,6 +31,12 @@ public:
         field_collection.AddField(type, name, std::move(value));
     }
 
+    /**
+     * Submits a Testcase.
+     * @returns A bool indicating whether the submission succeeded
+     */
+    bool SubmitTestcase();
+
 private:
     Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
     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 c5f7128ec6c9fd3f6b15ba7071eac0dd4e0824af..ddb1a1d69f45cde66178ed65fb556e56565876f6 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -53,6 +53,8 @@ add_library(video_core STATIC
     renderer_opengl/renderer_opengl.h
     renderer_opengl/utils.cpp
     renderer_opengl/utils.h
+    surface.cpp
+    surface.h
     textures/astc.cpp
     textures/astc.h
     textures/decoders.cpp
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7357d20d16830b51a1b54c0396943f26e32d5ef4..d79c509193361cd5365f1272135ce3dfbb003bb6 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) {
     // Reset the current macro.
     executing_macro = 0;
 
-    // The requested macro must have been uploaded already.
-    auto macro_code = uploaded_macros.find(method);
-    if (macro_code == uploaded_macros.end()) {
-        LOG_ERROR(HW_GPU, "Macro {:04X} was not uploaded", method);
+    // Lookup the macro offset
+    const u32 entry{(method - MacroRegistersStart) >> 1};
+    const auto& search{macro_offsets.find(entry)};
+    if (search == macro_offsets.end()) {
+        LOG_CRITICAL(HW_GPU, "macro not found for method 0x{:X}!", method);
+        UNREACHABLE();
         return;
     }
 
     // Execute the current macro.
-    macro_interpreter.Execute(macro_code->second, std::move(parameters));
+    macro_interpreter.Execute(search->second, std::move(parameters));
 }
 
 void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
@@ -97,6 +99,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
         ProcessMacroUpload(value);
         break;
     }
+    case MAXWELL3D_REG_INDEX(macros.bind): {
+        ProcessMacroBind(value);
+        break;
+    }
     case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
     case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
     case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
@@ -158,9 +164,13 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
 }
 
 void Maxwell3D::ProcessMacroUpload(u32 data) {
-    // Store the uploaded macro code to interpret them when they're called.
-    auto& macro = uploaded_macros[regs.macros.entry * 2 + MacroRegistersStart];
-    macro.push_back(data);
+    ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
+               "upload_address exceeded macro_memory size!");
+    macro_memory[regs.macros.upload_address++] = data;
+}
+
+void Maxwell3D::ProcessMacroBind(u32 data) {
+    macro_offsets[regs.macros.entry] = data;
 }
 
 void Maxwell3D::ProcessQueryGet() {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 443affc36d60c38a849b9c4cac498e1b9de57f0b..50873813e8f92846af7a1a7ca2cb3530ff4c522a 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -475,12 +475,13 @@ public:
                 INSERT_PADDING_WORDS(0x45);
 
                 struct {
-                    INSERT_PADDING_WORDS(1);
+                    u32 upload_address;
                     u32 data;
                     u32 entry;
+                    u32 bind;
                 } macros;
 
-                INSERT_PADDING_WORDS(0x189);
+                INSERT_PADDING_WORDS(0x188);
 
                 u32 tfb_enabled;
 
@@ -994,12 +995,25 @@ public:
     /// Returns the texture information for a specific texture in a specific shader stage.
     Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
 
+    /// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
+    /// we've seen used.
+    using MacroMemory = std::array<u32, 0x40000>;
+
+    /// Gets a reference to macro memory.
+    const MacroMemory& GetMacroMemory() const {
+        return macro_memory;
+    }
+
 private:
     void InitializeRegisterDefaults();
 
     VideoCore::RasterizerInterface& rasterizer;
 
-    std::unordered_map<u32, std::vector<u32>> uploaded_macros;
+    /// Start offsets of each macro in macro_memory
+    std::unordered_map<u32, u32> macro_offsets;
+
+    /// Memory for macro code
+    MacroMemory macro_memory;
 
     /// Macro method that is currently being executed / being fed parameters.
     u32 executing_macro = 0;
@@ -1022,9 +1036,12 @@ private:
      */
     void CallMacroMethod(u32 method, std::vector<u32> parameters);
 
-    /// Handles writes to the macro uploading registers.
+    /// Handles writes to the macro uploading register.
     void ProcessMacroUpload(u32 data);
 
+    /// Handles writes to the macro bind register.
+    void ProcessMacroBind(u32 data);
+
     /// Handles a write to the CLEAR_BUFFERS register.
     void ProcessClearBuffers();
 
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index b84da512f3cebb399043d19afe7c211a5016173d..83a6fd875716da42c4b75f3d8606bdb1f90d79b2 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -577,6 +577,10 @@ union Instruction {
         BitField<55, 1, u64> saturate;
     } fmul32;
 
+    union {
+        BitField<52, 1, u64> generates_cc;
+    } op_32;
+
     union {
         BitField<48, 1, u64> is_signed;
     } shift;
@@ -1231,6 +1235,7 @@ union Instruction {
     BitField<60, 1, u64> is_b_gpr;
     BitField<59, 1, u64> is_c_gpr;
     BitField<20, 24, s64> smem_imm;
+    BitField<0, 5, ControlCode> flow_control_code;
 
     Attribute attribute;
     Sampler sampler;
@@ -1658,4 +1663,4 @@ private:
     }
 };
 
-} // namespace Tegra::Shader
\ No newline at end of file
+} // namespace Tegra::Shader
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index f6af132fbf12fcd9ef0542669259baa0b8f98ebd..335a8d4079751bae665aa564621c9ec2330a492e 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -11,7 +11,7 @@ namespace Tegra {
 
 MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
 
-void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> parameters) {
+void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
     Reset();
     registers[1] = parameters[0];
     this->parameters = std::move(parameters);
@@ -19,7 +19,7 @@ void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> pa
     // Execute the code until we hit an exit condition.
     bool keep_executing = true;
     while (keep_executing) {
-        keep_executing = Step(code, false);
+        keep_executing = Step(offset, false);
     }
 
     // Assert the the macro used all the input parameters
@@ -37,10 +37,10 @@ void MacroInterpreter::Reset() {
     next_parameter_index = 1;
 }
 
-bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
+bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
     u32 base_address = pc;
 
-    Opcode opcode = GetOpcode(code);
+    Opcode opcode = GetOpcode(offset);
     pc += 4;
 
     // Update the program counter if we were delayed
@@ -108,7 +108,7 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
 
             delayed_pc = base_address + opcode.GetBranchTarget();
             // Execute one more instruction due to the delay slot.
-            return Step(code, true);
+            return Step(offset, true);
         }
         break;
     }
@@ -121,17 +121,18 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
         // Exit has a delay slot, execute the next instruction
         // Note: Executing an exit during a branch delay slot will cause the instruction at the
         // branch target to be executed before exiting.
-        Step(code, true);
+        Step(offset, true);
         return false;
     }
 
     return true;
 }
 
-MacroInterpreter::Opcode MacroInterpreter::GetOpcode(const std::vector<u32>& code) const {
+MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
+    const auto& macro_memory{maxwell3d.GetMacroMemory()};
     ASSERT((pc % sizeof(u32)) == 0);
-    ASSERT(pc < code.size() * sizeof(u32));
-    return {code[pc / sizeof(u32)]};
+    ASSERT((pc + offset) < macro_memory.size() * sizeof(u32));
+    return {macro_memory[offset + pc / sizeof(u32)]};
 }
 
 u32 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 773684bdebef5d12a6633ec691b78d23a010181b..62d1ce289b3d1f4da12f027f418720960676b491 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -22,10 +22,10 @@ public:
 
     /**
      * Executes the macro code with the specified input parameters.
-     * @param code The macro byte code to execute
-     * @param parameters The parameters of the macro
+     * @param offset Offset to start execution at.
+     * @param parameters The parameters of the macro.
      */
-    void Execute(const std::vector<u32>& code, std::vector<u32> parameters);
+    void Execute(u32 offset, std::vector<u32> parameters);
 
 private:
     enum class Operation : u32 {
@@ -110,11 +110,11 @@ private:
     /**
      * Executes a single macro instruction located at the current program counter. Returns whether
      * the interpreter should keep running.
-     * @param code The macro code to execute.
+     * @param offset Offset to start execution at.
      * @param is_delay_slot Whether the current step is being executed due to a delay slot in a
      * previous instruction.
      */
-    bool Step(const std::vector<u32>& code, bool is_delay_slot);
+    bool Step(u32 offset, bool is_delay_slot);
 
     /// Calculates the result of an ALU operation. src_a OP src_b;
     u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
@@ -127,7 +127,7 @@ private:
     bool EvaluateBranchCondition(BranchCondition cond, u32 value) const;
 
     /// Reads an opcode at the current program counter location.
-    Opcode GetOpcode(const std::vector<u32>& code) const;
+    Opcode GetOpcode(u32 offset) const;
 
     /// Returns the specified register's value. Register 0 is hardcoded to always return 0.
     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 bf381271e04e096a298cb332b3f72051272a5898..a0527fe57373ab7acdce5ee3ac9c094b32cde241 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -30,8 +30,8 @@
 namespace OpenGL {
 
 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
-using PixelFormat = SurfaceParams::PixelFormat;
-using SurfaceType = SurfaceParams::SurfaceType;
+using PixelFormat = VideoCore::Surface::PixelFormat;
+using SurfaceType = VideoCore::Surface::SurfaceType;
 
 MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192));
 MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192));
@@ -104,7 +104,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
     }
 
     ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
-
+    OpenGLState::ApplyDefaultState();
     // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
     state.clip_distance[0] = true;
 
@@ -115,8 +115,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
     state.draw.shader_program = 0;
     state.Apply();
 
-    glEnable(GL_BLEND);
-
     glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
 
     LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
@@ -703,7 +701,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
 
     // Verify that the cached surface is the same size and format as the requested framebuffer
     const auto& params{surface->GetSurfaceParams()};
-    const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)};
+    const auto& pixel_format{
+        VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
     ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
     ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
     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 513d82e3943e8540c3b2eca22e64e4b25ce3d656..0582b069cd826002414bf38c23a48bc5da08692f 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 @@
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/renderer_opengl/gl_rasterizer_cache.h"
 #include "video_core/renderer_opengl/utils.h"
+#include "video_core/surface.h"
 #include "video_core/textures/astc.h"
 #include "video_core/textures/decoders.h"
 #include "video_core/utils.h"
 
 namespace OpenGL {
 
-using SurfaceType = SurfaceParams::SurfaceType;
-using PixelFormat = SurfaceParams::PixelFormat;
-using ComponentType = SurfaceParams::ComponentType;
+using VideoCore::Surface::ComponentTypeFromDepthFormat;
+using VideoCore::Surface::ComponentTypeFromRenderTarget;
+using VideoCore::Surface::ComponentTypeFromTexture;
+using VideoCore::Surface::PixelFormatFromDepthFormat;
+using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
+using VideoCore::Surface::PixelFormatFromTextureFormat;
+using VideoCore::Surface::SurfaceTargetFromTextureType;
 
 struct FormatTuple {
     GLint internal_format;
@@ -35,46 +40,6 @@ struct FormatTuple {
     bool compressed;
 };
 
-static bool IsPixelFormatASTC(PixelFormat format) {
-    switch (format) {
-    case PixelFormat::ASTC_2D_4X4:
-    case PixelFormat::ASTC_2D_5X4:
-    case PixelFormat::ASTC_2D_8X8:
-    case PixelFormat::ASTC_2D_8X5:
-    case PixelFormat::ASTC_2D_4X4_SRGB:
-    case PixelFormat::ASTC_2D_5X4_SRGB:
-    case PixelFormat::ASTC_2D_8X8_SRGB:
-    case PixelFormat::ASTC_2D_8X5_SRGB:
-        return true;
-    default:
-        return false;
-    }
-}
-
-static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
-    switch (format) {
-    case PixelFormat::ASTC_2D_4X4:
-        return {4, 4};
-    case PixelFormat::ASTC_2D_5X4:
-        return {5, 4};
-    case PixelFormat::ASTC_2D_8X8:
-        return {8, 8};
-    case PixelFormat::ASTC_2D_8X5:
-        return {8, 5};
-    case PixelFormat::ASTC_2D_4X4_SRGB:
-        return {4, 4};
-    case PixelFormat::ASTC_2D_5X4_SRGB:
-        return {5, 4};
-    case PixelFormat::ASTC_2D_8X8_SRGB:
-        return {8, 8};
-    case PixelFormat::ASTC_2D_8X5_SRGB:
-        return {8, 5};
-    default:
-        LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
-        UNREACHABLE();
-    }
-}
-
 void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
     auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
     const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)};
@@ -267,7 +232,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
     return params;
 }
 
-static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
+static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{
     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
     {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false},                     // ABGR8S
     {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
      ComponentType::Float, false}, // Z32FS8
 }};
 
-static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) {
+static GLenum SurfaceTargetToGL(SurfaceTarget target) {
     switch (target) {
-    case SurfaceParams::SurfaceTarget::Texture1D:
+    case SurfaceTarget::Texture1D:
         return GL_TEXTURE_1D;
-    case SurfaceParams::SurfaceTarget::Texture2D:
+    case SurfaceTarget::Texture2D:
         return GL_TEXTURE_2D;
-    case SurfaceParams::SurfaceTarget::Texture3D:
+    case SurfaceTarget::Texture3D:
         return GL_TEXTURE_3D;
-    case SurfaceParams::SurfaceTarget::Texture1DArray:
+    case SurfaceTarget::Texture1DArray:
         return GL_TEXTURE_1D_ARRAY;
-    case SurfaceParams::SurfaceTarget::Texture2DArray:
+    case SurfaceTarget::Texture2DArray:
         return GL_TEXTURE_2D_ARRAY;
-    case SurfaceParams::SurfaceTarget::TextureCubemap:
+    case SurfaceTarget::TextureCubemap:
         return GL_TEXTURE_CUBE_MAP;
     }
     LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
@@ -392,31 +357,10 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
     return {0, actual_height, MipWidth(mip_level), 0};
 }
 
-/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
-static bool IsFormatBCn(PixelFormat format) {
-    switch (format) {
-    case PixelFormat::DXT1:
-    case PixelFormat::DXT23:
-    case PixelFormat::DXT45:
-    case PixelFormat::DXN1:
-    case PixelFormat::DXN2SNORM:
-    case PixelFormat::DXN2UNORM:
-    case PixelFormat::BC7U:
-    case PixelFormat::BC6H_UF16:
-    case PixelFormat::BC6H_SF16:
-    case PixelFormat::DXT1_SRGB:
-    case PixelFormat::DXT23_SRGB:
-    case PixelFormat::DXT45_SRGB:
-    case PixelFormat::BC7U_SRGB:
-        return true;
-    }
-    return false;
-}
-
 template <bool morton_to_gl, PixelFormat format>
 void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
                 std::size_t gl_buffer_size, VAddr addr) {
-    constexpr u32 bytes_per_pixel = SurfaceParams::GetBytesPerPixel(format);
+    constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
 
     // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
     // pixel values.
@@ -435,7 +379,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
 }
 
 using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
-                                     SurfaceParams::MaxPixelFormat>;
+                                     VideoCore::Surface::MaxPixelFormat>;
 
 static constexpr GLConversionArray morton_to_gl_fns = {
     // clang-format off
@@ -575,7 +519,7 @@ static constexpr GLConversionArray gl_to_morton_fns = {
 void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
                  std::vector<u8>& gl_buffer, u32 mip_level) {
     u32 depth = params.MipDepth(mip_level);
-    if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
+    if (params.target == SurfaceTarget::Texture2D) {
         // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
         depth = 1U;
     }
@@ -622,13 +566,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
 
     if (src_params.type == SurfaceType::ColorTexture) {
         switch (src_params.target) {
-        case SurfaceParams::SurfaceTarget::Texture2D:
+        case SurfaceTarget::Texture2D:
             glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
                                    GL_TEXTURE_2D, src_surface->Texture().handle, 0);
             glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
                                    0, 0);
             break;
-        case SurfaceParams::SurfaceTarget::TextureCubemap:
+        case SurfaceTarget::TextureCubemap:
             glFramebufferTexture2D(
                 GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
                 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,
                 GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
             break;
-        case SurfaceParams::SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::Texture2DArray:
             glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
                                       src_surface->Texture().handle, 0, 0);
             glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
             break;
-        case SurfaceParams::SurfaceTarget::Texture3D:
+        case SurfaceTarget::Texture3D:
             glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
                                    SurfaceTargetToGL(src_params.target),
                                    src_surface->Texture().handle, 0, 0);
@@ -658,13 +602,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
         }
 
         switch (dst_params.target) {
-        case SurfaceParams::SurfaceTarget::Texture2D:
+        case SurfaceTarget::Texture2D:
             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
                                    GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
             glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
                                    0, 0);
             break;
-        case SurfaceParams::SurfaceTarget::TextureCubemap:
+        case SurfaceTarget::TextureCubemap:
             glFramebufferTexture2D(
                 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
                 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,
                 GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
             break;
-        case SurfaceParams::SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::Texture2DArray:
             glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
                                       dst_surface->Texture().handle, 0, 0);
             glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
             break;
 
-        case SurfaceParams::SurfaceTarget::Texture3D:
+        case SurfaceTarget::Texture3D:
             glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
                                    SurfaceTargetToGL(dst_params.target),
                                    dst_surface->Texture().handle, 0, 0);
@@ -800,21 +744,21 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
         UNREACHABLE();
     } else {
         switch (dst_params.target) {
-        case SurfaceParams::SurfaceTarget::Texture1D:
+        case SurfaceTarget::Texture1D:
             glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format,
                                 dest_format.type, nullptr);
             break;
-        case SurfaceParams::SurfaceTarget::Texture2D:
+        case SurfaceTarget::Texture2D:
             glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height,
                                 dest_format.format, dest_format.type, nullptr);
             break;
-        case SurfaceParams::SurfaceTarget::Texture3D:
-        case SurfaceParams::SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::Texture3D:
+        case SurfaceTarget::Texture2DArray:
             glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height,
                                 static_cast<GLsizei>(dst_params.depth), dest_format.format,
                                 dest_format.type, nullptr);
             break;
-        case SurfaceParams::SurfaceTarget::TextureCubemap:
+        case SurfaceTarget::TextureCubemap:
             glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0,
                                 static_cast<GLint>(cubemap_face), width, height, 1,
                                 dest_format.format, dest_format.type, nullptr);
@@ -851,17 +795,17 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
     if (!format_tuple.compressed) {
         // Only pre-create the texture for non-compressed textures.
         switch (params.target) {
-        case SurfaceParams::SurfaceTarget::Texture1D:
+        case SurfaceTarget::Texture1D:
             glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
                            format_tuple.internal_format, rect.GetWidth());
             break;
-        case SurfaceParams::SurfaceTarget::Texture2D:
-        case SurfaceParams::SurfaceTarget::TextureCubemap:
+        case SurfaceTarget::Texture2D:
+        case SurfaceTarget::TextureCubemap:
             glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
                            format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
             break;
-        case SurfaceParams::SurfaceTarget::Texture3D:
-        case SurfaceParams::SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::Texture3D:
+        case SurfaceTarget::Texture2DArray:
             glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
                            format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
                            params.depth);
@@ -916,7 +860,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
 
     S8Z24 s8z24_pixel{};
     Z24S8 z24s8_pixel{};
-    constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::S8Z24)};
+    constexpr auto bpp{GetBytesPerPixel(PixelFormat::S8Z24)};
     for (std::size_t y = 0; y < height; ++y) {
         for (std::size_t x = 0; x < width; ++x) {
             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
 }
 
 static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
-    constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::G8R8U)};
+    constexpr auto bpp{GetBytesPerPixel(PixelFormat::G8R8U)};
     for (std::size_t y = 0; y < height; ++y) {
         for (std::size_t x = 0; x < width; ++x) {
             const std::size_t offset{bpp * (y * width + x)};
@@ -1042,7 +986,7 @@ void CachedSurface::FlushGLBuffer() {
 
     const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
     // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
-    ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0);
+    ASSERT(params.width * GetBytesPerPixel(params.pixel_format) % 4 == 0);
     glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
     ASSERT(!tuple.compressed);
     glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
@@ -1074,7 +1018,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
     std::size_t buffer_offset =
         static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
                                  static_cast<std::size_t>(x0)) *
-        SurfaceParams::GetBytesPerPixel(params.pixel_format);
+        GetBytesPerPixel(params.pixel_format);
 
     const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
     const GLuint target_tex = texture.handle;
@@ -1090,35 +1034,34 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
     cur_state.Apply();
 
     // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
-    ASSERT(params.MipWidth(mip_map) * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 ==
-           0);
+    ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0);
     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
 
     GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
     glActiveTexture(GL_TEXTURE0);
     if (tuple.compressed) {
         switch (params.target) {
-        case SurfaceParams::SurfaceTarget::Texture2D:
+        case SurfaceTarget::Texture2D:
             glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
                                    static_cast<GLsizei>(params.MipWidth(mip_map)),
                                    static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
                                    &gl_buffer[mip_map][buffer_offset]);
             break;
-        case SurfaceParams::SurfaceTarget::Texture3D:
+        case SurfaceTarget::Texture3D:
             glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
                                    static_cast<GLsizei>(params.MipWidth(mip_map)),
                                    static_cast<GLsizei>(params.MipHeight(mip_map)),
                                    static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
                                    &gl_buffer[mip_map][buffer_offset]);
             break;
-        case SurfaceParams::SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::Texture2DArray:
             glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
                                    static_cast<GLsizei>(params.MipWidth(mip_map)),
                                    static_cast<GLsizei>(params.MipHeight(mip_map)),
                                    static_cast<GLsizei>(params.depth), 0, image_size,
                                    &gl_buffer[mip_map][buffer_offset]);
             break;
-        case SurfaceParams::SurfaceTarget::TextureCubemap: {
+        case SurfaceTarget::TextureCubemap: {
             GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
             for (std::size_t face = 0; face < params.depth; ++face) {
                 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,
     } else {
 
         switch (params.target) {
-        case SurfaceParams::SurfaceTarget::Texture1D:
+        case SurfaceTarget::Texture1D:
             glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
                             static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
                             &gl_buffer[mip_map][buffer_offset]);
             break;
-        case SurfaceParams::SurfaceTarget::Texture2D:
+        case SurfaceTarget::Texture2D:
             glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
                             static_cast<GLsizei>(rect.GetWidth()),
                             static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
                             &gl_buffer[mip_map][buffer_offset]);
             break;
-        case SurfaceParams::SurfaceTarget::Texture3D:
+        case SurfaceTarget::Texture3D:
             glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
                             static_cast<GLsizei>(rect.GetWidth()),
                             static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
                             tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
             break;
-        case SurfaceParams::SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::Texture2DArray:
             glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
                             static_cast<GLsizei>(rect.GetWidth()),
                             static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
                             tuple.type, &gl_buffer[mip_map][buffer_offset]);
             break;
-        case SurfaceParams::SurfaceTarget::TextureCubemap: {
+        case SurfaceTarget::TextureCubemap: {
             std::size_t start = buffer_offset;
             for (std::size_t face = 0; face < params.depth; ++face) {
                 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
@@ -1341,8 +1284,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
     // For compatible surfaces, we can just do fast glCopyImageSubData based copy
     if (old_params.target == new_params.target && old_params.type == new_params.type &&
         old_params.depth == new_params.depth && old_params.depth == 1 &&
-        SurfaceParams::GetFormatBpp(old_params.pixel_format) ==
-            SurfaceParams::GetFormatBpp(new_params.pixel_format)) {
+        GetFormatBpp(old_params.pixel_format) == GetFormatBpp(new_params.pixel_format)) {
         FastCopySurface(old_surface, new_surface);
         return new_surface;
     }
@@ -1355,13 +1297,14 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
     const bool is_blit{old_params.pixel_format == new_params.pixel_format};
 
     switch (new_params.target) {
-    case SurfaceParams::SurfaceTarget::Texture2D:
+    case SurfaceTarget::Texture2D:
         if (is_blit) {
             BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
         } else {
             CopySurface(old_surface, new_surface, copy_pbo.handle);
         }
         break;
+
     case SurfaceParams::SurfaceTarget::TextureCubemap:
     case SurfaceParams::SurfaceTarget::Texture3D:
     case SurfaceParams::SurfaceTarget::Texture2DArray:
@@ -1374,7 +1317,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
     }
 
     return new_surface;
-} // namespace OpenGL
+}
 
 Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const {
     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 e72f4f2d2707e61a8098ec75917f2d5f466debf2..f255f4419c6deb3100aa4908b4c5b8016197db66 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 @@
 #include <array>
 #include <map>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "common/alignment.h"
@@ -18,6 +19,7 @@
 #include "video_core/rasterizer_cache.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
 #include "video_core/renderer_opengl/gl_shader_gen.h"
+#include "video_core/surface.h"
 #include "video_core/textures/decoders.h"
 #include "video_core/textures/texture.h"
 
@@ -27,135 +29,12 @@ class CachedSurface;
 using Surface = std::shared_ptr<CachedSurface>;
 using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
 
-struct SurfaceParams {
-    enum class PixelFormat {
-        ABGR8U = 0,
-        ABGR8S = 1,
-        ABGR8UI = 2,
-        B5G6R5U = 3,
-        A2B10G10R10U = 4,
-        A1B5G5R5U = 5,
-        R8U = 6,
-        R8UI = 7,
-        RGBA16F = 8,
-        RGBA16U = 9,
-        RGBA16UI = 10,
-        R11FG11FB10F = 11,
-        RGBA32UI = 12,
-        DXT1 = 13,
-        DXT23 = 14,
-        DXT45 = 15,
-        DXN1 = 16, // This is also known as BC4
-        DXN2UNORM = 17,
-        DXN2SNORM = 18,
-        BC7U = 19,
-        BC6H_UF16 = 20,
-        BC6H_SF16 = 21,
-        ASTC_2D_4X4 = 22,
-        G8R8U = 23,
-        G8R8S = 24,
-        BGRA8 = 25,
-        RGBA32F = 26,
-        RG32F = 27,
-        R32F = 28,
-        R16F = 29,
-        R16U = 30,
-        R16S = 31,
-        R16UI = 32,
-        R16I = 33,
-        RG16 = 34,
-        RG16F = 35,
-        RG16UI = 36,
-        RG16I = 37,
-        RG16S = 38,
-        RGB32F = 39,
-        RGBA8_SRGB = 40,
-        RG8U = 41,
-        RG8S = 42,
-        RG32UI = 43,
-        R32UI = 44,
-        ASTC_2D_8X8 = 45,
-        ASTC_2D_8X5 = 46,
-        ASTC_2D_5X4 = 47,
-        BGRA8_SRGB = 48,
-        DXT1_SRGB = 49,
-        DXT23_SRGB = 50,
-        DXT45_SRGB = 51,
-        BC7U_SRGB = 52,
-        ASTC_2D_4X4_SRGB = 53,
-        ASTC_2D_8X8_SRGB = 54,
-        ASTC_2D_8X5_SRGB = 55,
-        ASTC_2D_5X4_SRGB = 56,
-
-        MaxColorFormat,
-
-        // Depth formats
-        Z32F = 57,
-        Z16 = 58,
-
-        MaxDepthFormat,
-
-        // DepthStencil formats
-        Z24S8 = 59,
-        S8Z24 = 60,
-        Z32FS8 = 61,
-
-        MaxDepthStencilFormat,
-
-        Max = MaxDepthStencilFormat,
-        Invalid = 255,
-    };
-
-    static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
-
-    enum class ComponentType {
-        Invalid = 0,
-        SNorm = 1,
-        UNorm = 2,
-        SInt = 3,
-        UInt = 4,
-        Float = 5,
-    };
-
-    enum class SurfaceType {
-        ColorTexture = 0,
-        Depth = 1,
-        DepthStencil = 2,
-        Fill = 3,
-        Invalid = 4,
-    };
-
-    enum class SurfaceTarget {
-        Texture1D,
-        Texture2D,
-        Texture3D,
-        Texture1DArray,
-        Texture2DArray,
-        TextureCubemap,
-    };
-
-    static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
-        switch (texture_type) {
-        case Tegra::Texture::TextureType::Texture1D:
-            return SurfaceTarget::Texture1D;
-        case Tegra::Texture::TextureType::Texture2D:
-        case Tegra::Texture::TextureType::Texture2DNoMipmap:
-            return SurfaceTarget::Texture2D;
-        case Tegra::Texture::TextureType::Texture3D:
-            return SurfaceTarget::Texture3D;
-        case Tegra::Texture::TextureType::TextureCubemap:
-            return SurfaceTarget::TextureCubemap;
-        case Tegra::Texture::TextureType::Texture1DArray:
-            return SurfaceTarget::Texture1DArray;
-        case Tegra::Texture::TextureType::Texture2DArray:
-            return SurfaceTarget::Texture2DArray;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
-            UNREACHABLE();
-            return SurfaceTarget::Texture2D;
-        }
-    }
+using SurfaceTarget = VideoCore::Surface::SurfaceTarget;
+using SurfaceType = VideoCore::Surface::SurfaceType;
+using PixelFormat = VideoCore::Surface::PixelFormat;
+using ComponentType = VideoCore::Surface::ComponentType;
 
+struct SurfaceParams {
     static std::string SurfaceTargetName(SurfaceTarget target) {
         switch (target) {
         case SurfaceTarget::Texture1D:
@@ -177,660 +56,8 @@ struct SurfaceParams {
         }
     }
 
-    static bool SurfaceTargetIsLayered(SurfaceTarget target) {
-        switch (target) {
-        case SurfaceTarget::Texture1D:
-        case SurfaceTarget::Texture2D:
-        case SurfaceTarget::Texture3D:
-            return false;
-        case SurfaceTarget::Texture1DArray:
-        case SurfaceTarget::Texture2DArray:
-        case SurfaceTarget::TextureCubemap:
-            return true;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
-            UNREACHABLE();
-            return false;
-        }
-    }
-
-    /**
-     * Gets the compression factor for the specified PixelFormat. This applies to just the
-     * "compressed width" and "compressed height", not the overall compression factor of a
-     * compressed image. This is used for maintaining proper surface sizes for compressed
-     * texture formats.
-     */
-    static constexpr u32 GetCompressionFactor(PixelFormat format) {
-        if (format == PixelFormat::Invalid)
-            return 0;
-
-        constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
-            1, // ABGR8U
-            1, // ABGR8S
-            1, // ABGR8UI
-            1, // B5G6R5U
-            1, // A2B10G10R10U
-            1, // A1B5G5R5U
-            1, // R8U
-            1, // R8UI
-            1, // RGBA16F
-            1, // RGBA16U
-            1, // RGBA16UI
-            1, // R11FG11FB10F
-            1, // RGBA32UI
-            4, // DXT1
-            4, // DXT23
-            4, // DXT45
-            4, // DXN1
-            4, // DXN2UNORM
-            4, // DXN2SNORM
-            4, // BC7U
-            4, // BC6H_UF16
-            4, // BC6H_SF16
-            4, // ASTC_2D_4X4
-            1, // G8R8U
-            1, // G8R8S
-            1, // BGRA8
-            1, // RGBA32F
-            1, // RG32F
-            1, // R32F
-            1, // R16F
-            1, // R16U
-            1, // R16S
-            1, // R16UI
-            1, // R16I
-            1, // RG16
-            1, // RG16F
-            1, // RG16UI
-            1, // RG16I
-            1, // RG16S
-            1, // RGB32F
-            1, // RGBA8_SRGB
-            1, // RG8U
-            1, // RG8S
-            1, // RG32UI
-            1, // R32UI
-            4, // ASTC_2D_8X8
-            4, // ASTC_2D_8X5
-            4, // ASTC_2D_5X4
-            1, // BGRA8_SRGB
-            4, // DXT1_SRGB
-            4, // DXT23_SRGB
-            4, // DXT45_SRGB
-            4, // BC7U_SRGB
-            4, // ASTC_2D_4X4_SRGB
-            4, // ASTC_2D_8X8_SRGB
-            4, // ASTC_2D_8X5_SRGB
-            4, // ASTC_2D_5X4_SRGB
-            1, // Z32F
-            1, // Z16
-            1, // Z24S8
-            1, // S8Z24
-            1, // Z32FS8
-        }};
-
-        ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
-        return compression_factor_table[static_cast<std::size_t>(format)];
-    }
-
-    static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
-        if (format == PixelFormat::Invalid)
-            return 0;
-        constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
-            1, // ABGR8U
-            1, // ABGR8S
-            1, // ABGR8UI
-            1, // B5G6R5U
-            1, // A2B10G10R10U
-            1, // A1B5G5R5U
-            1, // R8U
-            1, // R8UI
-            1, // RGBA16F
-            1, // RGBA16U
-            1, // RGBA16UI
-            1, // R11FG11FB10F
-            1, // RGBA32UI
-            4, // DXT1
-            4, // DXT23
-            4, // DXT45
-            4, // DXN1
-            4, // DXN2UNORM
-            4, // DXN2SNORM
-            4, // BC7U
-            4, // BC6H_UF16
-            4, // BC6H_SF16
-            4, // ASTC_2D_4X4
-            1, // G8R8U
-            1, // G8R8S
-            1, // BGRA8
-            1, // RGBA32F
-            1, // RG32F
-            1, // R32F
-            1, // R16F
-            1, // R16U
-            1, // R16S
-            1, // R16UI
-            1, // R16I
-            1, // RG16
-            1, // RG16F
-            1, // RG16UI
-            1, // RG16I
-            1, // RG16S
-            1, // RGB32F
-            1, // RGBA8_SRGB
-            1, // RG8U
-            1, // RG8S
-            1, // RG32UI
-            1, // R32UI
-            8, // ASTC_2D_8X8
-            5, // ASTC_2D_8X5
-            4, // ASTC_2D_5X4
-            1, // BGRA8_SRGB
-            4, // DXT1_SRGB
-            4, // DXT23_SRGB
-            4, // DXT45_SRGB
-            4, // BC7U_SRGB
-            4, // ASTC_2D_4X4_SRGB
-            8, // ASTC_2D_8X8_SRGB
-            5, // ASTC_2D_8X5_SRGB
-            4, // ASTC_2D_5X4_SRGB
-            1, // Z32F
-            1, // Z16
-            1, // Z24S8
-            1, // S8Z24
-            1, // Z32FS8
-        }};
-        ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
-        return block_height_table[static_cast<std::size_t>(format)];
-    }
-
-    static constexpr u32 GetFormatBpp(PixelFormat format) {
-        if (format == PixelFormat::Invalid)
-            return 0;
-
-        constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
-            32,  // ABGR8U
-            32,  // ABGR8S
-            32,  // ABGR8UI
-            16,  // B5G6R5U
-            32,  // A2B10G10R10U
-            16,  // A1B5G5R5U
-            8,   // R8U
-            8,   // R8UI
-            64,  // RGBA16F
-            64,  // RGBA16U
-            64,  // RGBA16UI
-            32,  // R11FG11FB10F
-            128, // RGBA32UI
-            64,  // DXT1
-            128, // DXT23
-            128, // DXT45
-            64,  // DXN1
-            128, // DXN2UNORM
-            128, // DXN2SNORM
-            128, // BC7U
-            128, // BC6H_UF16
-            128, // BC6H_SF16
-            32,  // ASTC_2D_4X4
-            16,  // G8R8U
-            16,  // G8R8S
-            32,  // BGRA8
-            128, // RGBA32F
-            64,  // RG32F
-            32,  // R32F
-            16,  // R16F
-            16,  // R16U
-            16,  // R16S
-            16,  // R16UI
-            16,  // R16I
-            32,  // RG16
-            32,  // RG16F
-            32,  // RG16UI
-            32,  // RG16I
-            32,  // RG16S
-            96,  // RGB32F
-            32,  // RGBA8_SRGB
-            16,  // RG8U
-            16,  // RG8S
-            64,  // RG32UI
-            32,  // R32UI
-            16,  // ASTC_2D_8X8
-            16,  // ASTC_2D_8X5
-            32,  // ASTC_2D_5X4
-            32,  // BGRA8_SRGB
-            64,  // DXT1_SRGB
-            128, // DXT23_SRGB
-            128, // DXT45_SRGB
-            128, // BC7U
-            32,  // ASTC_2D_4X4_SRGB
-            16,  // ASTC_2D_8X8_SRGB
-            16,  // ASTC_2D_8X5_SRGB
-            32,  // ASTC_2D_5X4_SRGB
-            32,  // Z32F
-            16,  // Z16
-            32,  // Z24S8
-            32,  // S8Z24
-            64,  // Z32FS8
-        }};
-
-        ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
-        return bpp_table[static_cast<std::size_t>(format)];
-    }
-
     u32 GetFormatBpp() const {
-        return GetFormatBpp(pixel_format);
-    }
-
-    static PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
-        switch (format) {
-        case Tegra::DepthFormat::S8_Z24_UNORM:
-            return PixelFormat::S8Z24;
-        case Tegra::DepthFormat::Z24_S8_UNORM:
-            return PixelFormat::Z24S8;
-        case Tegra::DepthFormat::Z32_FLOAT:
-            return PixelFormat::Z32F;
-        case Tegra::DepthFormat::Z16_UNORM:
-            return PixelFormat::Z16;
-        case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
-            return PixelFormat::Z32FS8;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
-            UNREACHABLE();
-        }
-    }
-
-    static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
-        switch (format) {
-        // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
-        // gamma.
-        case Tegra::RenderTargetFormat::RGBA8_SRGB:
-            return PixelFormat::RGBA8_SRGB;
-        case Tegra::RenderTargetFormat::RGBA8_UNORM:
-            return PixelFormat::ABGR8U;
-        case Tegra::RenderTargetFormat::RGBA8_SNORM:
-            return PixelFormat::ABGR8S;
-        case Tegra::RenderTargetFormat::RGBA8_UINT:
-            return PixelFormat::ABGR8UI;
-        case Tegra::RenderTargetFormat::BGRA8_SRGB:
-            return PixelFormat::BGRA8_SRGB;
-        case Tegra::RenderTargetFormat::BGRA8_UNORM:
-            return PixelFormat::BGRA8;
-        case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
-            return PixelFormat::A2B10G10R10U;
-        case Tegra::RenderTargetFormat::RGBA16_FLOAT:
-            return PixelFormat::RGBA16F;
-        case Tegra::RenderTargetFormat::RGBA16_UNORM:
-            return PixelFormat::RGBA16U;
-        case Tegra::RenderTargetFormat::RGBA16_UINT:
-            return PixelFormat::RGBA16UI;
-        case Tegra::RenderTargetFormat::RGBA32_FLOAT:
-            return PixelFormat::RGBA32F;
-        case Tegra::RenderTargetFormat::RG32_FLOAT:
-            return PixelFormat::RG32F;
-        case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
-            return PixelFormat::R11FG11FB10F;
-        case Tegra::RenderTargetFormat::B5G6R5_UNORM:
-            return PixelFormat::B5G6R5U;
-        case Tegra::RenderTargetFormat::BGR5A1_UNORM:
-            return PixelFormat::A1B5G5R5U;
-        case Tegra::RenderTargetFormat::RGBA32_UINT:
-            return PixelFormat::RGBA32UI;
-        case Tegra::RenderTargetFormat::R8_UNORM:
-            return PixelFormat::R8U;
-        case Tegra::RenderTargetFormat::R8_UINT:
-            return PixelFormat::R8UI;
-        case Tegra::RenderTargetFormat::RG16_FLOAT:
-            return PixelFormat::RG16F;
-        case Tegra::RenderTargetFormat::RG16_UINT:
-            return PixelFormat::RG16UI;
-        case Tegra::RenderTargetFormat::RG16_SINT:
-            return PixelFormat::RG16I;
-        case Tegra::RenderTargetFormat::RG16_UNORM:
-            return PixelFormat::RG16;
-        case Tegra::RenderTargetFormat::RG16_SNORM:
-            return PixelFormat::RG16S;
-        case Tegra::RenderTargetFormat::RG8_UNORM:
-            return PixelFormat::RG8U;
-        case Tegra::RenderTargetFormat::RG8_SNORM:
-            return PixelFormat::RG8S;
-        case Tegra::RenderTargetFormat::R16_FLOAT:
-            return PixelFormat::R16F;
-        case Tegra::RenderTargetFormat::R16_UNORM:
-            return PixelFormat::R16U;
-        case Tegra::RenderTargetFormat::R16_SNORM:
-            return PixelFormat::R16S;
-        case Tegra::RenderTargetFormat::R16_UINT:
-            return PixelFormat::R16UI;
-        case Tegra::RenderTargetFormat::R16_SINT:
-            return PixelFormat::R16I;
-        case Tegra::RenderTargetFormat::R32_FLOAT:
-            return PixelFormat::R32F;
-        case Tegra::RenderTargetFormat::R32_UINT:
-            return PixelFormat::R32UI;
-        case Tegra::RenderTargetFormat::RG32_UINT:
-            return PixelFormat::RG32UI;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
-            UNREACHABLE();
-        }
-    }
-
-    static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
-                                                    Tegra::Texture::ComponentType component_type,
-                                                    bool is_srgb) {
-        // TODO(Subv): Properly implement this
-        switch (format) {
-        case Tegra::Texture::TextureFormat::A8R8G8B8:
-            if (is_srgb) {
-                return PixelFormat::RGBA8_SRGB;
-            }
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::ABGR8U;
-            case Tegra::Texture::ComponentType::SNORM:
-                return PixelFormat::ABGR8S;
-            case Tegra::Texture::ComponentType::UINT:
-                return PixelFormat::ABGR8UI;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::B5G6R5:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::B5G6R5U;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::A2B10G10R10:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::A2B10G10R10U;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::A1B5G5R5:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::A1B5G5R5U;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::R8:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::R8U;
-            case Tegra::Texture::ComponentType::UINT:
-                return PixelFormat::R8UI;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::G8R8:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::G8R8U;
-            case Tegra::Texture::ComponentType::SNORM:
-                return PixelFormat::G8R8S;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::RGBA16U;
-            case Tegra::Texture::ComponentType::FLOAT:
-                return PixelFormat::RGBA16F;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::BF10GF11RF11:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::FLOAT:
-                return PixelFormat::R11FG11FB10F;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::FLOAT:
-                return PixelFormat::RGBA32F;
-            case Tegra::Texture::ComponentType::UINT:
-                return PixelFormat::RGBA32UI;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::R32_G32:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::FLOAT:
-                return PixelFormat::RG32F;
-            case Tegra::Texture::ComponentType::UINT:
-                return PixelFormat::RG32UI;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::R32_G32_B32:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::FLOAT:
-                return PixelFormat::RGB32F;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::R16:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::FLOAT:
-                return PixelFormat::R16F;
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::R16U;
-            case Tegra::Texture::ComponentType::SNORM:
-                return PixelFormat::R16S;
-            case Tegra::Texture::ComponentType::UINT:
-                return PixelFormat::R16UI;
-            case Tegra::Texture::ComponentType::SINT:
-                return PixelFormat::R16I;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::R32:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::FLOAT:
-                return PixelFormat::R32F;
-            case Tegra::Texture::ComponentType::UINT:
-                return PixelFormat::R32UI;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::ZF32:
-            return PixelFormat::Z32F;
-        case Tegra::Texture::TextureFormat::Z16:
-            return PixelFormat::Z16;
-        case Tegra::Texture::TextureFormat::Z24S8:
-            return PixelFormat::Z24S8;
-        case Tegra::Texture::TextureFormat::DXT1:
-            return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
-        case Tegra::Texture::TextureFormat::DXT23:
-            return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
-        case Tegra::Texture::TextureFormat::DXT45:
-            return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
-        case Tegra::Texture::TextureFormat::DXN1:
-            return PixelFormat::DXN1;
-        case Tegra::Texture::TextureFormat::DXN2:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::DXN2UNORM;
-            case Tegra::Texture::ComponentType::SNORM:
-                return PixelFormat::DXN2SNORM;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        case Tegra::Texture::TextureFormat::BC7U:
-            return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
-        case Tegra::Texture::TextureFormat::BC6H_UF16:
-            return PixelFormat::BC6H_UF16;
-        case Tegra::Texture::TextureFormat::BC6H_SF16:
-            return PixelFormat::BC6H_SF16;
-        case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
-            return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
-        case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
-            return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
-        case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
-            return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
-        case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
-            return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
-        case Tegra::Texture::TextureFormat::R16_G16:
-            switch (component_type) {
-            case Tegra::Texture::ComponentType::FLOAT:
-                return PixelFormat::RG16F;
-            case Tegra::Texture::ComponentType::UNORM:
-                return PixelFormat::RG16;
-            case Tegra::Texture::ComponentType::SNORM:
-                return PixelFormat::RG16S;
-            case Tegra::Texture::ComponentType::UINT:
-                return PixelFormat::RG16UI;
-            case Tegra::Texture::ComponentType::SINT:
-                return PixelFormat::RG16I;
-            }
-            LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
-                         static_cast<u32>(component_type));
-            UNREACHABLE();
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}",
-                         static_cast<u32>(format), static_cast<u32>(component_type));
-            UNREACHABLE();
-        }
-    }
-
-    static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
-        // TODO(Subv): Implement more component types
-        switch (type) {
-        case Tegra::Texture::ComponentType::UNORM:
-            return ComponentType::UNorm;
-        case Tegra::Texture::ComponentType::FLOAT:
-            return ComponentType::Float;
-        case Tegra::Texture::ComponentType::SNORM:
-            return ComponentType::SNorm;
-        case Tegra::Texture::ComponentType::UINT:
-            return ComponentType::UInt;
-        case Tegra::Texture::ComponentType::SINT:
-            return ComponentType::SInt;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
-            UNREACHABLE();
-        }
-    }
-
-    static ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
-        // TODO(Subv): Implement more render targets
-        switch (format) {
-        case Tegra::RenderTargetFormat::RGBA8_UNORM:
-        case Tegra::RenderTargetFormat::RGBA8_SRGB:
-        case Tegra::RenderTargetFormat::BGRA8_UNORM:
-        case Tegra::RenderTargetFormat::BGRA8_SRGB:
-        case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
-        case Tegra::RenderTargetFormat::R8_UNORM:
-        case Tegra::RenderTargetFormat::RG16_UNORM:
-        case Tegra::RenderTargetFormat::R16_UNORM:
-        case Tegra::RenderTargetFormat::B5G6R5_UNORM:
-        case Tegra::RenderTargetFormat::BGR5A1_UNORM:
-        case Tegra::RenderTargetFormat::RG8_UNORM:
-        case Tegra::RenderTargetFormat::RGBA16_UNORM:
-            return ComponentType::UNorm;
-        case Tegra::RenderTargetFormat::RGBA8_SNORM:
-        case Tegra::RenderTargetFormat::RG16_SNORM:
-        case Tegra::RenderTargetFormat::R16_SNORM:
-        case Tegra::RenderTargetFormat::RG8_SNORM:
-            return ComponentType::SNorm;
-        case Tegra::RenderTargetFormat::RGBA16_FLOAT:
-        case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
-        case Tegra::RenderTargetFormat::RGBA32_FLOAT:
-        case Tegra::RenderTargetFormat::RG32_FLOAT:
-        case Tegra::RenderTargetFormat::RG16_FLOAT:
-        case Tegra::RenderTargetFormat::R16_FLOAT:
-        case Tegra::RenderTargetFormat::R32_FLOAT:
-            return ComponentType::Float;
-        case Tegra::RenderTargetFormat::RGBA32_UINT:
-        case Tegra::RenderTargetFormat::RGBA16_UINT:
-        case Tegra::RenderTargetFormat::RG16_UINT:
-        case Tegra::RenderTargetFormat::R8_UINT:
-        case Tegra::RenderTargetFormat::R16_UINT:
-        case Tegra::RenderTargetFormat::RG32_UINT:
-        case Tegra::RenderTargetFormat::R32_UINT:
-        case Tegra::RenderTargetFormat::RGBA8_UINT:
-            return ComponentType::UInt;
-        case Tegra::RenderTargetFormat::RG16_SINT:
-        case Tegra::RenderTargetFormat::R16_SINT:
-            return ComponentType::SInt;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
-            UNREACHABLE();
-        }
-    }
-
-    static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
-        switch (format) {
-        case Tegra::FramebufferConfig::PixelFormat::ABGR8:
-            return PixelFormat::ABGR8U;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
-            UNREACHABLE();
-        }
-    }
-
-    static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
-        switch (format) {
-        case Tegra::DepthFormat::Z16_UNORM:
-        case Tegra::DepthFormat::S8_Z24_UNORM:
-        case Tegra::DepthFormat::Z24_S8_UNORM:
-            return ComponentType::UNorm;
-        case Tegra::DepthFormat::Z32_FLOAT:
-        case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
-            return ComponentType::Float;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
-            UNREACHABLE();
-        }
-    }
-
-    static SurfaceType GetFormatType(PixelFormat pixel_format) {
-        if (static_cast<std::size_t>(pixel_format) <
-            static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
-            return SurfaceType::ColorTexture;
-        }
-
-        if (static_cast<std::size_t>(pixel_format) <
-            static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
-            return SurfaceType::Depth;
-        }
-
-        if (static_cast<std::size_t>(pixel_format) <
-            static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
-            return SurfaceType::DepthStencil;
-        }
-
-        // TODO(Subv): Implement the other formats
-        ASSERT(false);
-
-        return SurfaceType::Invalid;
-    }
-
-    /// Returns the sizer in bytes of the specified pixel format
-    static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
-        if (pixel_format == SurfaceParams::PixelFormat::Invalid) {
-            return 0;
-        }
-        return GetFormatBpp(pixel_format) / CHAR_BIT;
+        return VideoCore::Surface::GetFormatBpp(pixel_format);
     }
 
     /// 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 d1f6ffe40adbdd42423a89073675332e06c719b7..09b003c598b77a019e8e89260f856f9ea8749548 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:
         if (sets_cc) {
             const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
             SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
+            LOG_WARNING(HW_GPU, "Control Codes Imcomplete.");
         }
     }
 
@@ -1525,6 +1526,10 @@ private:
 
                 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
                                         instr.alu.saturate_d, 0, true);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "FMUL Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::FADD_C:
@@ -1535,6 +1540,10 @@ private:
 
                 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
                                         instr.alu.saturate_d, 0, true);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "FADD Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::MUFU: {
@@ -1588,6 +1597,10 @@ private:
                                         '(' + condition + ") ? min(" + parameters + ") : max(" +
                                             parameters + ')',
                                         1, 1, false, 0, true);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "FMNMX Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::RRO_C:
@@ -1618,6 +1631,10 @@ private:
                                         regs.GetRegisterAsFloat(instr.gpr8) + " * " +
                                             GetImmediate32(instr),
                                         1, 1, instr.fmul32.saturate, 0, true);
+                if (instr.op_32.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "FMUL32 Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::FADD32I: {
@@ -1641,6 +1658,10 @@ private:
                 }
 
                 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true);
+                if (instr.op_32.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "FADD32 Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             }
@@ -1661,6 +1682,10 @@ private:
                     std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
 
                 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "BFE Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             default: {
@@ -1698,12 +1723,20 @@ private:
                 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift
                 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')',
                                           1, 1);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "SHR Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::SHL_C:
             case OpCode::Id::SHL_R:
             case OpCode::Id::SHL_IMM:
                 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "SHL Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             default: {
                 LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName());
@@ -1723,6 +1756,10 @@ private:
 
                 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
                                           instr.iadd32i.saturate != 0);
+                if (instr.op_32.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "IADD32 Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             case OpCode::Id::LOP32I: {
                 if (instr.alu.lop32i.invert_a)
@@ -1734,6 +1771,10 @@ private:
                 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
                                     Tegra::Shader::PredicateResultMode::None,
                                     Tegra::Shader::Pred::UnusedIndex);
+                if (instr.op_32.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "LOP32I Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             default: {
@@ -1770,6 +1811,10 @@ private:
 
                 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
                                           instr.alu.saturate_d);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "IADD Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::IADD3_C:
@@ -1831,6 +1876,11 @@ private:
                 }
 
                 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1);
+
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "IADD3 Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::ISCADD_C:
@@ -1846,6 +1896,10 @@ private:
 
                 regs.SetRegisterToInteger(instr.gpr0, true, 0,
                                           "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "ISCADD Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::POPC_C:
@@ -1877,6 +1931,10 @@ private:
 
                 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
                                     instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "LOP Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::LOP3_C:
@@ -1892,6 +1950,10 @@ private:
                 }
 
                 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "LOP3 Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::IMNMX_C:
@@ -1906,6 +1968,10 @@ private:
                                           '(' + condition + ") ? min(" + parameters + ") : max(" +
                                               parameters + ')',
                                           1, 1);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "IMNMX Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::LEA_R2:
@@ -2107,6 +2173,10 @@ private:
 
             regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')',
                                     1, 1, instr.alu.saturate_d, 0, true);
+            if (instr.generates_cc) {
+                LOG_CRITICAL(HW_GPU, "FFMA Generates an unhandled Control Code");
+                UNREACHABLE();
+            }
 
             break;
         }
@@ -2212,6 +2282,11 @@ private:
                 }
 
                 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
+
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "I2F Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::F2F_R: {
@@ -2250,6 +2325,11 @@ private:
                 }
 
                 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
+
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "F2F Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             case OpCode::Id::F2I_R:
@@ -2299,6 +2379,10 @@ private:
 
                 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
                                           1, false, 0, instr.conversion.dest_size);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "F2I Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
                 break;
             }
             default: {
@@ -3107,6 +3191,11 @@ private:
                 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
             }
 
+            if (instr.generates_cc) {
+                LOG_CRITICAL(HW_GPU, "PSET Generates an unhandled Control Code");
+                UNREACHABLE();
+            }
+
             break;
         }
         case OpCode::Type::PredicateSetPredicate: {
@@ -3372,6 +3461,10 @@ private:
             }
 
             regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
+            if (instr.generates_cc) {
+                LOG_CRITICAL(HW_GPU, "XMAD Generates an unhandled Control Code");
+                UNREACHABLE();
+            }
             break;
         }
         default: {
@@ -3381,6 +3474,12 @@ private:
                     EmitFragmentOutputsWrite();
                 }
 
+                const Tegra::Shader::ControlCode cc = instr.flow_control_code;
+                if (cc != Tegra::Shader::ControlCode::T) {
+                    LOG_CRITICAL(HW_GPU, "EXIT Control Code used: {}", static_cast<u32>(cc));
+                    UNREACHABLE();
+                }
+
                 switch (instr.flow.cond) {
                 case Tegra::Shader::FlowCondition::Always:
                     shader.AddLine("return true;");
@@ -3410,6 +3509,11 @@ private:
 
                 // Enclose "discard" in a conditional, so that GLSL compilation does not complain
                 // about unexecuted instructions that may follow this.
+                const Tegra::Shader::ControlCode cc = instr.flow_control_code;
+                if (cc != Tegra::Shader::ControlCode::T) {
+                    LOG_CRITICAL(HW_GPU, "KIL Control Code used: {}", static_cast<u32>(cc));
+                    UNREACHABLE();
+                }
                 shader.AddLine("if (true) {");
                 ++shader.scope;
                 shader.AddLine("discard;");
@@ -3467,6 +3571,11 @@ private:
             case OpCode::Id::BRA: {
                 ASSERT_MSG(instr.bra.constant_buffer == 0,
                            "BRA with constant buffers are not implemented");
+                const Tegra::Shader::ControlCode cc = instr.flow_control_code;
+                if (cc != Tegra::Shader::ControlCode::T) {
+                    LOG_CRITICAL(HW_GPU, "BRA Control Code used: {}", static_cast<u32>(cc));
+                    UNREACHABLE();
+                }
                 const u32 target = offset + instr.bra.GetBranchTarget();
                 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
                 break;
@@ -3507,13 +3616,21 @@ private:
             }
             case OpCode::Id::SYNC: {
                 // The SYNC opcode jumps to the address previously set by the SSY opcode
-                ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
+                const Tegra::Shader::ControlCode cc = instr.flow_control_code;
+                if (cc != Tegra::Shader::ControlCode::T) {
+                    LOG_CRITICAL(HW_GPU, "SYNC Control Code used: {}", static_cast<u32>(cc));
+                    UNREACHABLE();
+                }
                 EmitPopFromFlowStack();
                 break;
             }
             case OpCode::Id::BRK: {
                 // The BRK opcode jumps to the address previously set by the PBK opcode
-                ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
+                const Tegra::Shader::ControlCode cc = instr.flow_control_code;
+                if (cc != Tegra::Shader::ControlCode::T) {
+                    LOG_CRITICAL(HW_GPU, "BRK Control Code used: {}", static_cast<u32>(cc));
+                    UNREACHABLE();
+                }
                 EmitPopFromFlowStack();
                 break;
             }
@@ -3543,6 +3660,11 @@ private:
                 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
                                           instr.vmad.saturate == 1, 0, Register::Size::Word,
                                           instr.vmad.cc);
+                if (instr.generates_cc) {
+                    LOG_CRITICAL(HW_GPU, "VMAD Generates an unhandled Control Code");
+                    UNREACHABLE();
+                }
+
                 break;
             }
             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 d8a43cc94d3bc852bf2cd7d5ed4ddf9d0dc198da..b6b426f3426547dc62314e7cc8aff15a583ca7a8 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() {
     point.size = 1;
 }
 
-void OpenGLState::Apply() const {
+void OpenGLState::ApplyDefaultState() {
+    glDisable(GL_FRAMEBUFFER_SRGB);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_PRIMITIVE_RESTART);
+    glDisable(GL_STENCIL_TEST);
+    glEnable(GL_BLEND);
+    glDisable(GL_COLOR_LOGIC_OP);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+void OpenGLState::ApplySRgb() const {
     // sRGB
     if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) {
         if (framebuffer_srgb.enabled) {
@@ -100,96 +111,122 @@ void OpenGLState::Apply() const {
             glDisable(GL_FRAMEBUFFER_SRGB);
         }
     }
+}
+
+void OpenGLState::ApplyCulling() const {
     // Culling
-    if (cull.enabled != cur_state.cull.enabled) {
+    const bool cull_changed = cull.enabled != cur_state.cull.enabled;
+    if (cull_changed) {
         if (cull.enabled) {
             glEnable(GL_CULL_FACE);
         } else {
             glDisable(GL_CULL_FACE);
         }
     }
+    if (cull.enabled) {
+        if (cull_changed || cull.mode != cur_state.cull.mode) {
+            glCullFace(cull.mode);
+        }
 
-    if (cull.mode != cur_state.cull.mode) {
-        glCullFace(cull.mode);
-    }
-
-    if (cull.front_face != cur_state.cull.front_face) {
-        glFrontFace(cull.front_face);
+        if (cull_changed || cull.front_face != cur_state.cull.front_face) {
+            glFrontFace(cull.front_face);
+        }
     }
+}
 
+void OpenGLState::ApplyDepth() const {
     // Depth test
-    if (depth.test_enabled != cur_state.depth.test_enabled) {
+    const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
+    if (depth_test_changed) {
         if (depth.test_enabled) {
             glEnable(GL_DEPTH_TEST);
         } else {
             glDisable(GL_DEPTH_TEST);
         }
     }
-
-    if (depth.test_func != cur_state.depth.test_func) {
+    if (depth.test_enabled &&
+        (depth_test_changed || depth.test_func != cur_state.depth.test_func)) {
         glDepthFunc(depth.test_func);
     }
-
     // Depth mask
     if (depth.write_mask != cur_state.depth.write_mask) {
         glDepthMask(depth.write_mask);
     }
-
     // Depth range
     if (depth.depth_range_near != cur_state.depth.depth_range_near ||
         depth.depth_range_far != cur_state.depth.depth_range_far) {
         glDepthRange(depth.depth_range_near, depth.depth_range_far);
     }
+}
 
-    // Primitive restart
-    if (primitive_restart.enabled != cur_state.primitive_restart.enabled) {
+void OpenGLState::ApplyPrimitiveRestart() const {
+    const bool primitive_restart_changed =
+        primitive_restart.enabled != cur_state.primitive_restart.enabled;
+    if (primitive_restart_changed) {
         if (primitive_restart.enabled) {
             glEnable(GL_PRIMITIVE_RESTART);
         } else {
             glDisable(GL_PRIMITIVE_RESTART);
         }
     }
-    if (primitive_restart.index != cur_state.primitive_restart.index) {
+    if (primitive_restart_changed ||
+        (primitive_restart.enabled &&
+         primitive_restart.index != cur_state.primitive_restart.index)) {
         glPrimitiveRestartIndex(primitive_restart.index);
     }
+}
 
-    // Color mask
-    if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
-        color_mask.green_enabled != cur_state.color_mask.green_enabled ||
-        color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
-        color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
-        glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
-                    color_mask.alpha_enabled);
-    }
-
-    // Stencil test
-    if (stencil.test_enabled != cur_state.stencil.test_enabled) {
+void OpenGLState::ApplyStencilTest() const {
+    const bool stencil_test_changed = stencil.test_enabled != cur_state.stencil.test_enabled;
+    if (stencil_test_changed) {
         if (stencil.test_enabled) {
             glEnable(GL_STENCIL_TEST);
         } else {
             glDisable(GL_STENCIL_TEST);
         }
     }
-    auto config_stencil = [](GLenum face, const auto& config, const auto& prev_config) {
-        if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref ||
-            config.test_mask != prev_config.test_mask) {
-            glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
-        }
-        if (config.action_depth_fail != prev_config.action_depth_fail ||
-            config.action_depth_pass != prev_config.action_depth_pass ||
-            config.action_stencil_fail != prev_config.action_stencil_fail) {
-            glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
-                                config.action_depth_pass);
-        }
-        if (config.write_mask != prev_config.write_mask) {
-            glStencilMaskSeparate(face, config.write_mask);
+    if (stencil.test_enabled) {
+        auto config_stencil = [stencil_test_changed](GLenum face, const auto& config,
+                                                     const auto& prev_config) {
+            if (stencil_test_changed || config.test_func != prev_config.test_func ||
+                config.test_ref != prev_config.test_ref ||
+                config.test_mask != prev_config.test_mask) {
+                glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
+            }
+            if (stencil_test_changed || config.action_depth_fail != prev_config.action_depth_fail ||
+                config.action_depth_pass != prev_config.action_depth_pass ||
+                config.action_stencil_fail != prev_config.action_stencil_fail) {
+                glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
+                                    config.action_depth_pass);
+            }
+            if (config.write_mask != prev_config.write_mask) {
+                glStencilMaskSeparate(face, config.write_mask);
+            }
+        };
+        config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
+        config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
+    }
+}
+
+void OpenGLState::ApplyScissorTest() const {
+    const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
+    if (scissor_changed) {
+        if (scissor.enabled) {
+            glEnable(GL_SCISSOR_TEST);
+        } else {
+            glDisable(GL_SCISSOR_TEST);
         }
-    };
-    config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
-    config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
+    }
+    if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x ||
+        scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width ||
+        scissor.height != cur_state.scissor.height) {
+        glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
+    }
+}
 
-    // Blending
-    if (blend.enabled != cur_state.blend.enabled) {
+void OpenGLState::ApplyBlending() const {
+    const bool blend_changed = blend.enabled != cur_state.blend.enabled;
+    if (blend_changed) {
         if (blend.enabled) {
             ASSERT(!logic_op.enabled);
             glEnable(GL_BLEND);
@@ -197,29 +234,32 @@ void OpenGLState::Apply() const {
             glDisable(GL_BLEND);
         }
     }
+    if (blend.enabled) {
+        if (blend_changed || blend.color.red != cur_state.blend.color.red ||
+            blend.color.green != cur_state.blend.color.green ||
+            blend.color.blue != cur_state.blend.color.blue ||
+            blend.color.alpha != cur_state.blend.color.alpha) {
+            glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha);
+        }
 
-    if (blend.color.red != cur_state.blend.color.red ||
-        blend.color.green != cur_state.blend.color.green ||
-        blend.color.blue != cur_state.blend.color.blue ||
-        blend.color.alpha != cur_state.blend.color.alpha) {
-        glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha);
-    }
-
-    if (blend.src_rgb_func != cur_state.blend.src_rgb_func ||
-        blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
-        blend.src_a_func != cur_state.blend.src_a_func ||
-        blend.dst_a_func != cur_state.blend.dst_a_func) {
-        glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
-                            blend.dst_a_func);
-    }
+        if (blend_changed || blend.src_rgb_func != cur_state.blend.src_rgb_func ||
+            blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
+            blend.src_a_func != cur_state.blend.src_a_func ||
+            blend.dst_a_func != cur_state.blend.dst_a_func) {
+            glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
+                                blend.dst_a_func);
+        }
 
-    if (blend.rgb_equation != cur_state.blend.rgb_equation ||
-        blend.a_equation != cur_state.blend.a_equation) {
-        glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
+        if (blend_changed || blend.rgb_equation != cur_state.blend.rgb_equation ||
+            blend.a_equation != cur_state.blend.a_equation) {
+            glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
+        }
     }
+}
 
-    // Logic Operation
-    if (logic_op.enabled != cur_state.logic_op.enabled) {
+void OpenGLState::ApplyLogicOp() const {
+    const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
+    if (logic_op_changed) {
         if (logic_op.enabled) {
             ASSERT(!blend.enabled);
             glEnable(GL_COLOR_LOGIC_OP);
@@ -228,11 +268,13 @@ void OpenGLState::Apply() const {
         }
     }
 
-    if (logic_op.operation != cur_state.logic_op.operation) {
+    if (logic_op.enabled &&
+        (logic_op_changed || logic_op.operation != cur_state.logic_op.operation)) {
         glLogicOp(logic_op.operation);
     }
+}
 
-    // Textures
+void OpenGLState::ApplyTextures() const {
     for (std::size_t i = 0; i < std::size(texture_units); ++i) {
         const auto& texture_unit = texture_units[i];
         const auto& cur_state_texture_unit = cur_state.texture_units[i];
@@ -251,28 +293,29 @@ void OpenGLState::Apply() const {
             glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
         }
     }
+}
 
-    // Samplers
-    {
-        bool has_delta{};
-        std::size_t first{}, last{};
-        std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
-        for (std::size_t i = 0; i < std::size(samplers); ++i) {
-            samplers[i] = texture_units[i].sampler;
-            if (samplers[i] != cur_state.texture_units[i].sampler) {
-                if (!has_delta) {
-                    first = i;
-                    has_delta = true;
-                }
-                last = i;
+void OpenGLState::ApplySamplers() const {
+    bool has_delta{};
+    std::size_t first{}, last{};
+    std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
+    for (std::size_t i = 0; i < std::size(samplers); ++i) {
+        samplers[i] = texture_units[i].sampler;
+        if (samplers[i] != cur_state.texture_units[i].sampler) {
+            if (!has_delta) {
+                first = i;
+                has_delta = true;
             }
-        }
-        if (has_delta) {
-            glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
-                           samplers.data());
+            last = i;
         }
     }
+    if (has_delta) {
+        glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
+                       samplers.data());
+    }
+}
 
+void OpenGLState::Apply() const {
     // Framebuffer
     if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
         glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
@@ -305,27 +348,12 @@ void OpenGLState::Apply() const {
     if (draw.program_pipeline != cur_state.draw.program_pipeline) {
         glBindProgramPipeline(draw.program_pipeline);
     }
-
-    // Scissor test
-    if (scissor.enabled != cur_state.scissor.enabled) {
-        if (scissor.enabled) {
-            glEnable(GL_SCISSOR_TEST);
-        } else {
-            glDisable(GL_SCISSOR_TEST);
-        }
-    }
-
-    if (scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
-        scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height) {
-        glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
-    }
-
+    // Viewport
     if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
         viewport.width != cur_state.viewport.width ||
         viewport.height != cur_state.viewport.height) {
         glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
     }
-
     // Clip distance
     for (std::size_t i = 0; i < clip_distance.size(); ++i) {
         if (clip_distance[i] != cur_state.clip_distance[i]) {
@@ -336,12 +364,28 @@ void OpenGLState::Apply() const {
             }
         }
     }
-
+    // Color mask
+    if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
+        color_mask.green_enabled != cur_state.color_mask.green_enabled ||
+        color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
+        color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
+        glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
+                    color_mask.alpha_enabled);
+    }
     // Point
     if (point.size != cur_state.point.size) {
         glPointSize(point.size);
     }
-
+    ApplyScissorTest();
+    ApplyStencilTest();
+    ApplySRgb();
+    ApplyCulling();
+    ApplyDepth();
+    ApplyPrimitiveRestart();
+    ApplyBlending();
+    ApplyLogicOp();
+    ApplyTextures();
+    ApplySamplers();
     cur_state = *this;
 }
 
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 9e2c573b54ae003bd58c555cdf7cd2dc713c291a..fe648aff6869836f839419de845b6e38c1d8ea09 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -173,7 +173,8 @@ public:
     }
     /// Apply this state as the current OpenGL state
     void Apply() const;
-
+    /// Set the initial OpenGL state
+    static void ApplyDefaultState();
     /// Resets any references to the given resource
     OpenGLState& UnbindTexture(GLuint handle);
     OpenGLState& ResetSampler(GLuint handle);
@@ -188,6 +189,16 @@ private:
     // Workaround for sRGB problems caused by
     // QT not supporting srgb output
     static bool s_rgb_used;
+    void ApplySRgb() const;
+    void ApplyCulling() const;
+    void ApplyDepth() const;
+    void ApplyPrimitiveRestart() const;
+    void ApplyStencilTest() const;
+    void ApplyScissorTest() const;
+    void ApplyBlending() const;
+    void ApplyLogicOp() const;
+    void ApplyTextures() const;
+    void ApplySamplers() const;
 };
 
 } // namespace OpenGL
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d9a97e30b9017d807700c4bafda87199913391df
--- /dev/null
+++ b/src/video_core/surface.cpp
@@ -0,0 +1,499 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/common_types.h"
+#include "common/math_util.h"
+#include "video_core/surface.h"
+
+namespace VideoCore::Surface {
+
+SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
+    switch (texture_type) {
+    case Tegra::Texture::TextureType::Texture1D:
+        return SurfaceTarget::Texture1D;
+    case Tegra::Texture::TextureType::Texture2D:
+    case Tegra::Texture::TextureType::Texture2DNoMipmap:
+        return SurfaceTarget::Texture2D;
+    case Tegra::Texture::TextureType::Texture3D:
+        return SurfaceTarget::Texture3D;
+    case Tegra::Texture::TextureType::TextureCubemap:
+        return SurfaceTarget::TextureCubemap;
+    case Tegra::Texture::TextureType::Texture1DArray:
+        return SurfaceTarget::Texture1DArray;
+    case Tegra::Texture::TextureType::Texture2DArray:
+        return SurfaceTarget::Texture2DArray;
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
+        UNREACHABLE();
+        return SurfaceTarget::Texture2D;
+    }
+}
+
+bool SurfaceTargetIsLayered(SurfaceTarget target) {
+    switch (target) {
+    case SurfaceTarget::Texture1D:
+    case SurfaceTarget::Texture2D:
+    case SurfaceTarget::Texture3D:
+        return false;
+    case SurfaceTarget::Texture1DArray:
+    case SurfaceTarget::Texture2DArray:
+    case SurfaceTarget::TextureCubemap:
+        return true;
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
+        UNREACHABLE();
+        return false;
+    }
+}
+
+PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
+    switch (format) {
+    case Tegra::DepthFormat::S8_Z24_UNORM:
+        return PixelFormat::S8Z24;
+    case Tegra::DepthFormat::Z24_S8_UNORM:
+        return PixelFormat::Z24S8;
+    case Tegra::DepthFormat::Z32_FLOAT:
+        return PixelFormat::Z32F;
+    case Tegra::DepthFormat::Z16_UNORM:
+        return PixelFormat::Z16;
+    case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
+        return PixelFormat::Z32FS8;
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
+        UNREACHABLE();
+    }
+}
+
+PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
+    switch (format) {
+        // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
+        // gamma.
+    case Tegra::RenderTargetFormat::RGBA8_SRGB:
+        return PixelFormat::RGBA8_SRGB;
+    case Tegra::RenderTargetFormat::RGBA8_UNORM:
+        return PixelFormat::ABGR8U;
+    case Tegra::RenderTargetFormat::RGBA8_SNORM:
+        return PixelFormat::ABGR8S;
+    case Tegra::RenderTargetFormat::RGBA8_UINT:
+        return PixelFormat::ABGR8UI;
+    case Tegra::RenderTargetFormat::BGRA8_SRGB:
+        return PixelFormat::BGRA8_SRGB;
+    case Tegra::RenderTargetFormat::BGRA8_UNORM:
+        return PixelFormat::BGRA8;
+    case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
+        return PixelFormat::A2B10G10R10U;
+    case Tegra::RenderTargetFormat::RGBA16_FLOAT:
+        return PixelFormat::RGBA16F;
+    case Tegra::RenderTargetFormat::RGBA16_UNORM:
+        return PixelFormat::RGBA16U;
+    case Tegra::RenderTargetFormat::RGBA16_UINT:
+        return PixelFormat::RGBA16UI;
+    case Tegra::RenderTargetFormat::RGBA32_FLOAT:
+        return PixelFormat::RGBA32F;
+    case Tegra::RenderTargetFormat::RG32_FLOAT:
+        return PixelFormat::RG32F;
+    case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
+        return PixelFormat::R11FG11FB10F;
+    case Tegra::RenderTargetFormat::B5G6R5_UNORM:
+        return PixelFormat::B5G6R5U;
+    case Tegra::RenderTargetFormat::BGR5A1_UNORM:
+        return PixelFormat::A1B5G5R5U;
+    case Tegra::RenderTargetFormat::RGBA32_UINT:
+        return PixelFormat::RGBA32UI;
+    case Tegra::RenderTargetFormat::R8_UNORM:
+        return PixelFormat::R8U;
+    case Tegra::RenderTargetFormat::R8_UINT:
+        return PixelFormat::R8UI;
+    case Tegra::RenderTargetFormat::RG16_FLOAT:
+        return PixelFormat::RG16F;
+    case Tegra::RenderTargetFormat::RG16_UINT:
+        return PixelFormat::RG16UI;
+    case Tegra::RenderTargetFormat::RG16_SINT:
+        return PixelFormat::RG16I;
+    case Tegra::RenderTargetFormat::RG16_UNORM:
+        return PixelFormat::RG16;
+    case Tegra::RenderTargetFormat::RG16_SNORM:
+        return PixelFormat::RG16S;
+    case Tegra::RenderTargetFormat::RG8_UNORM:
+        return PixelFormat::RG8U;
+    case Tegra::RenderTargetFormat::RG8_SNORM:
+        return PixelFormat::RG8S;
+    case Tegra::RenderTargetFormat::R16_FLOAT:
+        return PixelFormat::R16F;
+    case Tegra::RenderTargetFormat::R16_UNORM:
+        return PixelFormat::R16U;
+    case Tegra::RenderTargetFormat::R16_SNORM:
+        return PixelFormat::R16S;
+    case Tegra::RenderTargetFormat::R16_UINT:
+        return PixelFormat::R16UI;
+    case Tegra::RenderTargetFormat::R16_SINT:
+        return PixelFormat::R16I;
+    case Tegra::RenderTargetFormat::R32_FLOAT:
+        return PixelFormat::R32F;
+    case Tegra::RenderTargetFormat::R32_UINT:
+        return PixelFormat::R32UI;
+    case Tegra::RenderTargetFormat::RG32_UINT:
+        return PixelFormat::RG32UI;
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
+        UNREACHABLE();
+    }
+}
+
+PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
+                                         Tegra::Texture::ComponentType component_type,
+                                         bool is_srgb) {
+    // TODO(Subv): Properly implement this
+    switch (format) {
+    case Tegra::Texture::TextureFormat::A8R8G8B8:
+        if (is_srgb) {
+            return PixelFormat::RGBA8_SRGB;
+        }
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::ABGR8U;
+        case Tegra::Texture::ComponentType::SNORM:
+            return PixelFormat::ABGR8S;
+        case Tegra::Texture::ComponentType::UINT:
+            return PixelFormat::ABGR8UI;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::B5G6R5:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::B5G6R5U;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::A2B10G10R10:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::A2B10G10R10U;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::A1B5G5R5:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::A1B5G5R5U;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::R8:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::R8U;
+        case Tegra::Texture::ComponentType::UINT:
+            return PixelFormat::R8UI;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::G8R8:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::G8R8U;
+        case Tegra::Texture::ComponentType::SNORM:
+            return PixelFormat::G8R8S;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::RGBA16U;
+        case Tegra::Texture::ComponentType::FLOAT:
+            return PixelFormat::RGBA16F;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::BF10GF11RF11:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::FLOAT:
+            return PixelFormat::R11FG11FB10F;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::FLOAT:
+            return PixelFormat::RGBA32F;
+        case Tegra::Texture::ComponentType::UINT:
+            return PixelFormat::RGBA32UI;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::R32_G32:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::FLOAT:
+            return PixelFormat::RG32F;
+        case Tegra::Texture::ComponentType::UINT:
+            return PixelFormat::RG32UI;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::R32_G32_B32:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::FLOAT:
+            return PixelFormat::RGB32F;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::R16:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::FLOAT:
+            return PixelFormat::R16F;
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::R16U;
+        case Tegra::Texture::ComponentType::SNORM:
+            return PixelFormat::R16S;
+        case Tegra::Texture::ComponentType::UINT:
+            return PixelFormat::R16UI;
+        case Tegra::Texture::ComponentType::SINT:
+            return PixelFormat::R16I;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::R32:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::FLOAT:
+            return PixelFormat::R32F;
+        case Tegra::Texture::ComponentType::UINT:
+            return PixelFormat::R32UI;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::ZF32:
+        return PixelFormat::Z32F;
+    case Tegra::Texture::TextureFormat::Z16:
+        return PixelFormat::Z16;
+    case Tegra::Texture::TextureFormat::Z24S8:
+        return PixelFormat::Z24S8;
+    case Tegra::Texture::TextureFormat::DXT1:
+        return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
+    case Tegra::Texture::TextureFormat::DXT23:
+        return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
+    case Tegra::Texture::TextureFormat::DXT45:
+        return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
+    case Tegra::Texture::TextureFormat::DXN1:
+        return PixelFormat::DXN1;
+    case Tegra::Texture::TextureFormat::DXN2:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::DXN2UNORM;
+        case Tegra::Texture::ComponentType::SNORM:
+            return PixelFormat::DXN2SNORM;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    case Tegra::Texture::TextureFormat::BC7U:
+        return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
+    case Tegra::Texture::TextureFormat::BC6H_UF16:
+        return PixelFormat::BC6H_UF16;
+    case Tegra::Texture::TextureFormat::BC6H_SF16:
+        return PixelFormat::BC6H_SF16;
+    case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
+        return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
+    case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
+        return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
+    case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
+        return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
+    case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
+        return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
+    case Tegra::Texture::TextureFormat::R16_G16:
+        switch (component_type) {
+        case Tegra::Texture::ComponentType::FLOAT:
+            return PixelFormat::RG16F;
+        case Tegra::Texture::ComponentType::UNORM:
+            return PixelFormat::RG16;
+        case Tegra::Texture::ComponentType::SNORM:
+            return PixelFormat::RG16S;
+        case Tegra::Texture::ComponentType::UINT:
+            return PixelFormat::RG16UI;
+        case Tegra::Texture::ComponentType::SINT:
+            return PixelFormat::RG16I;
+        }
+        LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
+        UNREACHABLE();
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", static_cast<u32>(format),
+                     static_cast<u32>(component_type));
+        UNREACHABLE();
+    }
+}
+
+ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
+    // TODO(Subv): Implement more component types
+    switch (type) {
+    case Tegra::Texture::ComponentType::UNORM:
+        return ComponentType::UNorm;
+    case Tegra::Texture::ComponentType::FLOAT:
+        return ComponentType::Float;
+    case Tegra::Texture::ComponentType::SNORM:
+        return ComponentType::SNorm;
+    case Tegra::Texture::ComponentType::UINT:
+        return ComponentType::UInt;
+    case Tegra::Texture::ComponentType::SINT:
+        return ComponentType::SInt;
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
+        UNREACHABLE();
+    }
+}
+
+ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
+    // TODO(Subv): Implement more render targets
+    switch (format) {
+    case Tegra::RenderTargetFormat::RGBA8_UNORM:
+    case Tegra::RenderTargetFormat::RGBA8_SRGB:
+    case Tegra::RenderTargetFormat::BGRA8_UNORM:
+    case Tegra::RenderTargetFormat::BGRA8_SRGB:
+    case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
+    case Tegra::RenderTargetFormat::R8_UNORM:
+    case Tegra::RenderTargetFormat::RG16_UNORM:
+    case Tegra::RenderTargetFormat::R16_UNORM:
+    case Tegra::RenderTargetFormat::B5G6R5_UNORM:
+    case Tegra::RenderTargetFormat::BGR5A1_UNORM:
+    case Tegra::RenderTargetFormat::RG8_UNORM:
+    case Tegra::RenderTargetFormat::RGBA16_UNORM:
+        return ComponentType::UNorm;
+    case Tegra::RenderTargetFormat::RGBA8_SNORM:
+    case Tegra::RenderTargetFormat::RG16_SNORM:
+    case Tegra::RenderTargetFormat::R16_SNORM:
+    case Tegra::RenderTargetFormat::RG8_SNORM:
+        return ComponentType::SNorm;
+    case Tegra::RenderTargetFormat::RGBA16_FLOAT:
+    case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
+    case Tegra::RenderTargetFormat::RGBA32_FLOAT:
+    case Tegra::RenderTargetFormat::RG32_FLOAT:
+    case Tegra::RenderTargetFormat::RG16_FLOAT:
+    case Tegra::RenderTargetFormat::R16_FLOAT:
+    case Tegra::RenderTargetFormat::R32_FLOAT:
+        return ComponentType::Float;
+    case Tegra::RenderTargetFormat::RGBA32_UINT:
+    case Tegra::RenderTargetFormat::RGBA16_UINT:
+    case Tegra::RenderTargetFormat::RG16_UINT:
+    case Tegra::RenderTargetFormat::R8_UINT:
+    case Tegra::RenderTargetFormat::R16_UINT:
+    case Tegra::RenderTargetFormat::RG32_UINT:
+    case Tegra::RenderTargetFormat::R32_UINT:
+    case Tegra::RenderTargetFormat::RGBA8_UINT:
+        return ComponentType::UInt;
+    case Tegra::RenderTargetFormat::RG16_SINT:
+    case Tegra::RenderTargetFormat::R16_SINT:
+        return ComponentType::SInt;
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
+        UNREACHABLE();
+    }
+}
+
+PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
+    switch (format) {
+    case Tegra::FramebufferConfig::PixelFormat::ABGR8:
+        return PixelFormat::ABGR8U;
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
+        UNREACHABLE();
+    }
+}
+
+ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
+    switch (format) {
+    case Tegra::DepthFormat::Z16_UNORM:
+    case Tegra::DepthFormat::S8_Z24_UNORM:
+    case Tegra::DepthFormat::Z24_S8_UNORM:
+        return ComponentType::UNorm;
+    case Tegra::DepthFormat::Z32_FLOAT:
+    case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
+        return ComponentType::Float;
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
+        UNREACHABLE();
+    }
+}
+
+SurfaceType GetFormatType(PixelFormat pixel_format) {
+    if (static_cast<std::size_t>(pixel_format) <
+        static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
+        return SurfaceType::ColorTexture;
+    }
+
+    if (static_cast<std::size_t>(pixel_format) <
+        static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
+        return SurfaceType::Depth;
+    }
+
+    if (static_cast<std::size_t>(pixel_format) <
+        static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
+        return SurfaceType::DepthStencil;
+    }
+
+    // TODO(Subv): Implement the other formats
+    ASSERT(false);
+
+    return SurfaceType::Invalid;
+}
+
+bool IsPixelFormatASTC(PixelFormat format) {
+    switch (format) {
+    case PixelFormat::ASTC_2D_4X4:
+    case PixelFormat::ASTC_2D_5X4:
+    case PixelFormat::ASTC_2D_8X8:
+    case PixelFormat::ASTC_2D_8X5:
+    case PixelFormat::ASTC_2D_4X4_SRGB:
+    case PixelFormat::ASTC_2D_5X4_SRGB:
+    case PixelFormat::ASTC_2D_8X8_SRGB:
+    case PixelFormat::ASTC_2D_8X5_SRGB:
+        return true;
+    default:
+        return false;
+    }
+}
+
+std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
+    switch (format) {
+    case PixelFormat::ASTC_2D_4X4:
+        return {4, 4};
+    case PixelFormat::ASTC_2D_5X4:
+        return {5, 4};
+    case PixelFormat::ASTC_2D_8X8:
+        return {8, 8};
+    case PixelFormat::ASTC_2D_8X5:
+        return {8, 5};
+    case PixelFormat::ASTC_2D_4X4_SRGB:
+        return {4, 4};
+    case PixelFormat::ASTC_2D_5X4_SRGB:
+        return {5, 4};
+    case PixelFormat::ASTC_2D_8X8_SRGB:
+        return {8, 8};
+    case PixelFormat::ASTC_2D_8X5_SRGB:
+        return {8, 5};
+    default:
+        LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
+        UNREACHABLE();
+    }
+}
+
+bool IsFormatBCn(PixelFormat format) {
+    switch (format) {
+    case PixelFormat::DXT1:
+    case PixelFormat::DXT23:
+    case PixelFormat::DXT45:
+    case PixelFormat::DXN1:
+    case PixelFormat::DXN2SNORM:
+    case PixelFormat::DXN2UNORM:
+    case PixelFormat::BC7U:
+    case PixelFormat::BC6H_UF16:
+    case PixelFormat::BC6H_SF16:
+    case PixelFormat::DXT1_SRGB:
+    case PixelFormat::DXT23_SRGB:
+    case PixelFormat::DXT45_SRGB:
+    case PixelFormat::BC7U_SRGB:
+        return true;
+    }
+    return false;
+}
+
+} // namespace VideoCore::Surface
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
new file mode 100644
index 0000000000000000000000000000000000000000..3232e437f35c0af7ded3565379bb35624705159f
--- /dev/null
+++ b/src/video_core/surface.h
@@ -0,0 +1,385 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <climits>
+#include <utility>
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "video_core/gpu.h"
+#include "video_core/textures/texture.h"
+
+namespace VideoCore::Surface {
+
+enum class PixelFormat {
+    ABGR8U = 0,
+    ABGR8S = 1,
+    ABGR8UI = 2,
+    B5G6R5U = 3,
+    A2B10G10R10U = 4,
+    A1B5G5R5U = 5,
+    R8U = 6,
+    R8UI = 7,
+    RGBA16F = 8,
+    RGBA16U = 9,
+    RGBA16UI = 10,
+    R11FG11FB10F = 11,
+    RGBA32UI = 12,
+    DXT1 = 13,
+    DXT23 = 14,
+    DXT45 = 15,
+    DXN1 = 16, // This is also known as BC4
+    DXN2UNORM = 17,
+    DXN2SNORM = 18,
+    BC7U = 19,
+    BC6H_UF16 = 20,
+    BC6H_SF16 = 21,
+    ASTC_2D_4X4 = 22,
+    G8R8U = 23,
+    G8R8S = 24,
+    BGRA8 = 25,
+    RGBA32F = 26,
+    RG32F = 27,
+    R32F = 28,
+    R16F = 29,
+    R16U = 30,
+    R16S = 31,
+    R16UI = 32,
+    R16I = 33,
+    RG16 = 34,
+    RG16F = 35,
+    RG16UI = 36,
+    RG16I = 37,
+    RG16S = 38,
+    RGB32F = 39,
+    RGBA8_SRGB = 40,
+    RG8U = 41,
+    RG8S = 42,
+    RG32UI = 43,
+    R32UI = 44,
+    ASTC_2D_8X8 = 45,
+    ASTC_2D_8X5 = 46,
+    ASTC_2D_5X4 = 47,
+    BGRA8_SRGB = 48,
+    DXT1_SRGB = 49,
+    DXT23_SRGB = 50,
+    DXT45_SRGB = 51,
+    BC7U_SRGB = 52,
+    ASTC_2D_4X4_SRGB = 53,
+    ASTC_2D_8X8_SRGB = 54,
+    ASTC_2D_8X5_SRGB = 55,
+    ASTC_2D_5X4_SRGB = 56,
+
+    MaxColorFormat,
+
+    // Depth formats
+    Z32F = 57,
+    Z16 = 58,
+
+    MaxDepthFormat,
+
+    // DepthStencil formats
+    Z24S8 = 59,
+    S8Z24 = 60,
+    Z32FS8 = 61,
+
+    MaxDepthStencilFormat,
+
+    Max = MaxDepthStencilFormat,
+    Invalid = 255,
+};
+
+static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
+
+enum class ComponentType {
+    Invalid = 0,
+    SNorm = 1,
+    UNorm = 2,
+    SInt = 3,
+    UInt = 4,
+    Float = 5,
+};
+
+enum class SurfaceType {
+    ColorTexture = 0,
+    Depth = 1,
+    DepthStencil = 2,
+    Fill = 3,
+    Invalid = 4,
+};
+
+enum class SurfaceTarget {
+    Texture1D,
+    Texture2D,
+    Texture3D,
+    Texture1DArray,
+    Texture2DArray,
+    TextureCubemap,
+};
+
+/**
+ * Gets the compression factor for the specified PixelFormat. This applies to just the
+ * "compressed width" and "compressed height", not the overall compression factor of a
+ * compressed image. This is used for maintaining proper surface sizes for compressed
+ * texture formats.
+ */
+static constexpr u32 GetCompressionFactor(PixelFormat format) {
+    if (format == PixelFormat::Invalid)
+        return 0;
+
+    constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
+        1, // ABGR8U
+        1, // ABGR8S
+        1, // ABGR8UI
+        1, // B5G6R5U
+        1, // A2B10G10R10U
+        1, // A1B5G5R5U
+        1, // R8U
+        1, // R8UI
+        1, // RGBA16F
+        1, // RGBA16U
+        1, // RGBA16UI
+        1, // R11FG11FB10F
+        1, // RGBA32UI
+        4, // DXT1
+        4, // DXT23
+        4, // DXT45
+        4, // DXN1
+        4, // DXN2UNORM
+        4, // DXN2SNORM
+        4, // BC7U
+        4, // BC6H_UF16
+        4, // BC6H_SF16
+        4, // ASTC_2D_4X4
+        1, // G8R8U
+        1, // G8R8S
+        1, // BGRA8
+        1, // RGBA32F
+        1, // RG32F
+        1, // R32F
+        1, // R16F
+        1, // R16U
+        1, // R16S
+        1, // R16UI
+        1, // R16I
+        1, // RG16
+        1, // RG16F
+        1, // RG16UI
+        1, // RG16I
+        1, // RG16S
+        1, // RGB32F
+        1, // RGBA8_SRGB
+        1, // RG8U
+        1, // RG8S
+        1, // RG32UI
+        1, // R32UI
+        4, // ASTC_2D_8X8
+        4, // ASTC_2D_8X5
+        4, // ASTC_2D_5X4
+        1, // BGRA8_SRGB
+        4, // DXT1_SRGB
+        4, // DXT23_SRGB
+        4, // DXT45_SRGB
+        4, // BC7U_SRGB
+        4, // ASTC_2D_4X4_SRGB
+        4, // ASTC_2D_8X8_SRGB
+        4, // ASTC_2D_8X5_SRGB
+        4, // ASTC_2D_5X4_SRGB
+        1, // Z32F
+        1, // Z16
+        1, // Z24S8
+        1, // S8Z24
+        1, // Z32FS8
+    }};
+
+    ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
+    return compression_factor_table[static_cast<std::size_t>(format)];
+}
+
+static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
+    if (format == PixelFormat::Invalid)
+        return 0;
+
+    constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
+        1, // ABGR8U
+        1, // ABGR8S
+        1, // ABGR8UI
+        1, // B5G6R5U
+        1, // A2B10G10R10U
+        1, // A1B5G5R5U
+        1, // R8U
+        1, // R8UI
+        1, // RGBA16F
+        1, // RGBA16U
+        1, // RGBA16UI
+        1, // R11FG11FB10F
+        1, // RGBA32UI
+        4, // DXT1
+        4, // DXT23
+        4, // DXT45
+        4, // DXN1
+        4, // DXN2UNORM
+        4, // DXN2SNORM
+        4, // BC7U
+        4, // BC6H_UF16
+        4, // BC6H_SF16
+        4, // ASTC_2D_4X4
+        1, // G8R8U
+        1, // G8R8S
+        1, // BGRA8
+        1, // RGBA32F
+        1, // RG32F
+        1, // R32F
+        1, // R16F
+        1, // R16U
+        1, // R16S
+        1, // R16UI
+        1, // R16I
+        1, // RG16
+        1, // RG16F
+        1, // RG16UI
+        1, // RG16I
+        1, // RG16S
+        1, // RGB32F
+        1, // RGBA8_SRGB
+        1, // RG8U
+        1, // RG8S
+        1, // RG32UI
+        1, // R32UI
+        8, // ASTC_2D_8X8
+        5, // ASTC_2D_8X5
+        4, // ASTC_2D_5X4
+        1, // BGRA8_SRGB
+        4, // DXT1_SRGB
+        4, // DXT23_SRGB
+        4, // DXT45_SRGB
+        4, // BC7U_SRGB
+        4, // ASTC_2D_4X4_SRGB
+        8, // ASTC_2D_8X8_SRGB
+        5, // ASTC_2D_8X5_SRGB
+        4, // ASTC_2D_5X4_SRGB
+        1, // Z32F
+        1, // Z16
+        1, // Z24S8
+        1, // S8Z24
+        1, // Z32FS8
+    }};
+
+    ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
+    return block_height_table[static_cast<std::size_t>(format)];
+}
+
+static constexpr u32 GetFormatBpp(PixelFormat format) {
+    if (format == PixelFormat::Invalid)
+        return 0;
+
+    constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
+        32,  // ABGR8U
+        32,  // ABGR8S
+        32,  // ABGR8UI
+        16,  // B5G6R5U
+        32,  // A2B10G10R10U
+        16,  // A1B5G5R5U
+        8,   // R8U
+        8,   // R8UI
+        64,  // RGBA16F
+        64,  // RGBA16U
+        64,  // RGBA16UI
+        32,  // R11FG11FB10F
+        128, // RGBA32UI
+        64,  // DXT1
+        128, // DXT23
+        128, // DXT45
+        64,  // DXN1
+        128, // DXN2UNORM
+        128, // DXN2SNORM
+        128, // BC7U
+        128, // BC6H_UF16
+        128, // BC6H_SF16
+        32,  // ASTC_2D_4X4
+        16,  // G8R8U
+        16,  // G8R8S
+        32,  // BGRA8
+        128, // RGBA32F
+        64,  // RG32F
+        32,  // R32F
+        16,  // R16F
+        16,  // R16U
+        16,  // R16S
+        16,  // R16UI
+        16,  // R16I
+        32,  // RG16
+        32,  // RG16F
+        32,  // RG16UI
+        32,  // RG16I
+        32,  // RG16S
+        96,  // RGB32F
+        32,  // RGBA8_SRGB
+        16,  // RG8U
+        16,  // RG8S
+        64,  // RG32UI
+        32,  // R32UI
+        16,  // ASTC_2D_8X8
+        16,  // ASTC_2D_8X5
+        32,  // ASTC_2D_5X4
+        32,  // BGRA8_SRGB
+        64,  // DXT1_SRGB
+        128, // DXT23_SRGB
+        128, // DXT45_SRGB
+        128, // BC7U
+        32,  // ASTC_2D_4X4_SRGB
+        16,  // ASTC_2D_8X8_SRGB
+        16,  // ASTC_2D_8X5_SRGB
+        32,  // ASTC_2D_5X4_SRGB
+        32,  // Z32F
+        16,  // Z16
+        32,  // Z24S8
+        32,  // S8Z24
+        64,  // Z32FS8
+    }};
+
+    ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
+    return bpp_table[static_cast<std::size_t>(format)];
+}
+
+/// Returns the sizer in bytes of the specified pixel format
+static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
+    if (pixel_format == PixelFormat::Invalid) {
+        return 0;
+    }
+    return GetFormatBpp(pixel_format) / CHAR_BIT;
+}
+
+SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type);
+
+bool SurfaceTargetIsLayered(SurfaceTarget target);
+
+PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format);
+
+PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format);
+
+PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
+                                         Tegra::Texture::ComponentType component_type,
+                                         bool is_srgb);
+
+ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type);
+
+ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format);
+
+PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format);
+
+ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format);
+
+SurfaceType GetFormatType(PixelFormat pixel_format);
+
+bool IsPixelFormatASTC(PixelFormat format);
+
+std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
+
+/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
+bool IsFormatBCn(PixelFormat format);
+
+} // namespace VideoCore::Surface
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp
index 0a8f2bd9e12a1e1199705d90dca4be1248696b6b..9156ce80282c7b07b03397139000abfa09455a1b 100644
--- a/src/web_service/telemetry_json.cpp
+++ b/src/web_service/telemetry_json.cpp
@@ -102,16 +102,27 @@ void TelemetryJson::Complete() {
     impl->SerializeSection(Telemetry::FieldType::App, "App");
     impl->SerializeSection(Telemetry::FieldType::Session, "Session");
     impl->SerializeSection(Telemetry::FieldType::Performance, "Performance");
-    impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
     impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
     impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
 
     auto content = impl->TopSection().dump();
     // Send the telemetry async but don't handle the errors since they were written to the log
-    Common::DetachedTasks::AddTask(
-        [host{impl->host}, username{impl->username}, token{impl->token}, content]() {
-            Client{host, username, token}.PostJson("/telemetry", content, true);
-        });
+    Common::DetachedTasks::AddTask([host{impl->host}, content]() {
+        Client{host, "", ""}.PostJson("/telemetry", content, true);
+    });
+}
+
+bool TelemetryJson::SubmitTestcase() {
+    impl->SerializeSection(Telemetry::FieldType::App, "App");
+    impl->SerializeSection(Telemetry::FieldType::Session, "Session");
+    impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
+    impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
+
+    auto content = impl->TopSection().dump();
+    Client client(impl->host, impl->username, impl->token);
+    auto value = client.PostJson("/gamedb/testcase", content, false);
+
+    return value.result_code == Common::WebResult::Code::Success;
 }
 
 } // namespace WebService
diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h
index 93371414aeda6e23441f1c9db3628bed44860f99..dfd202829a1259b22948672945fcccb495e8ff2b 100644
--- a/src/web_service/telemetry_json.h
+++ b/src/web_service/telemetry_json.h
@@ -35,6 +35,7 @@ public:
     void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override;
 
     void Complete() override;
+    bool SubmitTestcase() override;
 
 private:
     struct Impl;
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 9379d9110f32a3d66be993331f9b8b77df80e898..f9ca2948ee82e8a688fa678ccbe8009d8777d2cb 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -56,6 +56,8 @@ add_executable(yuzu
     main.h
     ui_settings.cpp
     ui_settings.h
+    util/limitable_input_dialog.cpp
+    util/limitable_input_dialog.h
     util/spinbox.cpp
     util/spinbox.h
     util/util.cpp
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index 91e75427431fa69dbe5da7b426c4dc31f231f99d..5f0896f848774872ae528c8560f0394a9e612e7c 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -5,6 +5,7 @@
 #include <QButtonGroup>
 #include <QMessageBox>
 #include <QPushButton>
+#include <QtConcurrent/qtconcurrentrun.h>
 #include "common/logging/log.h"
 #include "common/telemetry.h"
 #include "core/core.h"
@@ -23,6 +24,8 @@ CompatDB::CompatDB(QWidget* parent)
     connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext);
     connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext);
     connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit);
+    connect(&testcase_watcher, &QFutureWatcher<bool>::finished, this,
+            &CompatDB::OnTestcaseSubmitted);
 }
 
 CompatDB::~CompatDB() = default;
@@ -48,18 +51,38 @@ void CompatDB::Submit() {
         }
         break;
     case CompatDBPage::Final:
+        back();
         LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
         Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility",
                                    compatibility->checkedId());
-        // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
-        // workaround
+
+        button(NextButton)->setEnabled(false);
+        button(NextButton)->setText(tr("Submitting"));
         button(QWizard::CancelButton)->setVisible(false);
+
+        testcase_watcher.setFuture(QtConcurrent::run(
+            [this]() { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); }));
         break;
     default:
         LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
     }
 }
 
+void CompatDB::OnTestcaseSubmitted() {
+    if (!testcase_watcher.result()) {
+        QMessageBox::critical(this, tr("Communication error"),
+                              tr("An error occured while sending the Testcase"));
+        button(NextButton)->setEnabled(true);
+        button(NextButton)->setText(tr("Next"));
+        button(QWizard::CancelButton)->setVisible(true);
+    } else {
+        next();
+        // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
+        // workaround
+        button(QWizard::CancelButton)->setVisible(false);
+    }
+}
+
 void CompatDB::EnableNext() {
     button(NextButton)->setEnabled(true);
 }
diff --git a/src/yuzu/compatdb.h b/src/yuzu/compatdb.h
index ca0dd11d6105e115c1acff915e9c7719624ce76e..5381f67f79aa9e93041a84df06e9ed7c9585e972 100644
--- a/src/yuzu/compatdb.h
+++ b/src/yuzu/compatdb.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <memory>
+#include <QFutureWatcher>
 #include <QWizard>
 
 namespace Ui {
@@ -19,8 +20,11 @@ public:
     ~CompatDB();
 
 private:
+    QFutureWatcher<bool> testcase_watcher;
+
     std::unique_ptr<Ui::CompatDB> ui;
 
     void Submit();
+    void OnTestcaseSubmitted();
     void EnableNext();
 };
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 1b8aa7de2c2e35f3d0b89eaac5f94ffba84c6a95..b4b4a4a567b986d5c93195d961a30e99156858ed 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -6,20 +6,20 @@
 #include <QFileDialog>
 #include <QGraphicsItem>
 #include <QGraphicsScene>
-#include <QInputDialog>
+#include <QHeaderView>
 #include <QMessageBox>
 #include <QStandardItemModel>
 #include <QTreeView>
 #include <QVBoxLayout>
-#include "common/common_paths.h"
-#include "common/logging/backend.h"
+#include "common/assert.h"
+#include "common/file_util.h"
 #include "common/string_util.h"
 #include "core/core.h"
 #include "core/hle/service/acc/profile_manager.h"
 #include "core/settings.h"
 #include "ui_configure_system.h"
 #include "yuzu/configuration/configure_system.h"
-#include "yuzu/main.h"
+#include "yuzu/util/limitable_input_dialog.h"
 
 namespace {
 constexpr std::array<int, 12> days_in_month = {{
@@ -83,6 +83,12 @@ QPixmap GetIcon(Service::Account::UUID uuid) {
 
     return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
 }
+
+QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_text) {
+    return LimitableInputDialog::GetText(parent, ConfigureSystem::tr("Enter Username"),
+                                         description_text, 1,
+                                         static_cast<int>(Service::Account::profile_username_size));
+}
 } // Anonymous namespace
 
 ConfigureSystem::ConfigureSystem(QWidget* parent)
@@ -244,15 +250,13 @@ void ConfigureSystem::SelectUser(const QModelIndex& index) {
 }
 
 void ConfigureSystem::AddUser() {
-    const auto uuid = Service::Account::UUID::Generate();
-
-    bool ok = false;
     const auto username =
-        QInputDialog::getText(this, tr("Enter Username"), tr("Enter a username for the new user:"),
-                              QLineEdit::Normal, QString(), &ok);
-    if (!ok)
+        GetProfileUsernameFromUser(this, tr("Enter a username for the new user:"));
+    if (username.isEmpty()) {
         return;
+    }
 
+    const auto uuid = Service::Account::UUID::Generate();
     profile_manager->CreateNewUser(uuid, username.toStdString());
 
     item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
@@ -267,23 +271,14 @@ void ConfigureSystem::RenameUser() {
     if (!profile_manager->GetProfileBase(*uuid, profile))
         return;
 
-    bool ok = false;
-    const auto old_username = GetAccountUsername(*profile_manager, *uuid);
-    const auto new_username =
-        QInputDialog::getText(this, tr("Enter Username"), tr("Enter a new username:"),
-                              QLineEdit::Normal, old_username, &ok);
-
-    if (!ok)
+    const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:"));
+    if (new_username.isEmpty()) {
         return;
+    }
 
-    std::fill(profile.username.begin(), profile.username.end(), '\0');
     const auto username_std = new_username.toStdString();
-    if (username_std.size() > profile.username.size()) {
-        std::copy_n(username_std.begin(), std::min(profile.username.size(), username_std.size()),
-                    profile.username.begin());
-    } else {
-        std::copy(username_std.begin(), username_std.end(), profile.username.begin());
-    }
+    std::fill(profile.username.begin(), profile.username.end(), '\0');
+    std::copy(username_std.begin(), username_std.end(), profile.username.begin());
 
     profile_manager->SetProfileBase(*uuid, profile);
 
diff --git a/src/yuzu/util/limitable_input_dialog.cpp b/src/yuzu/util/limitable_input_dialog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..edd78e5793d723d9685709df57d979fc32c5240b
--- /dev/null
+++ b/src/yuzu/util/limitable_input_dialog.cpp
@@ -0,0 +1,59 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QDialogButtonBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include "yuzu/util/limitable_input_dialog.h"
+
+LimitableInputDialog::LimitableInputDialog(QWidget* parent) : QDialog{parent} {
+    CreateUI();
+    ConnectEvents();
+}
+
+LimitableInputDialog::~LimitableInputDialog() = default;
+
+void LimitableInputDialog::CreateUI() {
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    text_label = new QLabel(this);
+    text_entry = new QLineEdit(this);
+    buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
+
+    auto* const layout = new QVBoxLayout;
+    layout->addWidget(text_label);
+    layout->addWidget(text_entry);
+    layout->addWidget(buttons);
+
+    setLayout(layout);
+}
+
+void LimitableInputDialog::ConnectEvents() {
+    connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
+    connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
+}
+
+QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, const QString& text,
+                                      int min_character_limit, int max_character_limit) {
+    Q_ASSERT(min_character_limit <= max_character_limit);
+
+    LimitableInputDialog dialog{parent};
+    dialog.setWindowTitle(title);
+    dialog.text_label->setText(text);
+    dialog.text_entry->setMaxLength(max_character_limit);
+
+    auto* const ok_button = dialog.buttons->button(QDialogButtonBox::Ok);
+    ok_button->setEnabled(false);
+    connect(dialog.text_entry, &QLineEdit::textEdited, [&](const QString& new_text) {
+        ok_button->setEnabled(new_text.length() >= min_character_limit);
+    });
+
+    if (dialog.exec() != QDialog::Accepted) {
+        return {};
+    }
+
+    return dialog.text_entry->text();
+}
diff --git a/src/yuzu/util/limitable_input_dialog.h b/src/yuzu/util/limitable_input_dialog.h
new file mode 100644
index 0000000000000000000000000000000000000000..164ad73019eabcdb305a8829fd0bb800d9e9076f
--- /dev/null
+++ b/src/yuzu/util/limitable_input_dialog.h
@@ -0,0 +1,31 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <QDialog>
+
+class QDialogButtonBox;
+class QLabel;
+class QLineEdit;
+
+/// A QDialog that functions similarly to QInputDialog, however, it allows
+/// restricting the minimum and total number of characters that can be entered.
+class LimitableInputDialog final : public QDialog {
+    Q_OBJECT
+public:
+    explicit LimitableInputDialog(QWidget* parent = nullptr);
+    ~LimitableInputDialog() override;
+
+    static QString GetText(QWidget* parent, const QString& title, const QString& text,
+                           int min_character_limit, int max_character_limit);
+
+private:
+    void CreateUI();
+    void ConnectEvents();
+
+    QLabel* text_label;
+    QLineEdit* text_entry;
+    QDialogButtonBox* buttons;
+};