From a14be972382a7fbb620e2fe0146a409637125d5d Mon Sep 17 00:00:00 2001 From: GPUCode Date: Mon, 13 Feb 2023 22:47:07 +0200 Subject: [PATCH] rasterizer_cache: Simplify SurfaceBase * The casts are bit ugly but will be refactored soon --- src/video_core/CMakeLists.txt | 1 + .../rasterizer_cache/rasterizer_cache.h | 5 +- .../rasterizer_cache/rasterizer_cache_base.h | 1 - .../rasterizer_cache/surface_base.cpp | 127 ++++++++++++++++ .../rasterizer_cache/surface_base.h | 143 ++---------------- .../renderer_opengl/gl_texture_runtime.cpp | 2 +- .../renderer_opengl/gl_texture_runtime.h | 4 +- .../renderer_vulkan/vk_texture_runtime.cpp | 7 +- .../renderer_vulkan/vk_texture_runtime.h | 5 +- 9 files changed, 147 insertions(+), 148 deletions(-) create mode 100644 src/video_core/rasterizer_cache/surface_base.cpp diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 483327b1f..773a5f325 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -37,6 +37,7 @@ add_library(video_core STATIC rasterizer_cache/sampler_params.h rasterizer_cache/slot_vector.h rasterizer_cache/surface_base.h + rasterizer_cache/surface_base.cpp rasterizer_cache/utils.cpp rasterizer_cache/utils.h rasterizer_cache/surface_params.cpp diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index 56481b1ce..84593f6fb 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -611,7 +611,8 @@ auto RasterizerCache::GetTextureSurface(const Pica::Texture::TextureInfo& inf } if (watcher && !watcher->IsValid()) { - auto level_surface = watcher->Get(); + auto level_surface = + std::static_pointer_cast(watcher->Get()); if (!level_surface->invalid_regions.empty()) { ValidateSurface(level_surface, level_surface->addr, level_surface->size); } @@ -684,7 +685,7 @@ auto RasterizerCache::GetTextureCube(const TextureCubeConfig& config) -> cons for (std::size_t i = 0; i < addresses.size(); i++) { const auto& watcher = watchers[i]; if (watcher && !watcher->IsValid()) { - auto face = watcher->Get(); + auto face = std::static_pointer_cast(watcher->Get()); if (!face->invalid_regions.empty()) { ValidateSurface(face, face->addr, face->size); } diff --git a/src/video_core/rasterizer_cache/rasterizer_cache_base.h b/src/video_core/rasterizer_cache/rasterizer_cache_base.h index e80995974..5167018dc 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache_base.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache_base.h @@ -47,7 +47,6 @@ class RasterizerCache : NonCopyable { using TextureRuntime = typename T::RuntimeType; using Sampler = typename T::Sampler; using Surface = std::shared_ptr; - using Watcher = SurfaceWatcher; /// Declare rasterizer interval types using SurfaceMap = boost::icl::interval_map= addr && + boost::icl::last_next(fill_interval) <= end && // dest_surface is within our fill range + dest_surface.FromInterval(fill_interval).GetInterval() == + fill_interval) { // make sure interval is a rectangle in dest surface + + if (fill_size * 8 != dest_surface.GetFormatBpp()) { + // Check if bits repeat for our fill_size + const u32 dest_bytes_per_pixel = std::max(dest_surface.GetFormatBpp() / 8, 1u); + std::vector fill_test(fill_size * dest_bytes_per_pixel); + + for (u32 i = 0; i < dest_bytes_per_pixel; ++i) + std::memcpy(&fill_test[i * fill_size], &fill_data[0], fill_size); + + for (u32 i = 0; i < fill_size; ++i) + if (std::memcmp(&fill_test[dest_bytes_per_pixel * i], &fill_test[0], + dest_bytes_per_pixel) != 0) + return false; + + if (dest_surface.GetFormatBpp() == 4 && (fill_test[0] & 0xF) != (fill_test[0] >> 4)) + return false; + } + return true; + } + return false; +} + +bool SurfaceBase::CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const { + SurfaceParams subrect_params = dest_surface.FromInterval(copy_interval); + ASSERT(subrect_params.GetInterval() == copy_interval); + if (CanSubRect(subrect_params)) + return true; + + if (CanFill(dest_surface, copy_interval)) + return true; + + return false; +} + +SurfaceInterval SurfaceBase::GetCopyableInterval(const SurfaceParams& params) const { + SurfaceInterval result{}; + const u32 tile_align = params.BytesInPixels(params.is_tiled ? 8 * 8 : 1); + const auto valid_regions = + SurfaceRegions{params.GetInterval() & GetInterval()} - invalid_regions; + + for (auto& valid_interval : valid_regions) { + const SurfaceInterval aligned_interval{ + params.addr + + Common::AlignUp(boost::icl::first(valid_interval) - params.addr, tile_align), + params.addr + + Common::AlignDown(boost::icl::last_next(valid_interval) - params.addr, tile_align)}; + + if (tile_align > boost::icl::length(valid_interval) || + boost::icl::length(aligned_interval) == 0) { + continue; + } + + // Get the rectangle within aligned_interval + const u32 stride_bytes = params.BytesInPixels(params.stride) * (params.is_tiled ? 8 : 1); + SurfaceInterval rect_interval{ + params.addr + + Common::AlignUp(boost::icl::first(aligned_interval) - params.addr, stride_bytes), + params.addr + Common::AlignDown(boost::icl::last_next(aligned_interval) - params.addr, + stride_bytes), + }; + + if (boost::icl::first(rect_interval) > boost::icl::last_next(rect_interval)) { + // 1 row + rect_interval = aligned_interval; + } else if (boost::icl::length(rect_interval) == 0) { + // 2 rows that do not make a rectangle, return the larger one + const SurfaceInterval row1{boost::icl::first(aligned_interval), + boost::icl::first(rect_interval)}; + const SurfaceInterval row2{boost::icl::first(rect_interval), + boost::icl::last_next(aligned_interval)}; + rect_interval = (boost::icl::length(row1) > boost::icl::length(row2)) ? row1 : row2; + } + + if (boost::icl::length(rect_interval) > boost::icl::length(result)) { + result = rect_interval; + } + } + return result; +} + +std::shared_ptr SurfaceBase::CreateWatcher() { + auto weak_ptr = weak_from_this(); + auto watcher = std::make_shared(std::move(weak_ptr)); + watchers.push_back(watcher); + return watcher; +} + +void SurfaceBase::InvalidateAllWatcher() { + for (const auto& watcher : watchers) { + if (auto locked = watcher.lock()) { + locked->valid = false; + } + } +} + +void SurfaceBase::UnlinkAllWatcher() { + for (const auto& watcher : watchers) { + if (auto locked = watcher.lock()) { + locked->valid = false; + locked->surface.reset(); + } + } + + watchers.clear(); +} + +} // namespace VideoCore diff --git a/src/video_core/rasterizer_cache/surface_base.h b/src/video_core/rasterizer_cache/surface_base.h index 059768d79..f98ed2ccd 100644 --- a/src/video_core/rasterizer_cache/surface_base.h +++ b/src/video_core/rasterizer_cache/surface_base.h @@ -5,22 +5,21 @@ #pragma once #include -#include "common/alignment.h" -#include "common/assert.h" #include "video_core/rasterizer_cache/surface_params.h" namespace VideoCore { using SurfaceRegions = boost::icl::interval_set; +class SurfaceBase; + /** * A watcher that notifies whether a cached surface has been changed. This is useful for caching * surface collection objects, including texture cube and mipmap. */ -template -class SurfaceWatcher { +class Watcher { public: - explicit SurfaceWatcher(std::weak_ptr&& surface) : surface(std::move(surface)) {} + explicit Watcher(std::weak_ptr&& surface) : surface(std::move(surface)) {} /// Checks whether the surface has been changed. bool IsValid() const { @@ -34,23 +33,19 @@ public: } /// Gets the referencing surface. Returns null if the surface has been destroyed - std::shared_ptr Get() const { + std::shared_ptr Get() const { return surface.lock(); } public: - std::weak_ptr surface; + std::weak_ptr surface; bool valid = false; }; -template -class SurfaceBase : public SurfaceParams, public std::enable_shared_from_this { - using Watcher = SurfaceWatcher; - +class SurfaceBase : public SurfaceParams, public std::enable_shared_from_this { public: - SurfaceBase() = default; - SurfaceBase(const SurfaceParams& params) : SurfaceParams{params} {} - virtual ~SurfaceBase() = default; + SurfaceBase(); + explicit SurfaceBase(const SurfaceParams& params); [[nodiscard]] bool Overlaps(PAddr overlap_addr, size_t overlap_size) const noexcept { const PAddr overlap_end = overlap_addr + static_cast(overlap_size); @@ -99,124 +94,4 @@ public: std::vector> watchers; }; -template -bool SurfaceBase::CanFill(const SurfaceParams& dest_surface, - SurfaceInterval fill_interval) const { - if (type == SurfaceType::Fill && IsRegionValid(fill_interval) && - boost::icl::first(fill_interval) >= addr && - boost::icl::last_next(fill_interval) <= end && // dest_surface is within our fill range - dest_surface.FromInterval(fill_interval).GetInterval() == - fill_interval) { // make sure interval is a rectangle in dest surface - - if (fill_size * 8 != dest_surface.GetFormatBpp()) { - // Check if bits repeat for our fill_size - const u32 dest_bytes_per_pixel = std::max(dest_surface.GetFormatBpp() / 8, 1u); - std::vector fill_test(fill_size * dest_bytes_per_pixel); - - for (u32 i = 0; i < dest_bytes_per_pixel; ++i) - std::memcpy(&fill_test[i * fill_size], &fill_data[0], fill_size); - - for (u32 i = 0; i < fill_size; ++i) - if (std::memcmp(&fill_test[dest_bytes_per_pixel * i], &fill_test[0], - dest_bytes_per_pixel) != 0) - return false; - - if (dest_surface.GetFormatBpp() == 4 && (fill_test[0] & 0xF) != (fill_test[0] >> 4)) - return false; - } - return true; - } - return false; -} - -template -bool SurfaceBase::CanCopy(const SurfaceParams& dest_surface, - SurfaceInterval copy_interval) const { - SurfaceParams subrect_params = dest_surface.FromInterval(copy_interval); - ASSERT(subrect_params.GetInterval() == copy_interval); - if (CanSubRect(subrect_params)) - return true; - - if (CanFill(dest_surface, copy_interval)) - return true; - - return false; -} - -template -SurfaceInterval SurfaceBase::GetCopyableInterval(const SurfaceParams& params) const { - SurfaceInterval result{}; - const u32 tile_align = params.BytesInPixels(params.is_tiled ? 8 * 8 : 1); - const auto valid_regions = - SurfaceRegions{params.GetInterval() & GetInterval()} - invalid_regions; - - for (auto& valid_interval : valid_regions) { - const SurfaceInterval aligned_interval{ - params.addr + - Common::AlignUp(boost::icl::first(valid_interval) - params.addr, tile_align), - params.addr + - Common::AlignDown(boost::icl::last_next(valid_interval) - params.addr, tile_align)}; - - if (tile_align > boost::icl::length(valid_interval) || - boost::icl::length(aligned_interval) == 0) { - continue; - } - - // Get the rectangle within aligned_interval - const u32 stride_bytes = params.BytesInPixels(params.stride) * (params.is_tiled ? 8 : 1); - SurfaceInterval rect_interval{ - params.addr + - Common::AlignUp(boost::icl::first(aligned_interval) - params.addr, stride_bytes), - params.addr + Common::AlignDown(boost::icl::last_next(aligned_interval) - params.addr, - stride_bytes), - }; - - if (boost::icl::first(rect_interval) > boost::icl::last_next(rect_interval)) { - // 1 row - rect_interval = aligned_interval; - } else if (boost::icl::length(rect_interval) == 0) { - // 2 rows that do not make a rectangle, return the larger one - const SurfaceInterval row1{boost::icl::first(aligned_interval), - boost::icl::first(rect_interval)}; - const SurfaceInterval row2{boost::icl::first(rect_interval), - boost::icl::last_next(aligned_interval)}; - rect_interval = (boost::icl::length(row1) > boost::icl::length(row2)) ? row1 : row2; - } - - if (boost::icl::length(rect_interval) > boost::icl::length(result)) { - result = rect_interval; - } - } - return result; -} - -template -auto SurfaceBase::CreateWatcher() -> std::shared_ptr { - auto weak_ptr = reinterpret_cast(this)->weak_from_this(); - auto watcher = std::make_shared(std::move(weak_ptr)); - watchers.push_back(watcher); - return watcher; -} - -template -void SurfaceBase::InvalidateAllWatcher() { - for (const auto& watcher : watchers) { - if (auto locked = watcher.lock()) { - locked->valid = false; - } - } -} - -template -void SurfaceBase::UnlinkAllWatcher() { - for (const auto& watcher : watchers) { - if (auto locked = watcher.lock()) { - locked->valid = false; - locked->surface.reset(); - } - } - - watchers.clear(); -} - } // namespace VideoCore diff --git a/src/video_core/renderer_opengl/gl_texture_runtime.cpp b/src/video_core/renderer_opengl/gl_texture_runtime.cpp index 35e88ad00..b143d3e9c 100644 --- a/src/video_core/renderer_opengl/gl_texture_runtime.cpp +++ b/src/video_core/renderer_opengl/gl_texture_runtime.cpp @@ -313,7 +313,7 @@ void TextureRuntime::BindFramebuffer(GLenum target, GLint level, GLenum textarge } Surface::Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime) - : VideoCore::SurfaceBase{params}, runtime{runtime}, driver{runtime.GetDriver()} { + : VideoCore::SurfaceBase{params}, runtime{runtime}, driver{runtime.GetDriver()} { if (pixel_format != VideoCore::PixelFormat::Invalid) { texture = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), levels, params.pixel_format, texture_type); diff --git a/src/video_core/renderer_opengl/gl_texture_runtime.h b/src/video_core/renderer_opengl/gl_texture_runtime.h index a13900fa1..e2c9a332f 100644 --- a/src/video_core/renderer_opengl/gl_texture_runtime.h +++ b/src/video_core/renderer_opengl/gl_texture_runtime.h @@ -99,10 +99,10 @@ private: OGLFramebuffer read_fbo, draw_fbo; }; -class Surface : public VideoCore::SurfaceBase { +class Surface : public VideoCore::SurfaceBase { public: Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime); - ~Surface() override; + ~Surface(); /// Returns the surface image handle GLuint Handle() const noexcept { diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp index 67533ef4a..5f75db61f 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp @@ -747,11 +747,8 @@ bool TextureRuntime::NeedsConvertion(VideoCore::PixelFormat format) const { traits.aspect != (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil); } -Surface::Surface(TextureRuntime& runtime) - : runtime{runtime}, instance{runtime.GetInstance()}, scheduler{runtime.GetScheduler()} {} - Surface::Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime) - : VideoCore::SurfaceBase{params}, runtime{runtime}, instance{runtime.GetInstance()}, + : VideoCore::SurfaceBase{params}, runtime{runtime}, instance{runtime.GetInstance()}, scheduler{runtime.GetScheduler()}, traits{instance.GetTraits(pixel_format)} { if (pixel_format != VideoCore::PixelFormat::Invalid) { @@ -762,7 +759,7 @@ Surface::Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime Surface::Surface(const VideoCore::SurfaceParams& params, vk::Format format, vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect, TextureRuntime& runtime) - : VideoCore::SurfaceBase{params}, runtime{runtime}, instance{runtime.GetInstance()}, + : VideoCore::SurfaceBase{params}, runtime{runtime}, instance{runtime.GetInstance()}, scheduler{runtime.GetScheduler()} { if (format != vk::Format::eUndefined) { alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), levels, pixel_format, diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.h b/src/video_core/renderer_vulkan/vk_texture_runtime.h index e62c0a981..226c655cf 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.h +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.h @@ -163,15 +163,14 @@ private: std::unordered_multimap texture_recycler; }; -class Surface : public VideoCore::SurfaceBase { +class Surface : public VideoCore::SurfaceBase { friend class TextureRuntime; public: - Surface(TextureRuntime& runtime); Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime); Surface(const VideoCore::SurfaceParams& params, vk::Format format, vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect, TextureRuntime& runtime); - ~Surface() override; + ~Surface(); /// Returns the surface aspect vk::ImageAspectFlags Aspect() const noexcept {