فهرست منبع

texture_cache: Move staging buffer into a generic implementation

ReinUsesLisp 7 سال پیش
والد
کامیت
5f3aacdc37

+ 7 - 107
src/video_core/renderer_opengl/gl_texture_cache.cpp

@@ -15,7 +15,6 @@
 
 namespace OpenGL {
 
-using Tegra::Texture::ConvertFromGuestToHost;
 using Tegra::Texture::SwizzleSource;
 using VideoCore::MortonSwizzleMode;
 
@@ -207,32 +206,6 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte
     return texture;
 }
 
-void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
-                 u32 level) {
-    const u32 width{params.GetMipWidth(level)};
-    const u32 height{params.GetMipHeight(level)};
-    const u32 block_height{params.GetMipBlockHeight(level)};
-    const u32 block_depth{params.GetMipBlockDepth(level)};
-
-    std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
-    if (params.IsLayered()) {
-        std::size_t host_offset{0};
-        const std::size_t guest_stride = params.GetGuestLayerSize();
-        const std::size_t host_stride = params.GetHostLayerSize(level);
-        for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
-            MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
-                          1, params.GetTileWidthSpacing(), buffer + host_offset,
-                          memory + guest_offset);
-            guest_offset += guest_stride;
-            host_offset += host_stride;
-        }
-    } else {
-        MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
-                      params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
-                      memory + guest_offset);
-    }
-}
-
 } // Anonymous namespace
 
 CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params)
@@ -245,54 +218,11 @@ CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfacePar
     is_compressed = tuple.compressed;
     target = GetTextureTarget(params);
     texture = CreateTexture(params, target, internal_format);
-    staging_buffer.resize(params.GetHostSizeInBytes());
 }
 
 CachedSurface::~CachedSurface() = default;
 
-void CachedSurface::LoadBuffer() {
-    if (params.IsTiled()) {
-        ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
-                   params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
-        for (u32 level = 0; level < params.GetNumLevels(); ++level) {
-            u8* const buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)};
-            SwizzleFunc(MortonSwizzleMode::MortonToLinear, GetHostPtr(), params, buffer, level);
-        }
-    } else {
-        ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
-        const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
-        const u32 block_width{VideoCore::Surface::GetDefaultBlockWidth(params.GetPixelFormat())};
-        const u32 block_height{VideoCore::Surface::GetDefaultBlockHeight(params.GetPixelFormat())};
-        const u32 width{(params.GetWidth() + block_width - 1) / block_width};
-        const u32 height{(params.GetHeight() + block_height - 1) / block_height};
-        const u32 copy_size{width * bpp};
-        if (params.GetPitch() == copy_size) {
-            std::memcpy(staging_buffer.data(), GetHostPtr(), params.GetHostSizeInBytes());
-        } else {
-            const u8* start{GetHostPtr()};
-            u8* write_to{staging_buffer.data()};
-            for (u32 h = height; h > 0; --h) {
-                std::memcpy(write_to, start, copy_size);
-                start += params.GetPitch();
-                write_to += copy_size;
-            }
-        }
-    }
-
-    for (u32 level = 0; level < params.GetNumLevels(); ++level) {
-        ConvertFromGuestToHost(staging_buffer.data() + params.GetHostMipmapLevelOffset(level),
-                               params.GetPixelFormat(), params.GetMipWidth(level),
-                               params.GetMipHeight(level), params.GetMipDepth(level), true, true);
-    }
-}
-
-void CachedSurface::FlushBufferImpl() {
-    LOG_CRITICAL(Render_OpenGL, "Flushing");
-
-    if (!IsModified()) {
-        return;
-    }
-
+void CachedSurface::DownloadTextureImpl() {
     // TODO(Rodrigo): Optimize alignment
     glPixelStorei(GL_PACK_ALIGNMENT, 1);
     SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); });
@@ -300,60 +230,30 @@ void CachedSurface::FlushBufferImpl() {
     for (u32 level = 0; level < params.GetNumLevels(); ++level) {
         glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
         if (is_compressed) {
-            glGetCompressedTextureImage(
-                texture.handle, level, static_cast<GLsizei>(params.GetHostMipmapSize(level)),
-                staging_buffer.data() + params.GetHostMipmapLevelOffset(level));
+            glGetCompressedTextureImage(texture.handle, level,
+                                        static_cast<GLsizei>(params.GetHostMipmapSize(level)),
+                                        GetStagingBufferLevelData(level));
         } else {
             glGetTextureImage(texture.handle, level, format, type,
                               static_cast<GLsizei>(params.GetHostMipmapSize(level)),
-                              staging_buffer.data() + params.GetHostMipmapLevelOffset(level));
+                              GetStagingBufferLevelData(level));
         }
     }
-
-    if (params.IsTiled()) {
-        ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
-                   params.GetBlockWidth());
-        for (u32 level = 0; level < params.GetNumLevels(); ++level) {
-            u8* const buffer = staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
-            SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level);
-        }
-    } else {
-        UNIMPLEMENTED();
-        /*
-        ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
-        ASSERT(params.GetNumLevels() == 1);
-
-        const u32 bpp{params.GetFormatBpp() / 8};
-        const u32 copy_size{params.GetWidth() * bpp};
-        if (params.GetPitch() == copy_size) {
-            std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
-        } else {
-            u8* start{host_ptr};
-            const u8* read_to{staging_buffer.data()};
-            for (u32 h = params.GetHeight(); h > 0; --h) {
-                std::memcpy(start, read_to, copy_size);
-                start += params.GetPitch();
-                read_to += copy_size;
-            }
-        }
-        */
-    }
 }
 
 void CachedSurface::UploadTextureImpl() {
+    SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
     for (u32 level = 0; level < params.GetNumLevels(); ++level) {
         UploadTextureMipmap(level);
     }
 }
 
 void CachedSurface::UploadTextureMipmap(u32 level) {
-    u8* buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)};
-
     // TODO(Rodrigo): Optimize alignment
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
-    SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
 
+    u8* buffer{GetStagingBufferLevelData(level)};
     if (is_compressed) {
         const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))};
         switch (params.GetTarget()) {

+ 1 - 6
src/video_core/renderer_opengl/gl_texture_cache.h

@@ -39,8 +39,6 @@ public:
     explicit CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params);
     ~CachedSurface();
 
-    void LoadBuffer();
-
     GLenum GetTarget() const {
         return target;
     }
@@ -54,9 +52,8 @@ protected:
 
     std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key);
 
-    void FlushBufferImpl();
-
     void UploadTextureImpl();
+    void DownloadTextureImpl();
 
 private:
     void UploadTextureMipmap(u32 level);
@@ -68,8 +65,6 @@ private:
     GLenum target{};
 
     OGLTexture texture;
-
-    std::vector<u8> staging_buffer;
 };
 
 class CachedSurfaceView final {

+ 109 - 1
src/video_core/texture_cache.cpp

@@ -7,14 +7,16 @@
 #include "common/cityhash.h"
 #include "common/common_types.h"
 #include "core/core.h"
+#include "video_core/morton.h"
 #include "video_core/surface.h"
 #include "video_core/texture_cache.h"
+#include "video_core/textures/convert.h"
 #include "video_core/textures/decoders.h"
 #include "video_core/textures/texture.h"
 
 namespace VideoCommon {
 
-using VideoCore::Surface::SurfaceTarget;
+using VideoCore::MortonSwizzleMode;
 
 using VideoCore::Surface::ComponentTypeFromDepthFormat;
 using VideoCore::Surface::ComponentTypeFromRenderTarget;
@@ -22,12 +24,118 @@ using VideoCore::Surface::ComponentTypeFromTexture;
 using VideoCore::Surface::PixelFormatFromDepthFormat;
 using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
 using VideoCore::Surface::PixelFormatFromTextureFormat;
+using VideoCore::Surface::SurfaceTarget;
 using VideoCore::Surface::SurfaceTargetFromTextureType;
 
+using Tegra::Texture::ConvertFromGuestToHost;
+
+namespace {
+
 constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
     return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
 }
 
+void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
+                 u32 level) {
+    const u32 width{params.GetMipWidth(level)};
+    const u32 height{params.GetMipHeight(level)};
+    const u32 block_height{params.GetMipBlockHeight(level)};
+    const u32 block_depth{params.GetMipBlockDepth(level)};
+
+    std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
+    if (params.IsLayered()) {
+        std::size_t host_offset{0};
+        const std::size_t guest_stride = params.GetGuestLayerSize();
+        const std::size_t host_stride = params.GetHostLayerSize(level);
+        for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
+            MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
+                          1, params.GetTileWidthSpacing(), buffer + host_offset,
+                          memory + guest_offset);
+            guest_offset += guest_stride;
+            host_offset += host_stride;
+        }
+    } else {
+        MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
+                      params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
+                      memory + guest_offset);
+    }
+}
+
+} // Anonymous namespace
+
+SurfaceBaseImpl::SurfaceBaseImpl(const SurfaceParams& params) : params{params} {
+    staging_buffer.resize(params.GetHostSizeInBytes());
+}
+
+SurfaceBaseImpl::~SurfaceBaseImpl() = default;
+
+void SurfaceBaseImpl::LoadBuffer() {
+    if (params.IsTiled()) {
+        ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
+                   params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
+        for (u32 level = 0; level < params.GetNumLevels(); ++level) {
+            u8* const buffer{GetStagingBufferLevelData(level)};
+            SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, buffer, level);
+        }
+    } else {
+        ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
+        const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
+        const u32 block_width{params.GetDefaultBlockWidth()};
+        const u32 block_height{params.GetDefaultBlockHeight()};
+        const u32 width{(params.GetWidth() + block_width - 1) / block_width};
+        const u32 height{(params.GetHeight() + block_height - 1) / block_height};
+        const u32 copy_size{width * bpp};
+        if (params.GetPitch() == copy_size) {
+            std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes());
+        } else {
+            const u8* start{host_ptr};
+            u8* write_to{staging_buffer.data()};
+            for (u32 h = height; h > 0; --h) {
+                std::memcpy(write_to, start, copy_size);
+                start += params.GetPitch();
+                write_to += copy_size;
+            }
+        }
+    }
+
+    for (u32 level = 0; level < params.GetNumLevels(); ++level) {
+        ConvertFromGuestToHost(GetStagingBufferLevelData(level), params.GetPixelFormat(),
+                               params.GetMipWidth(level), params.GetMipHeight(level),
+                               params.GetMipDepth(level), true, true);
+    }
+}
+
+void SurfaceBaseImpl::FlushBuffer() {
+    if (params.IsTiled()) {
+        ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
+                   params.GetBlockWidth());
+        for (u32 level = 0; level < params.GetNumLevels(); ++level) {
+            u8* const buffer = GetStagingBufferLevelData(level);
+            SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level);
+        }
+    } else {
+        UNIMPLEMENTED();
+        /*
+        ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
+        ASSERT(params.GetNumLevels() == 1);
+
+        const u32 bpp{params.GetFormatBpp() / 8};
+        const u32 copy_size{params.GetWidth() * bpp};
+        if (params.GetPitch() == copy_size) {
+            std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
+        } else {
+            u8* start{host_ptr};
+            const u8* read_to{staging_buffer.data()};
+            for (u32 h = params.GetHeight(); h > 0; --h) {
+                std::memcpy(start, read_to, copy_size);
+                start += params.GetPitch();
+                read_to += copy_size;
+            }
+        }
+        */
+    }
+}
+
 SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
                                               const Tegra::Texture::FullTextureInfo& config) {
     SurfaceParams params;

+ 94 - 67
src/video_core/texture_cache.h

@@ -273,37 +273,11 @@ struct hash<VideoCommon::ViewKey> {
 
 namespace VideoCommon {
 
-template <typename TTextureCache, typename TView, typename TExecutionContext>
-class SurfaceBase {
-    static_assert(std::is_trivially_copyable_v<TExecutionContext>);
-
+class SurfaceBaseImpl {
 public:
-    virtual void LoadBuffer() = 0;
-
-    virtual TExecutionContext FlushBuffer(TExecutionContext exctx) = 0;
-
-    virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
-
-    TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
-        if (view_addr < gpu_addr || !params.IsFamiliar(view_params)) {
-            // It can't be a view if it's in a prior address.
-            return {};
-        }
-
-        const auto relative_offset{static_cast<u64>(view_addr - gpu_addr)};
-        const auto it{view_offset_map.find(relative_offset)};
-        if (it == view_offset_map.end()) {
-            // Couldn't find an aligned view.
-            return {};
-        }
-        const auto [layer, level] = it->second;
-
-        if (!params.IsViewValid(view_params, layer, level)) {
-            return {};
-        }
+    void LoadBuffer();
 
-        return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
-    }
+    void FlushBuffer();
 
     GPUVAddr GetGpuAddr() const {
         ASSERT(is_registered);
@@ -325,27 +299,10 @@ public:
         return cache_addr;
     }
 
-    std::size_t GetSizeInBytes() const {
-        return params.GetGuestSizeInBytes();
-    }
-
-    void MarkAsModified(bool is_modified_) {
-        is_modified = is_modified_;
-        if (is_modified_) {
-            modification_tick = texture_cache.Tick();
-        }
-    }
-
     const SurfaceParams& GetSurfaceParams() const {
         return params;
     }
 
-    TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
-        TView* view{TryGetView(view_addr, view_params)};
-        ASSERT(view != nullptr);
-        return view;
-    }
-
     void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) {
         ASSERT(!is_registered);
         is_registered = true;
@@ -361,30 +318,95 @@ public:
         is_registered = false;
     }
 
-    u64 GetModificationTick() const {
-        return modification_tick;
-    }
-
     bool IsRegistered() const {
         return is_registered;
     }
 
-protected:
-    explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params)
-        : params{params}, texture_cache{texture_cache}, view_offset_map{
-                                                            params.CreateViewOffsetMap()} {}
+    std::size_t GetSizeInBytes() const {
+        return params.GetGuestSizeInBytes();
+    }
 
-    ~SurfaceBase() = default;
+    u8* GetStagingBufferLevelData(u32 level) {
+        return staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
+    }
+
+protected:
+    explicit SurfaceBaseImpl(const SurfaceParams& params);
+    ~SurfaceBaseImpl(); // non-virtual is intended
 
     virtual void DecorateSurfaceName() = 0;
 
-    virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
+    const SurfaceParams params;
+
+private:
+    GPUVAddr gpu_addr{};
+    VAddr cpu_addr{};
+    u8* host_ptr{};
+    CacheAddr cache_addr{};
+    bool is_registered{};
+
+    std::vector<u8> staging_buffer;
+};
+
+template <typename TTextureCache, typename TView, typename TExecutionContext>
+class SurfaceBase : public SurfaceBaseImpl {
+    static_assert(std::is_trivially_copyable_v<TExecutionContext>);
+
+public:
+    virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
+
+    virtual TExecutionContext DownloadTexture(TExecutionContext exctx) = 0;
+
+    TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
+        if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) {
+            // It can't be a view if it's in a prior address.
+            return {};
+        }
+
+        const auto relative_offset{static_cast<u64>(view_addr - GetGpuAddr())};
+        const auto it{view_offset_map.find(relative_offset)};
+        if (it == view_offset_map.end()) {
+            // Couldn't find an aligned view.
+            return {};
+        }
+        const auto [layer, level] = it->second;
+
+        if (!params.IsViewValid(view_params, layer, level)) {
+            return {};
+        }
+
+        return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
+    }
+
+    void MarkAsModified(bool is_modified_) {
+        is_modified = is_modified_;
+        if (is_modified_) {
+            modification_tick = texture_cache.Tick();
+        }
+    }
+
+    TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
+        TView* view{TryGetView(view_addr, view_params)};
+        ASSERT(view != nullptr);
+        return view;
+    }
 
     bool IsModified() const {
         return is_modified;
     }
 
-    const SurfaceParams params;
+    u64 GetModificationTick() const {
+        return modification_tick;
+    }
+
+protected:
+    explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params)
+        : SurfaceBaseImpl{params}, texture_cache{texture_cache},
+          view_offset_map{params.CreateViewOffsetMap()} {}
+
+    ~SurfaceBase() = default;
+
+    virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
 
 private:
     TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) {
@@ -400,13 +422,8 @@ private:
     TTextureCache& texture_cache;
     const std::map<u64, std::pair<u32, u32>> view_offset_map;
 
-    GPUVAddr gpu_addr{};
-    VAddr cpu_addr{};
-    u8* host_ptr{};
-    CacheAddr cache_addr{};
-    u64 modification_tick{};
     bool is_modified{};
-    bool is_registered{};
+    u64 modification_tick{};
     std::unordered_map<ViewKey, std::unique_ptr<TView>> views;
 };
 
@@ -560,7 +577,7 @@ private:
             if (!fast_view) {
                 // Flush even when we don't care about the contents, to preserve memory not
                 // written by the new surface.
-                exctx = surface->FlushBuffer(exctx);
+                exctx = FlushSurface(exctx, surface);
             }
             Unregister(surface);
         }
@@ -590,6 +607,16 @@ private:
         return exctx;
     }
 
+    TExecutionContext FlushSurface(TExecutionContext exctx,
+                                   const std::shared_ptr<TSurface>& surface) {
+        if (!surface->IsModified()) {
+            return exctx;
+        }
+        exctx = surface->DownloadTexture(exctx);
+        surface->FlushBuffer();
+        return exctx;
+    }
+
     std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr,
                                                                std::size_t size) const {
         if (size == 0) {
@@ -701,8 +728,8 @@ private:
 template <typename TTextureCache, typename TView>
 class SurfaceBaseContextless : public SurfaceBase<TTextureCache, TView, DummyExecutionContext> {
 public:
-    DummyExecutionContext FlushBuffer(DummyExecutionContext) {
-        FlushBufferImpl();
+    DummyExecutionContext DownloadTexture(DummyExecutionContext) {
+        DownloadTextureImpl();
         return {};
     }
 
@@ -715,7 +742,7 @@ protected:
     explicit SurfaceBaseContextless(TTextureCache& texture_cache, const SurfaceParams& params)
         : SurfaceBase<TTextureCache, TView, DummyExecutionContext>{texture_cache, params} {}
 
-    virtual void FlushBufferImpl() = 0;
+    virtual void DownloadTextureImpl() = 0;
 
     virtual void UploadTextureImpl() = 0;
 };