Преглед изворни кода

Merge branch 'master' into Texture2DArray

greggameplayer пре 7 година
родитељ
комит
d3b9599b2d

+ 9 - 2
src/common/logging/backend.cpp

@@ -12,7 +12,8 @@
 #include <thread>
 #include <vector>
 #ifdef _WIN32
-#include <share.h> // For _SH_DENYWR
+#include <share.h>   // For _SH_DENYWR
+#include <windows.h> // For OutputDebugStringA
 #else
 #define _SH_DENYWR 0
 #endif
@@ -139,12 +140,18 @@ void FileBackend::Write(const Entry& entry) {
     if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) {
         return;
     }
-    bytes_written += file.WriteString(FormatLogMessage(entry) + '\n');
+    bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n'));
     if (entry.log_level >= Level::Error) {
         file.Flush();
     }
 }
 
+void DebuggerBackend::Write(const Entry& entry) {
+#ifdef _WIN32
+    ::OutputDebugStringA(FormatLogMessage(entry).append(1, '\n').c_str());
+#endif
+}
+
 /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
 #define ALL_LOG_CLASSES()                                                                          \
     CLS(Log)                                                                                       \

+ 14 - 0
src/common/logging/backend.h

@@ -103,6 +103,20 @@ private:
     std::size_t bytes_written;
 };
 
+/**
+ * Backend that writes to Visual Studio's output window
+ */
+class DebuggerBackend : public Backend {
+public:
+    static const char* Name() {
+        return "debugger";
+    }
+    const char* GetName() const override {
+        return Name();
+    }
+    void Write(const Entry& entry) override;
+};
+
 void AddBackend(std::unique_ptr<Backend> backend);
 
 void RemoveBackend(std::string_view backend_name);

+ 1 - 1
src/core/hle/service/audio/hwopus.cpp

@@ -161,7 +161,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
     ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
 
     std::size_t worker_sz = WorkerBufferSize(channel_count);
-    ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large");
+    ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
     std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
         static_cast<OpusDecoder*>(operator new(worker_sz))};
     if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {

+ 3 - 0
src/core/hle/service/hid/controllers/npad.cpp

@@ -427,6 +427,9 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
 }
 
 Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const {
+    // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
+    // be signalled at least once, and signaled after a new controller is connected?
+    styleset_changed_event->Signal();
     return styleset_changed_event;
 }
 

+ 2 - 0
src/core/hle/service/hid/hid.cpp

@@ -96,6 +96,8 @@ public:
         // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
 
         CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
+
+        ReloadInputDevices();
     }
 
     void ActivateController(HidController controller) {

+ 2 - 2
src/core/hle/service/nvflinger/buffer_queue.h

@@ -58,9 +58,9 @@ public:
         /// Rotate source image 90 degrees clockwise
         Rotate90 = 0x04,
         /// Rotate source image 180 degrees
-        Roate180 = 0x03,
+        Rotate180 = 0x03,
         /// Rotate source image 270 degrees clockwise
-        Roate270 = 0x07,
+        Rotate270 = 0x07,
     };
 
     struct Buffer {

+ 1 - 0
src/video_core/CMakeLists.txt

@@ -33,6 +33,7 @@ add_library(video_core STATIC
     renderer_opengl/gl_rasterizer.h
     renderer_opengl/gl_rasterizer_cache.cpp
     renderer_opengl/gl_rasterizer_cache.h
+    renderer_opengl/gl_resource_manager.cpp
     renderer_opengl/gl_resource_manager.h
     renderer_opengl/gl_shader_cache.cpp
     renderer_opengl/gl_shader_cache.h

+ 39 - 14
src/video_core/renderer_opengl/gl_rasterizer_cache.cpp

@@ -16,6 +16,7 @@
 #include "core/settings.h"
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/renderer_opengl/gl_rasterizer_cache.h"
+#include "video_core/renderer_opengl/gl_state.h"
 #include "video_core/renderer_opengl/utils.h"
 #include "video_core/surface.h"
 #include "video_core/textures/astc.h"
@@ -58,16 +59,14 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
 
 std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only,
                                                  bool uncompressed) const {
-    const u32 compression_factor{GetCompressionFactor(pixel_format)};
+    const u32 tile_x{GetDefaultBlockWidth(pixel_format)};
+    const u32 tile_y{GetDefaultBlockHeight(pixel_format)};
     const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
     u32 m_depth = (layer_only ? 1U : depth);
     u32 m_width = MipWidth(mip_level);
     u32 m_height = MipHeight(mip_level);
-    m_width = uncompressed ? m_width
-                           : std::max(1U, (m_width + compression_factor - 1) / compression_factor);
-    m_height = uncompressed
-                   ? m_height
-                   : std::max(1U, (m_height + compression_factor - 1) / compression_factor);
+    m_width = uncompressed ? m_width : std::max(1U, (m_width + tile_x - 1) / tile_x);
+    m_height = uncompressed ? m_height : std::max(1U, (m_height + tile_y - 1) / tile_y);
     m_depth = std::max(1U, m_depth >> mip_level);
     u32 m_block_height = MipBlockHeight(mip_level);
     u32 m_block_depth = MipBlockDepth(mip_level);
@@ -128,6 +127,13 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
             params.target = SurfaceTarget::Texture2D;
         }
         break;
+    case SurfaceTarget::TextureCubeArray:
+        params.depth = config.tic.Depth() * 6;
+        if (!entry.IsArray()) {
+            ASSERT(params.depth == 6);
+            params.target = SurfaceTarget::TextureCubemap;
+        }
+        break;
     default:
         LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target));
         UNREACHABLE();
@@ -305,6 +311,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB
+    {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},        // ASTC_2D_5X5
+    {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB
 
     // Depth formats
     {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
@@ -334,6 +342,8 @@ static GLenum SurfaceTargetToGL(SurfaceTarget target) {
         return GL_TEXTURE_2D_ARRAY;
     case SurfaceTarget::TextureCubemap:
         return GL_TEXTURE_CUBE_MAP;
+    case SurfaceTarget::TextureCubeArray:
+        return GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
     }
     LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
     UNREACHABLE();
@@ -364,15 +374,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
 
     // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
     // pixel values.
-    const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
+    const u32 tile_size_x{GetDefaultBlockWidth(format)};
+    const u32 tile_size_y{GetDefaultBlockHeight(format)};
 
     if (morton_to_gl) {
-        const std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
-            addr, tile_size, bytes_per_pixel, stride, height, depth, block_height, block_depth);
+        const std::vector<u8> data =
+            Tegra::Texture::UnswizzleTexture(addr, tile_size_x, tile_size_y, bytes_per_pixel,
+                                             stride, height, depth, block_height, block_depth);
         const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())};
         memcpy(gl_buffer, data.data(), size_to_copy);
     } else {
-        Tegra::Texture::CopySwizzledData(stride / tile_size, height / tile_size, depth,
+        Tegra::Texture::CopySwizzledData((stride + tile_size_x - 1) / tile_size_x,
+                                         (height + tile_size_y - 1) / tile_size_y, depth,
                                          bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr),
                                          gl_buffer, false, block_height, block_depth);
     }
@@ -440,6 +453,8 @@ static constexpr GLConversionArray morton_to_gl_fns = {
         MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
         MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
         MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
+        MortonCopy<true, PixelFormat::ASTC_2D_5X5>,
+        MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
         MortonCopy<true, PixelFormat::Z32F>,
         MortonCopy<true, PixelFormat::Z16>,
         MortonCopy<true, PixelFormat::Z24S8>,
@@ -508,6 +523,8 @@ static constexpr GLConversionArray gl_to_morton_fns = {
         nullptr,
         nullptr,
         nullptr,
+        nullptr,
+        nullptr,
         MortonCopy<false, PixelFormat::Z32F>,
         MortonCopy<false, PixelFormat::Z16>,
         MortonCopy<false, PixelFormat::Z24S8>,
@@ -754,6 +771,7 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
             break;
         case SurfaceTarget::Texture3D:
         case SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::TextureCubeArray:
             glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height,
                                 static_cast<GLsizei>(dst_params.depth), dest_format.format,
                                 dest_format.type, nullptr);
@@ -806,6 +824,7 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
             break;
         case SurfaceTarget::Texture3D:
         case SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::TextureCubeArray:
             glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
                            format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
                            params.depth);
@@ -897,21 +916,24 @@ static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
  * typical desktop GPUs.
  */
 static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format,
-                                               u32 width, u32 height) {
+                                               u32 width, u32 height, u32 depth) {
     switch (pixel_format) {
     case PixelFormat::ASTC_2D_4X4:
     case PixelFormat::ASTC_2D_8X8:
     case PixelFormat::ASTC_2D_8X5:
     case PixelFormat::ASTC_2D_5X4:
+    case PixelFormat::ASTC_2D_5X5:
     case PixelFormat::ASTC_2D_4X4_SRGB:
     case PixelFormat::ASTC_2D_8X8_SRGB:
     case PixelFormat::ASTC_2D_8X5_SRGB:
-    case PixelFormat::ASTC_2D_5X4_SRGB: {
+    case PixelFormat::ASTC_2D_5X4_SRGB:
+    case PixelFormat::ASTC_2D_5X5_SRGB: {
         // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
         u32 block_width{};
         u32 block_height{};
         std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format);
-        data = Tegra::Texture::ASTC::Decompress(data, width, height, block_width, block_height);
+        data =
+            Tegra::Texture::ASTC::Decompress(data, width, height, depth, block_width, block_height);
         break;
     }
     case PixelFormat::S8Z24:
@@ -971,7 +993,7 @@ void CachedSurface::LoadGLBuffer() {
     }
     for (u32 i = 0; i < params.max_mip_level; i++)
         ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
-                                           params.MipHeight(i));
+                                           params.MipHeight(i), params.MipDepth(i));
 }
 
 MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1055,6 +1077,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
                                    &gl_buffer[mip_map][buffer_offset]);
             break;
         case SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::TextureCubeArray:
             glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
                                    static_cast<GLsizei>(params.MipWidth(mip_map)),
                                    static_cast<GLsizei>(params.MipHeight(mip_map)),
@@ -1104,6 +1127,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
                             tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
             break;
         case SurfaceTarget::Texture2DArray:
+        case SurfaceTarget::TextureCubeArray:
             glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
                             static_cast<GLsizei>(rect.GetWidth()),
                             static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
@@ -1307,6 +1331,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
     case SurfaceTarget::TextureCubemap:
     case SurfaceTarget::Texture3D:
     case SurfaceTarget::Texture2DArray:
+    case SurfaceTarget::TextureCubeArray:
         AccurateCopySurface(old_surface, new_surface);
         break;
     default:

+ 3 - 1
src/video_core/renderer_opengl/gl_rasterizer_cache.h

@@ -49,6 +49,8 @@ struct SurfaceParams {
             return "Texture2DArray";
         case SurfaceTarget::TextureCubemap:
             return "TextureCubemap";
+        case SurfaceTarget::TextureCubeArray:
+            return "TextureCubeArray";
         default:
             LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
             UNREACHABLE();
@@ -139,7 +141,7 @@ struct SurfaceParams {
     }
 
     u32 MipDepth(u32 mip_level) const {
-        return std::max(1U, depth >> mip_level);
+        return is_layered ? depth : std::max(1U, depth >> mip_level);
     }
 
     // Auto block resizing algorithm from:

+ 146 - 0
src/video_core/renderer_opengl/gl_resource_manager.cpp

@@ -0,0 +1,146 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <utility>
+#include <glad/glad.h>
+#include "common/common_types.h"
+#include "video_core/renderer_opengl/gl_resource_manager.h"
+#include "video_core/renderer_opengl/gl_shader_util.h"
+#include "video_core/renderer_opengl/gl_state.h"
+
+namespace OpenGL {
+
+void OGLTexture::Create() {
+    if (handle != 0)
+        return;
+    glGenTextures(1, &handle);
+}
+
+void OGLTexture::Release() {
+    if (handle == 0)
+        return;
+    glDeleteTextures(1, &handle);
+    OpenGLState::GetCurState().UnbindTexture(handle).Apply();
+    handle = 0;
+}
+
+void OGLSampler::Create() {
+    if (handle != 0)
+        return;
+    glGenSamplers(1, &handle);
+}
+
+void OGLSampler::Release() {
+    if (handle == 0)
+        return;
+    glDeleteSamplers(1, &handle);
+    OpenGLState::GetCurState().ResetSampler(handle).Apply();
+    handle = 0;
+}
+
+void OGLShader::Create(const char* source, GLenum type) {
+    if (handle != 0)
+        return;
+    if (source == nullptr)
+        return;
+    handle = GLShader::LoadShader(source, type);
+}
+
+void OGLShader::Release() {
+    if (handle == 0)
+        return;
+    glDeleteShader(handle);
+    handle = 0;
+}
+
+void OGLProgram::CreateFromSource(const char* vert_shader, const char* geo_shader,
+                                  const char* frag_shader, bool separable_program) {
+    OGLShader vert, geo, frag;
+    if (vert_shader)
+        vert.Create(vert_shader, GL_VERTEX_SHADER);
+    if (geo_shader)
+        geo.Create(geo_shader, GL_GEOMETRY_SHADER);
+    if (frag_shader)
+        frag.Create(frag_shader, GL_FRAGMENT_SHADER);
+    Create(separable_program, vert.handle, geo.handle, frag.handle);
+}
+
+void OGLProgram::Release() {
+    if (handle == 0)
+        return;
+    glDeleteProgram(handle);
+    OpenGLState::GetCurState().ResetProgram(handle).Apply();
+    handle = 0;
+}
+
+void OGLPipeline::Create() {
+    if (handle != 0)
+        return;
+    glGenProgramPipelines(1, &handle);
+}
+
+void OGLPipeline::Release() {
+    if (handle == 0)
+        return;
+    glDeleteProgramPipelines(1, &handle);
+    OpenGLState::GetCurState().ResetPipeline(handle).Apply();
+    handle = 0;
+}
+
+void OGLBuffer::Create() {
+    if (handle != 0)
+        return;
+    glGenBuffers(1, &handle);
+}
+
+void OGLBuffer::Release() {
+    if (handle == 0)
+        return;
+    glDeleteBuffers(1, &handle);
+    OpenGLState::GetCurState().ResetBuffer(handle).Apply();
+    handle = 0;
+}
+
+void OGLSync::Create() {
+    if (handle != 0)
+        return;
+    handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void OGLSync::Release() {
+    if (handle == 0)
+        return;
+    glDeleteSync(handle);
+    handle = 0;
+}
+
+void OGLVertexArray::Create() {
+    if (handle != 0)
+        return;
+    glGenVertexArrays(1, &handle);
+}
+
+void OGLVertexArray::Release() {
+    if (handle == 0)
+        return;
+    glDeleteVertexArrays(1, &handle);
+    OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
+    handle = 0;
+}
+
+void OGLFramebuffer::Create() {
+    if (handle != 0)
+        return;
+    glGenFramebuffers(1, &handle);
+}
+
+void OGLFramebuffer::Release() {
+    if (handle == 0)
+        return;
+    glDeleteFramebuffers(1, &handle);
+    OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
+    handle = 0;
+}
+
+} // namespace OpenGL

+ 18 - 114
src/video_core/renderer_opengl/gl_resource_manager.h

@@ -8,7 +8,6 @@
 #include <glad/glad.h>
 #include "common/common_types.h"
 #include "video_core/renderer_opengl/gl_shader_util.h"
-#include "video_core/renderer_opengl/gl_state.h"
 
 namespace OpenGL {
 
@@ -29,20 +28,10 @@ public:
     }
 
     /// Creates a new internal OpenGL resource and stores the handle
-    void Create() {
-        if (handle != 0)
-            return;
-        glGenTextures(1, &handle);
-    }
+    void Create();
 
     /// Deletes the internal OpenGL resource
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteTextures(1, &handle);
-        OpenGLState::GetCurState().UnbindTexture(handle).Apply();
-        handle = 0;
-    }
+    void Release();
 
     GLuint handle = 0;
 };
@@ -64,20 +53,10 @@ public:
     }
 
     /// Creates a new internal OpenGL resource and stores the handle
-    void Create() {
-        if (handle != 0)
-            return;
-        glGenSamplers(1, &handle);
-    }
+    void Create();
 
     /// Deletes the internal OpenGL resource
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteSamplers(1, &handle);
-        OpenGLState::GetCurState().ResetSampler(handle).Apply();
-        handle = 0;
-    }
+    void Release();
 
     GLuint handle = 0;
 };
@@ -98,20 +77,9 @@ public:
         return *this;
     }
 
-    void Create(const char* source, GLenum type) {
-        if (handle != 0)
-            return;
-        if (source == nullptr)
-            return;
-        handle = GLShader::LoadShader(source, type);
-    }
+    void Create(const char* source, GLenum type);
 
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteShader(handle);
-        handle = 0;
-    }
+    void Release();
 
     GLuint handle = 0;
 };
@@ -141,25 +109,10 @@ public:
 
     /// Creates a new internal OpenGL resource and stores the handle
     void CreateFromSource(const char* vert_shader, const char* geo_shader, const char* frag_shader,
-                          bool separable_program = false) {
-        OGLShader vert, geo, frag;
-        if (vert_shader)
-            vert.Create(vert_shader, GL_VERTEX_SHADER);
-        if (geo_shader)
-            geo.Create(geo_shader, GL_GEOMETRY_SHADER);
-        if (frag_shader)
-            frag.Create(frag_shader, GL_FRAGMENT_SHADER);
-        Create(separable_program, vert.handle, geo.handle, frag.handle);
-    }
+                          bool separable_program = false);
 
     /// Deletes the internal OpenGL resource
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteProgram(handle);
-        OpenGLState::GetCurState().ResetProgram(handle).Apply();
-        handle = 0;
-    }
+    void Release();
 
     GLuint handle = 0;
 };
@@ -178,20 +131,10 @@ public:
     }
 
     /// Creates a new internal OpenGL resource and stores the handle
-    void Create() {
-        if (handle != 0)
-            return;
-        glGenProgramPipelines(1, &handle);
-    }
+    void Create();
 
     /// Deletes the internal OpenGL resource
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteProgramPipelines(1, &handle);
-        OpenGLState::GetCurState().ResetPipeline(handle).Apply();
-        handle = 0;
-    }
+    void Release();
 
     GLuint handle = 0;
 };
@@ -213,20 +156,10 @@ public:
     }
 
     /// Creates a new internal OpenGL resource and stores the handle
-    void Create() {
-        if (handle != 0)
-            return;
-        glGenBuffers(1, &handle);
-    }
+    void Create();
 
     /// Deletes the internal OpenGL resource
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteBuffers(1, &handle);
-        OpenGLState::GetCurState().ResetBuffer(handle).Apply();
-        handle = 0;
-    }
+    void Release();
 
     GLuint handle = 0;
 };
@@ -247,19 +180,10 @@ public:
     }
 
     /// Creates a new internal OpenGL resource and stores the handle
-    void Create() {
-        if (handle != 0)
-            return;
-        handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-    }
+    void Create();
 
     /// Deletes the internal OpenGL resource
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteSync(handle);
-        handle = 0;
-    }
+    void Release();
 
     GLsync handle = 0;
 };
@@ -281,20 +205,10 @@ public:
     }
 
     /// Creates a new internal OpenGL resource and stores the handle
-    void Create() {
-        if (handle != 0)
-            return;
-        glGenVertexArrays(1, &handle);
-    }
+    void Create();
 
     /// Deletes the internal OpenGL resource
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteVertexArrays(1, &handle);
-        OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
-        handle = 0;
-    }
+    void Release();
 
     GLuint handle = 0;
 };
@@ -316,20 +230,10 @@ public:
     }
 
     /// Creates a new internal OpenGL resource and stores the handle
-    void Create() {
-        if (handle != 0)
-            return;
-        glGenFramebuffers(1, &handle);
-    }
+    void Create();
 
     /// Deletes the internal OpenGL resource
-    void Release() {
-        if (handle == 0)
-            return;
-        glDeleteFramebuffers(1, &handle);
-        OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
-        handle = 0;
-    }
+    void Release();
 
     GLuint handle = 0;
 };

+ 1 - 0
src/video_core/renderer_opengl/gl_shader_manager.h

@@ -7,6 +7,7 @@
 #include <glad/glad.h>
 
 #include "video_core/renderer_opengl/gl_resource_manager.h"
+#include "video_core/renderer_opengl/gl_state.h"
 #include "video_core/renderer_opengl/maxwell_to_gl.h"
 
 namespace OpenGL::GLShader {

+ 8 - 21
src/video_core/surface.cpp

@@ -19,6 +19,8 @@ SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_t
         return SurfaceTarget::Texture3D;
     case Tegra::Texture::TextureType::TextureCubemap:
         return SurfaceTarget::TextureCubemap;
+    case Tegra::Texture::TextureType::TextureCubeArray:
+        return SurfaceTarget::TextureCubeArray;
     case Tegra::Texture::TextureType::Texture1DArray:
         return SurfaceTarget::Texture1DArray;
     case Tegra::Texture::TextureType::Texture2DArray:
@@ -39,6 +41,7 @@ bool SurfaceTargetIsLayered(SurfaceTarget target) {
     case SurfaceTarget::Texture1DArray:
     case SurfaceTarget::Texture2DArray:
     case SurfaceTarget::TextureCubemap:
+    case SurfaceTarget::TextureCubeArray:
         return true;
     default:
         LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
@@ -297,6 +300,8 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
         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_5X5:
+        return is_srgb ? PixelFormat::ASTC_2D_5X5_SRGB : PixelFormat::ASTC_2D_5X5;
     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:
@@ -440,10 +445,12 @@ bool IsPixelFormatASTC(PixelFormat format) {
     switch (format) {
     case PixelFormat::ASTC_2D_4X4:
     case PixelFormat::ASTC_2D_5X4:
+    case PixelFormat::ASTC_2D_5X5:
     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_5X5_SRGB:
     case PixelFormat::ASTC_2D_8X8_SRGB:
     case PixelFormat::ASTC_2D_8X5_SRGB:
         return true;
@@ -453,27 +460,7 @@ bool IsPixelFormatASTC(PixelFormat format) {
 }
 
 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();
-    }
+    return {GetDefaultBlockWidth(format), GetDefaultBlockHeight(format)};
 }
 
 bool IsFormatBCn(PixelFormat format) {

+ 95 - 13
src/video_core/surface.h

@@ -72,19 +72,21 @@ enum class PixelFormat {
     ASTC_2D_8X8_SRGB = 54,
     ASTC_2D_8X5_SRGB = 55,
     ASTC_2D_5X4_SRGB = 56,
+    ASTC_2D_5X5 = 57,
+    ASTC_2D_5X5_SRGB = 58,
 
     MaxColorFormat,
 
     // Depth formats
-    Z32F = 57,
-    Z16 = 58,
+    Z32F = 59,
+    Z16 = 60,
 
     MaxDepthFormat,
 
     // DepthStencil formats
-    Z24S8 = 59,
-    S8Z24 = 60,
-    Z32FS8 = 61,
+    Z24S8 = 61,
+    S8Z24 = 62,
+    Z32FS8 = 63,
 
     MaxDepthStencilFormat,
 
@@ -118,6 +120,7 @@ enum class SurfaceTarget {
     Texture1DArray,
     Texture2DArray,
     TextureCubemap,
+    TextureCubeArray,
 };
 
 /**
@@ -188,6 +191,8 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
         4, // ASTC_2D_8X8_SRGB
         4, // ASTC_2D_8X5_SRGB
         4, // ASTC_2D_5X4_SRGB
+        4, // ASTC_2D_5X5
+        4, // ASTC_2D_5X5_SRGB
         1, // Z32F
         1, // Z16
         1, // Z24S8
@@ -199,6 +204,79 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
     return compression_factor_table[static_cast<std::size_t>(format)];
 }
 
+static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
+    if (format == PixelFormat::Invalid)
+        return 0;
+    constexpr std::array<u32, MaxPixelFormat> block_width_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
+        8, // ASTC_2D_8X5
+        5, // 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
+        8, // ASTC_2D_8X5_SRGB
+        5, // ASTC_2D_5X4_SRGB
+        5, // ASTC_2D_5X5
+        5, // ASTC_2D_5X5_SRGB
+        1, // Z32F
+        1, // Z16
+        1, // Z24S8
+        1, // S8Z24
+        1, // Z32FS8
+    }};
+    ASSERT(static_cast<std::size_t>(format) < block_width_table.size());
+    return block_width_table[static_cast<std::size_t>(format)];
+}
+
 static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
     if (format == PixelFormat::Invalid)
         return 0;
@@ -261,6 +339,8 @@ static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
         8, // ASTC_2D_8X8_SRGB
         5, // ASTC_2D_8X5_SRGB
         4, // ASTC_2D_5X4_SRGB
+        5, // ASTC_2D_5X5
+        5, // ASTC_2D_5X5_SRGB
         1, // Z32F
         1, // Z16
         1, // Z24S8
@@ -299,7 +379,7 @@ static constexpr u32 GetFormatBpp(PixelFormat format) {
         128, // BC7U
         128, // BC6H_UF16
         128, // BC6H_SF16
-        32,  // ASTC_2D_4X4
+        128, // ASTC_2D_4X4
         16,  // G8R8U
         16,  // G8R8S
         32,  // BGRA8
@@ -322,18 +402,20 @@ static constexpr u32 GetFormatBpp(PixelFormat format) {
         16,  // RG8S
         64,  // RG32UI
         32,  // R32UI
-        16,  // ASTC_2D_8X8
-        16,  // ASTC_2D_8X5
-        32,  // ASTC_2D_5X4
+        128, // ASTC_2D_8X8
+        128, // ASTC_2D_8X5
+        128, // 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
+        128, // ASTC_2D_4X4_SRGB
+        128, // ASTC_2D_8X8_SRGB
+        128, // ASTC_2D_8X5_SRGB
+        128, // ASTC_2D_5X4_SRGB
+        128, // ASTC_2D_5X5
+        128, // ASTC_2D_5X5_SRGB
         32,  // Z32F
         16,  // Z16
         32,  // Z24S8

+ 17 - 15
src/video_core/textures/astc.cpp

@@ -1598,27 +1598,29 @@ static void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth,
 namespace Tegra::Texture::ASTC {
 
 std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
-                                uint32_t block_width, uint32_t block_height) {
+                                uint32_t depth, uint32_t block_width, uint32_t block_height) {
     uint32_t blockIdx = 0;
-    std::vector<uint8_t> outData(height * width * 4);
-    for (uint32_t j = 0; j < height; j += block_height) {
-        for (uint32_t i = 0; i < width; i += block_width) {
+    std::vector<uint8_t> outData(height * width * depth * 4);
+    for (uint32_t k = 0; k < depth; k++) {
+        for (uint32_t j = 0; j < height; j += block_height) {
+            for (uint32_t i = 0; i < width; i += block_width) {
 
-            uint8_t* blockPtr = data.data() + blockIdx * 16;
+                uint8_t* blockPtr = data.data() + blockIdx * 16;
 
-            // Blocks can be at most 12x12
-            uint32_t uncompData[144];
-            ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData);
+                // Blocks can be at most 12x12
+                uint32_t uncompData[144];
+                ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData);
 
-            uint32_t decompWidth = std::min(block_width, width - i);
-            uint32_t decompHeight = std::min(block_height, height - j);
+                uint32_t decompWidth = std::min(block_width, width - i);
+                uint32_t decompHeight = std::min(block_height, height - j);
 
-            uint8_t* outRow = outData.data() + (j * width + i) * 4;
-            for (uint32_t jj = 0; jj < decompHeight; jj++) {
-                memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4);
-            }
+                uint8_t* outRow = outData.data() + (j * width + i) * 4;
+                for (uint32_t jj = 0; jj < decompHeight; jj++) {
+                    memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4);
+                }
 
-            blockIdx++;
+                blockIdx++;
+            }
         }
     }
 

+ 1 - 1
src/video_core/textures/astc.h

@@ -10,6 +10,6 @@
 namespace Tegra::Texture::ASTC {
 
 std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
-                                uint32_t block_width, uint32_t block_height);
+                                uint32_t depth, uint32_t block_width, uint32_t block_height);
 
 } // namespace Tegra::Texture::ASTC

+ 7 - 5
src/video_core/textures/decoders.cpp

@@ -227,12 +227,14 @@ u32 BytesPerPixel(TextureFormat format) {
     }
 }
 
-std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
-                                 u32 height, u32 depth, u32 block_height, u32 block_depth) {
+std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
+                                 u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
+                                 u32 block_height, u32 block_depth) {
     std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel);
-    CopySwizzledData(width / tile_size, height / tile_size, depth, bytes_per_pixel, bytes_per_pixel,
-                     Memory::GetPointer(address), unswizzled_data.data(), true, block_height,
-                     block_depth);
+    CopySwizzledData((width + tile_size_x - 1) / tile_size_x,
+                     (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel,
+                     bytes_per_pixel, Memory::GetPointer(address), unswizzled_data.data(), true,
+                     block_height, block_depth);
     return unswizzled_data;
 }
 

+ 2 - 2
src/video_core/textures/decoders.h

@@ -19,8 +19,8 @@ inline std::size_t GetGOBSize() {
 /**
  * Unswizzles a swizzled texture without changing its format.
  */
-std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
-                                 u32 height, u32 depth,
+std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
+                                 u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
                                  u32 block_height = TICEntry::DefaultBlockHeight,
                                  u32 block_depth = TICEntry::DefaultBlockHeight);
 

+ 3 - 3
src/yuzu/debugger/graphics/graphics_surface.cpp

@@ -386,9 +386,9 @@ void GraphicsSurfaceWidget::OnUpdate() {
 
     // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles.
     // Needs to be fixed if we plan to use this feature more, otherwise we may remove it.
-    auto unswizzled_data =
-        Tegra::Texture::UnswizzleTexture(*address, 1, Tegra::Texture::BytesPerPixel(surface_format),
-                                         surface_width, surface_height, 1U);
+    auto unswizzled_data = Tegra::Texture::UnswizzleTexture(
+        *address, 1, 1, Tegra::Texture::BytesPerPixel(surface_format), surface_width,
+        surface_height, 1U);
 
     auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format,
                                                       surface_width, surface_height);

+ 10 - 1
src/yuzu/main.cpp

@@ -142,6 +142,9 @@ static void InitializeLogging() {
     const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
     FileUtil::CreateFullPath(log_dir);
     Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
+#ifdef _WIN32
+    Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
+#endif
 }
 
 GMainWindow::GMainWindow()
@@ -454,6 +457,7 @@ void GMainWindow::ConnectMenuEvents() {
     connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
 
     // Help
+    connect(ui.action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder);
     connect(ui.action_Rederive, &QAction::triggered, this,
             std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
     connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
@@ -1374,6 +1378,11 @@ void GMainWindow::OnLoadAmiibo() {
     }
 }
 
+void GMainWindow::OnOpenYuzuFolder() {
+    QDesktopServices::openUrl(QUrl::fromLocalFile(
+        QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::UserDir))));
+}
+
 void GMainWindow::OnAbout() {
     AboutDialog aboutDialog(this);
     aboutDialog.exec();
@@ -1532,7 +1541,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
                    "derivation. It will be attempted but may not complete.<br><br>") +
                     errors +
                     tr("<br><br>You can get all of these and dump all of your games easily by "
-                       "following <a href='https://yuzu-emu.org/help/quickstart/quickstart/'>the "
+                       "following <a href='https://yuzu-emu.org/help/quickstart/'>the "
                        "quickstart guide</a>. Alternatively, you can use another method of dumping "
                        "to obtain all of your keys."));
         }

+ 1 - 0
src/yuzu/main.h

@@ -167,6 +167,7 @@ private slots:
     void OnMenuRecentFile();
     void OnConfigure();
     void OnLoadAmiibo();
+    void OnOpenYuzuFolder();
     void OnAbout();
     void OnToggleFilterBar();
     void OnDisplayTitleBars(bool);

+ 6 - 0
src/yuzu/main.ui

@@ -110,6 +110,7 @@
      <string>&amp;Help</string>
     </property>
     <addaction name="action_Report_Compatibility"/>
+    <addaction name="action_Open_yuzu_Folder" />
     <addaction name="separator"/>
     <addaction name="action_About"/>
    </widget>
@@ -277,6 +278,11 @@
        <bool>false</bool>
      </property>
    </action>
+   <action name="action_Open_yuzu_Folder">
+     <property name="text">
+       <string>Open yuzu Folder</string>
+     </property>
+   </action>
   </widget>
  <resources/>
  <connections/>

+ 3 - 0
src/yuzu_cmd/yuzu.cpp

@@ -76,6 +76,9 @@ static void InitializeLogging() {
     const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
     FileUtil::CreateFullPath(log_dir);
     Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
+#ifdef _WIN32
+    Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
+#endif
 }
 
 /// Application entry point