Просмотр исходного кода

gl_texture_cache: Add copy from multiple overlaps into a single surface

ReinUsesLisp 7 лет назад
Родитель
Сommit
0cefb7bcb4

+ 50 - 4
src/video_core/renderer_opengl/gl_texture_cache.cpp

@@ -518,16 +518,14 @@ TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
 TextureCacheOpenGL::~TextureCacheOpenGL() = default;
 
 CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView(
-    VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, bool preserve_contents,
+    VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params, bool preserve_contents,
     const std::vector<CachedSurface*>& overlaps) {
     if (overlaps.size() > 1) {
-        return nullptr;
+        return TryCopyAsViews(cpu_addr, host_ptr, new_params, overlaps);
     }
 
     const auto& old_surface{overlaps[0]};
     const auto& old_params{old_surface->GetSurfaceParams()};
-    const auto& new_params{params};
-
     if (old_params.GetTarget() == new_params.GetTarget() &&
         old_params.GetDepth() == new_params.GetDepth() && old_params.GetDepth() == 1 &&
         old_params.GetNumLevels() == new_params.GetNumLevels() &&
@@ -567,6 +565,54 @@ CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(VAddr cpu_addr, u8* host_ptr,
     return new_surface->GetView(cpu_addr, new_params);
 }
 
+CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(VAddr cpu_addr, u8* host_ptr,
+                                                      const SurfaceParams& new_params,
+                                                      const std::vector<CachedSurface*>& overlaps) {
+    if (new_params.GetTarget() == SurfaceTarget::Texture1D ||
+        new_params.GetTarget() == SurfaceTarget::Texture1DArray ||
+        new_params.GetTarget() == SurfaceTarget::Texture3D) {
+        // Non-2D textures are not handled at the moment in this fast path.
+        return nullptr;
+    }
+
+    CachedSurface* const new_surface{GetUncachedSurface(new_params)};
+    // TODO(Rodrigo): Move this down
+    Register(new_surface, cpu_addr, host_ptr);
+
+    // TODO(Rodrigo): Find a way to avoid heap allocations here.
+    std::vector<CachedSurfaceView*> views;
+    views.reserve(overlaps.size());
+    for (const auto& overlap : overlaps) {
+        const auto view{
+            new_surface->TryGetView(overlap->GetCpuAddr(), overlap->GetSurfaceParams())};
+        if (!view) {
+            // TODO(Rodrigo): Remove this
+            Unregister(new_surface);
+            return nullptr;
+        }
+        views.push_back(view);
+    }
+
+    // TODO(Rodrigo): It's possible that these method leaves some unloaded textures if the data has
+    // been uploaded to guest memory but not used as a surface previously.
+    for (std::size_t i = 0; i < overlaps.size(); ++i) {
+        const auto& overlap{overlaps[i]};
+        const auto& view{views[i]};
+        for (u32 overlap_level = 0; overlap_level < view->GetNumLevels(); ++overlap_level) {
+            const u32 super_level{view->GetBaseLevel() + overlap_level};
+            glCopyImageSubData(overlap->GetTexture(), overlap->GetTarget(), overlap_level, 0, 0, 0,
+                               new_surface->GetTexture(), new_surface->GetTarget(), super_level, 0,
+                               0, view->GetBaseLayer(), view->GetWidth(), view->GetHeight(),
+                               view->GetNumLayers());
+        }
+    }
+
+    new_surface->MarkAsModified(true);
+
+    // TODO(Rodrigo): Add an entry to directly get the superview
+    return new_surface->GetView(cpu_addr, new_params);
+}
+
 std::unique_ptr<CachedSurface> TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) {
     return std::make_unique<CachedSurface>(params);
 }

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

@@ -90,6 +90,34 @@ public:
         return params;
     }
 
+    u32 GetWidth() const {
+        return params.GetMipWidth(GetBaseLevel());
+    }
+
+    u32 GetHeight() const {
+        return params.GetMipHeight(GetBaseLevel());
+    }
+
+    u32 GetDepth() const {
+        return params.GetMipDepth(GetBaseLevel());
+    }
+
+    u32 GetBaseLayer() const {
+        return key.base_layer;
+    }
+
+    u32 GetNumLayers() const {
+        return key.num_layers;
+    }
+
+    u32 GetBaseLevel() const {
+        return key.base_level;
+    }
+
+    u32 GetNumLevels() const {
+        return key.num_levels;
+    }
+
 private:
     struct TextureView {
         OGLTexture texture;
@@ -128,7 +156,8 @@ public:
 
 protected:
     CachedSurfaceView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr,
-                                             const SurfaceParams& params, bool preserve_contents,
+                                             const SurfaceParams& new_params,
+                                             bool preserve_contents,
                                              const std::vector<CachedSurface*>& overlaps);
 
     std::unique_ptr<CachedSurface> CreateSurface(const SurfaceParams& params);
@@ -136,6 +165,9 @@ protected:
 private:
     CachedSurfaceView* SurfaceCopy(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params,
                                    CachedSurface* old_surface, const SurfaceParams& old_params);
+
+    CachedSurfaceView* TryCopyAsViews(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params,
+                                      const std::vector<CachedSurface*>& overlaps);
 };
 
 } // namespace OpenGL

+ 1 - 1
src/video_core/texture_cache.cpp

@@ -316,7 +316,7 @@ std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only
         size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed);
     }
     if (is_tiled && !as_host_size) {
-        //size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
+        size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
     }
     return size;
 }