From fb94871791f78703737125cd2e5a13db8b7d1059 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 14 Apr 2019 01:44:16 -0300 Subject: [PATCH] gl_texture_cache: Add fast copy path --- .../renderer_opengl/gl_texture_cache.cpp | 51 +++++++++++++++++-- .../renderer_opengl/gl_texture_cache.h | 9 ++++ src/video_core/texture_cache.cpp | 4 +- src/video_core/textures/decoders.cpp | 3 +- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 3a456995e4..00f9ab92f2 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -177,9 +177,9 @@ void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { } } -OGLTexture CreateTexture(const SurfaceParams& params, GLenum internal_format) { +OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum internal_format) { OGLTexture texture; - texture.Create(GetTextureTarget(params)); + texture.Create(target); switch (params.GetTarget()) { case SurfaceTarget::Texture1D: @@ -241,7 +241,8 @@ CachedSurface::CachedSurface(const SurfaceParams& params) format = tuple.format; type = tuple.type; is_compressed = tuple.compressed; - texture = CreateTexture(params, internal_format); + target = GetTextureTarget(params); + texture = CreateTexture(params, target, internal_format); staging_buffer.resize(params.GetHostSizeInBytes()); } @@ -504,9 +505,53 @@ TextureCacheOpenGL::~TextureCacheOpenGL() = default; CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView( VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, bool preserve_contents, const std::vector& overlaps) { + if (overlaps.size() > 1) { + return nullptr; + } + + 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() && + old_params.GetPixelFormat() == new_params.GetPixelFormat()) { + return SurfaceCopy(cpu_addr, host_ptr, new_params, old_surface, old_params); + } + return nullptr; } +CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(VAddr cpu_addr, u8* host_ptr, + const SurfaceParams& new_params, + CachedSurface* old_surface, + const SurfaceParams& old_params) { + CachedSurface* const new_surface{GetUncachedSurface(new_params)}; + Register(new_surface, cpu_addr, host_ptr); + + const u32 min_width{ + std::max(old_params.GetDefaultBlockWidth(), new_params.GetDefaultBlockWidth())}; + const u32 min_height{ + std::max(old_params.GetDefaultBlockHeight(), new_params.GetDefaultBlockHeight())}; + for (u32 level = 0; level < old_params.GetNumLevels(); ++level) { + const u32 width{std::min(old_params.GetMipWidth(level), new_params.GetMipWidth(level))}; + const u32 height{std::min(old_params.GetMipHeight(level), new_params.GetMipHeight(level))}; + if (width < min_width || height < min_height) { + // Avoid copies that are too small to be handled in OpenGL + break; + } + glCopyImageSubData(old_surface->GetTexture(), old_surface->GetTarget(), level, 0, 0, 0, + new_surface->GetTexture(), new_surface->GetTarget(), level, 0, 0, 0, + width, height, 1); + } + + 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 TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) { return std::make_unique(params); } diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index f0a524882a..b18b32d999 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -38,6 +38,10 @@ public: void LoadBuffer(); + GLenum GetTarget() const { + return target; + } + GLuint GetTexture() const { return texture.handle; } @@ -56,6 +60,7 @@ private: GLenum format{}; GLenum type{}; bool is_compressed{}; + GLenum target{}; OGLTexture texture; @@ -126,6 +131,10 @@ protected: const std::vector& overlaps); std::unique_ptr CreateSurface(const SurfaceParams& params); + +private: + CachedSurfaceView* SurfaceCopy(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params, + CachedSurface* old_surface, const SurfaceParams& old_params); }; } // namespace OpenGL diff --git a/src/video_core/texture_cache.cpp b/src/video_core/texture_cache.cpp index c42365a82f..1cfb9962fa 100644 --- a/src/video_core/texture_cache.cpp +++ b/src/video_core/texture_cache.cpp @@ -160,7 +160,7 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const { // Auto block resizing algorithm from: // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c if (level == 0) { - return block_height; + return this->block_height; } const u32 height{GetMipHeight(level)}; const u32 default_block_height{GetDefaultBlockHeight()}; @@ -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; } diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 664ed4b566..2178053865 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -359,8 +359,7 @@ std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x); const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height); const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth); - const u32 size = aligned_width * aligned_height * aligned_depth; - return size; + return aligned_width * aligned_height * aligned_depth; } else { return width * height * depth * bytes_per_pixel; }