diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index cd819d69f..06fc59dbe 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -5,6 +5,7 @@ #pragma once #include "common/common_types.h" +#include "video_core/engines/fermi_2d.h" #include "video_core/gpu.h" #include "video_core/memory_manager.h" @@ -33,13 +34,9 @@ public: /// and invalidated virtual void FlushAndInvalidateRegion(VAddr addr, u64 size) = 0; - /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0 - virtual bool AccelerateDisplayTransfer(const void* config) { - return false; - } - - /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 1 - virtual bool AccelerateTextureCopy(const void* config) { + /// Attempt to use a faster method to perform a surface copy + virtual bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, + const Tegra::Engines::Fermi2D::Regs::Surface& dst) { return false; } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 60dcdc184..a3a14efd9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -616,14 +616,10 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) { InvalidateRegion(addr, size); } -bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { +bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, + const Tegra::Engines::Fermi2D::Regs::Surface& dst) { MICROPROFILE_SCOPE(OpenGL_Blits); - UNREACHABLE(); - return true; -} - -bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { - UNREACHABLE(); + res_cache.FermiCopySurface(src, dst); return true; } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index bf954bb5d..8b6b62241 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -52,8 +52,8 @@ public: void FlushRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override; void FlushAndInvalidateRegion(VAddr addr, u64 size) override; - bool AccelerateDisplayTransfer(const void* config) override; - bool AccelerateTextureCopy(const void* config) override; + bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, + const Tegra::Engines::Fermi2D::Regs::Surface& dst) override; bool AccelerateFill(const void* config) override; bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride) override; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 5fe6befe1..56ff83eff 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -143,6 +143,28 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { return params; } +/*static*/ SurfaceParams SurfaceParams::CreateForFermiCopySurface( + const Tegra::Engines::Fermi2D::Regs::Surface& config) { + SurfaceParams params{}; + params.addr = TryGetCpuAddr(config.Address()); + params.is_tiled = !config.linear; + params.block_height = params.is_tiled ? config.BlockHeight() : 0, + params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); + params.component_type = ComponentTypeFromRenderTarget(config.format); + params.type = GetFormatType(params.pixel_format); + params.width = config.width; + params.height = config.height; + params.unaligned_height = config.height; + params.target = SurfaceTarget::Texture2D; + params.depth = 1; + params.size_in_bytes_total = params.SizeInBytesTotal(); + params.size_in_bytes_2d = params.SizeInBytes2D(); + params.max_mip_level = 0; + params.rt = {}; + + return params; +} + static constexpr std::array tex_format_tuples = {{ {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S @@ -1045,6 +1067,26 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) { return surface; } +void RasterizerCacheOpenGL::FermiCopySurface( + const Tegra::Engines::Fermi2D::Regs::Surface& src_config, + const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) { + + const auto& src_params = SurfaceParams::CreateForFermiCopySurface(src_config); + const auto& dst_params = SurfaceParams::CreateForFermiCopySurface(dst_config); + + ASSERT(src_params.width == dst_params.width); + ASSERT(src_params.height == dst_params.height); + ASSERT(src_params.pixel_format == dst_params.pixel_format); + ASSERT(src_params.block_height == dst_params.block_height); + ASSERT(src_params.is_tiled == dst_params.is_tiled); + ASSERT(src_params.depth == dst_params.depth); + ASSERT(src_params.depth == 1); // Currently, FastCopySurface only works with 2D surfaces + ASSERT(src_params.target == dst_params.target); + ASSERT(src_params.rt.index == dst_params.rt.index); + + FastCopySurface(GetSurface(src_params, true), GetSurface(dst_params, false)); +} + Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, const SurfaceParams& new_params) { // Verify surface is compatible for blitting diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 49025a3fe..0b4940b3c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -13,6 +13,7 @@ #include "common/common_types.h" #include "common/hash.h" #include "common/math_util.h" +#include "video_core/engines/fermi_2d.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/rasterizer_cache.h" #include "video_core/renderer_opengl/gl_resource_manager.h" @@ -719,6 +720,10 @@ struct SurfaceParams { Tegra::GPUVAddr zeta_address, Tegra::DepthFormat format); + /// Creates SurfaceParams for a Fermi2D surface copy + static SurfaceParams CreateForFermiCopySurface( + const Tegra::Engines::Fermi2D::Regs::Surface& config); + /// Checks if surfaces are compatible for caching bool IsCompatibleSurface(const SurfaceParams& other) const { return std::tie(pixel_format, type, width, height, target, depth) == @@ -837,6 +842,10 @@ public: /// Tries to find a framebuffer using on the provided CPU address Surface TryFindFramebufferSurface(VAddr addr) const; + /// Copies the contents of one surface to another + void FermiCopySurface(const Tegra::Engines::Fermi2D::Regs::Surface& src_config, + const Tegra::Engines::Fermi2D::Regs::Surface& dst_config); + private: void LoadSurface(const Surface& surface); Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true);