diff options
-rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.cpp | 54 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.h | 34 | ||||
-rw-r--r-- | src/video_core/texture_cache.cpp | 2 |
3 files changed, 84 insertions, 6 deletions
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index ba6d3af4b..6a6fe7cc4 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/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); } diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 80733ac36..86ad91dab 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/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 diff --git a/src/video_core/texture_cache.cpp b/src/video_core/texture_cache.cpp index 1cfb9962f..2994312f4 100644 --- a/src/video_core/texture_cache.cpp +++ b/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; } |