From 5f3aacdc3760f0e9e0daeda3ee4c55e42fc9397e Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 24 Apr 2019 02:45:03 -0300 Subject: [PATCH] texture_cache: Move staging buffer into a generic implementation --- .../renderer_opengl/gl_texture_cache.cpp | 114 +------------ .../renderer_opengl/gl_texture_cache.h | 7 +- src/video_core/texture_cache.cpp | 110 +++++++++++- src/video_core/texture_cache.h | 161 ++++++++++-------- 4 files changed, 211 insertions(+), 181 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 362f4019cf..3e2a1f53c7 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/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(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(params.GetMipWidth(level))); if (is_compressed) { - glGetCompressedTextureImage( - texture.handle, level, static_cast(params.GetHostMipmapSize(level)), - staging_buffer.data() + params.GetHostMipmapLevelOffset(level)); + glGetCompressedTextureImage(texture.handle, level, + static_cast(params.GetHostMipmapSize(level)), + GetStagingBufferLevelData(level)); } else { glGetTextureImage(texture.handle, level, format, type, static_cast(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(params.GetMipWidth(level))); - SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); }); + u8* buffer{GetStagingBufferLevelData(level)}; if (is_compressed) { const auto image_size{static_cast(params.GetHostMipmapSize(level))}; switch (params.GetTarget()) { diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index e6448c6f81..0a69be233e 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/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 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 staging_buffer; }; class CachedSurfaceView final { diff --git a/src/video_core/texture_cache.cpp b/src/video_core/texture_cache.cpp index b78a7d9511..146e8ed9bc 100644 --- a/src/video_core/texture_cache.cpp +++ b/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(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; diff --git a/src/video_core/texture_cache.h b/src/video_core/texture_cache.h index f22e8e776c..90c72cb15e 100644 --- a/src/video_core/texture_cache.h +++ b/src/video_core/texture_cache.h @@ -273,37 +273,11 @@ struct hash { namespace VideoCommon { -template -class SurfaceBase { - static_assert(std::is_trivially_copyable_v); - +class SurfaceBaseImpl { public: - virtual void LoadBuffer() = 0; + void LoadBuffer(); - 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(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 {}; - } - - 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 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 staging_buffer; +}; + +template +class SurfaceBase : public SurfaceBaseImpl { + static_assert(std::is_trivially_copyable_v); + +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(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 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> 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> 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& surface) { + if (!surface->IsModified()) { + return exctx; + } + exctx = surface->DownloadTexture(exctx); + surface->FlushBuffer(); + return exctx; + } + std::vector> GetSurfacesInRegion(CacheAddr cache_addr, std::size_t size) const { if (size == 0) { @@ -701,8 +728,8 @@ private: template class SurfaceBaseContextless : public SurfaceBase { public: - DummyExecutionContext FlushBuffer(DummyExecutionContext) { - FlushBufferImpl(); + DummyExecutionContext DownloadTexture(DummyExecutionContext) { + DownloadTextureImpl(); return {}; } @@ -715,7 +742,7 @@ protected: explicit SurfaceBaseContextless(TTextureCache& texture_cache, const SurfaceParams& params) : SurfaceBase{texture_cache, params} {} - virtual void FlushBufferImpl() = 0; + virtual void DownloadTextureImpl() = 0; virtual void UploadTextureImpl() = 0; };