diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index 842b4010c..363642a79 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -37,6 +37,172 @@ RasterizerCache::~RasterizerCache() { #endif } +template +bool RasterizerCache::AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) { + u32 copy_size = Common::AlignDown(config.texture_copy.size, 16); + if (copy_size == 0) { + return false; + } + + u32 input_gap = config.texture_copy.input_gap * 16; + u32 input_width = config.texture_copy.input_width * 16; + if (input_width == 0 && input_gap != 0) { + return false; + } + if (input_gap == 0 || input_width >= copy_size) { + input_width = copy_size; + input_gap = 0; + } + if (copy_size % input_width != 0) { + return false; + } + + u32 output_gap = config.texture_copy.output_gap * 16; + u32 output_width = config.texture_copy.output_width * 16; + if (output_width == 0 && output_gap != 0) { + return false; + } + if (output_gap == 0 || output_width >= copy_size) { + output_width = copy_size; + output_gap = 0; + } + if (copy_size % output_width != 0) { + return false; + } + + SurfaceParams src_params; + src_params.addr = config.GetPhysicalInputAddress(); + src_params.stride = input_width + input_gap; // stride in bytes + src_params.width = input_width; // width in bytes + src_params.height = copy_size / input_width; + src_params.size = ((src_params.height - 1) * src_params.stride) + src_params.width; + src_params.end = src_params.addr + src_params.size; + + auto [src_surface, src_rect] = GetTexCopySurface(src_params); + if (src_surface == nullptr) { + return false; + } + + if (output_gap != 0 && + (output_width != src_surface->BytesInPixels(src_rect.GetWidth() / src_surface->res_scale) * + (src_surface->is_tiled ? 8 : 1) || + output_gap % src_surface->BytesInPixels(src_surface->is_tiled ? 64 : 1) != 0)) { + return false; + } + + SurfaceParams dst_params = *src_surface; + dst_params.addr = config.GetPhysicalOutputAddress(); + dst_params.width = src_rect.GetWidth() / src_surface->res_scale; + dst_params.stride = dst_params.width + src_surface->PixelsInBytes( + src_surface->is_tiled ? output_gap / 8 : output_gap); + dst_params.height = src_rect.GetHeight() / src_surface->res_scale; + dst_params.res_scale = src_surface->res_scale; + dst_params.UpdateParams(); + + // Since we are going to invalidate the gap if there is one, we will have to load it first + const bool load_gap = output_gap != 0; + auto [dst_surface, dst_rect] = GetSurfaceSubRect(dst_params, ScaleMatch::Upscale, load_gap); + + if (!dst_surface || dst_surface->type == SurfaceType::Texture || + !CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { + return false; + } + + ASSERT(src_rect.GetWidth() == dst_rect.GetWidth()); + + const TextureCopy texture_copy = { + .src_level = 0, + .dst_level = 0, + .src_offset = {src_rect.left, src_rect.bottom}, + .dst_offset = {dst_rect.left, dst_rect.bottom}, + .extent = {src_rect.GetWidth(), src_rect.GetHeight()}, + }; + runtime.CopyTextures(*src_surface, *dst_surface, texture_copy); + + InvalidateRegion(dst_params.addr, dst_params.size, dst_surface); + return true; +} + +template +bool RasterizerCache::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) { + SurfaceParams src_params; + src_params.addr = config.GetPhysicalInputAddress(); + src_params.width = config.output_width; + src_params.stride = config.input_width; + src_params.height = config.output_height; + src_params.is_tiled = !config.input_linear; + src_params.pixel_format = PixelFormatFromGPUPixelFormat(config.input_format); + src_params.UpdateParams(); + + SurfaceParams dst_params; + dst_params.addr = config.GetPhysicalOutputAddress(); + dst_params.width = config.scaling != config.NoScale ? config.output_width.Value() / 2 + : config.output_width.Value(); + dst_params.height = config.scaling == config.ScaleXY ? config.output_height.Value() / 2 + : config.output_height.Value(); + dst_params.is_tiled = config.input_linear != config.dont_swizzle; + dst_params.pixel_format = PixelFormatFromGPUPixelFormat(config.output_format); + dst_params.UpdateParams(); + + auto [src_surface, src_rect] = GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true); + if (src_surface == nullptr) + return false; + + dst_params.res_scale = src_surface->res_scale; + + auto [dst_surface, dst_rect] = GetSurfaceSubRect(dst_params, ScaleMatch::Upscale, false); + if (dst_surface == nullptr) { + return false; + } + + if (src_surface->is_tiled != dst_surface->is_tiled) { + std::swap(src_rect.top, src_rect.bottom); + } + if (config.flip_vertically) { + std::swap(src_rect.top, src_rect.bottom); + } + + if (!CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { + return false; + } + + const TextureBlit texture_blit = { + .src_level = 0, + .dst_level = 0, + .src_rect = src_rect, + .dst_rect = dst_rect, + }; + runtime.BlitTextures(*src_surface, *dst_surface, texture_blit); + + InvalidateRegion(dst_params.addr, dst_params.size, dst_surface); + return true; +} + +template +bool RasterizerCache::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) { + SurfaceParams params; + params.addr = config.GetStartAddress(); + params.end = config.GetEndAddress(); + params.size = params.end - params.addr; + params.type = SurfaceType::Fill; + params.res_scale = std::numeric_limits::max(); + + Surface fill_surface = std::make_shared(params, runtime); + + std::memcpy(&fill_surface->fill_data[0], &config.value_32bit, 4); + if (config.fill_32bit) { + fill_surface->fill_size = 4; + } else if (config.fill_24bit) { + fill_surface->fill_size = 3; + } else { + fill_surface->fill_size = 2; + } + + RegisterSurface(fill_surface); + InvalidateRegion(fill_surface->addr, fill_surface->size, fill_surface); + return true; +} + template template void RasterizerCache::ForEachSurfaceInRegion(PAddr addr, size_t size, Func&& func) { @@ -635,30 +801,6 @@ auto RasterizerCache::GetFramebufferSurfaces(bool using_color_fb, bool using_ return std::make_tuple(color_surface, depth_surface, fb_rect); } -template -auto RasterizerCache::GetFillSurface(const GPU::Regs::MemoryFillConfig& config) -> Surface { - SurfaceParams params; - params.addr = config.GetStartAddress(); - params.end = config.GetEndAddress(); - params.size = params.end - params.addr; - params.type = SurfaceType::Fill; - params.res_scale = std::numeric_limits::max(); - - Surface new_surface = std::make_shared(params, runtime); - - std::memcpy(&new_surface->fill_data[0], &config.value_32bit, 4); - if (config.fill_32bit) { - new_surface->fill_size = 4; - } else if (config.fill_24bit) { - new_surface->fill_size = 3; - } else { - new_surface->fill_size = 2; - } - - RegisterSurface(new_surface); - return new_surface; -} - template auto RasterizerCache::GetTexCopySurface(const SurfaceParams& params) -> SurfaceRect_Tuple { Common::Rectangle rect{}; diff --git a/src/video_core/rasterizer_cache/rasterizer_cache_base.h b/src/video_core/rasterizer_cache/rasterizer_cache_base.h index b140a2a72..6ea4983bd 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache_base.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache_base.h @@ -60,6 +60,15 @@ public: RasterizerCache(Memory::MemorySystem& memory, TextureRuntime& runtime); ~RasterizerCache(); + /// Perform hardware accelerated texture copy according to the provided configuration + bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config); + + /// Perform hardware accelerated display transfer according to the provided configuration + bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config); + + /// Perform hardware accelerated memory fill according to the provided configuration + bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config); + /// Blit one surface's texture to another bool BlitSurfaces(const Surface& src_surface, Common::Rectangle src_rect, const Surface& dst_surface, Common::Rectangle dst_rect); @@ -88,9 +97,6 @@ public: SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, const Common::Rectangle& viewport_rect); - /// Get a surface that matches the fill config - Surface GetFillSurface(const GPU::Regs::MemoryFillConfig& config); - /// Get a surface that matches a "texture copy" display transfer config SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index fedb1984b..587fd17a3 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -775,140 +775,15 @@ void RasterizerOpenGL::ClearAll(bool flush) { MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) { MICROPROFILE_SCOPE(OpenGL_Blits); - - VideoCore::SurfaceParams src_params; - src_params.addr = config.GetPhysicalInputAddress(); - src_params.width = config.output_width; - src_params.stride = config.input_width; - src_params.height = config.output_height; - src_params.is_tiled = !config.input_linear; - src_params.pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(config.input_format); - src_params.UpdateParams(); - - VideoCore::SurfaceParams dst_params; - dst_params.addr = config.GetPhysicalOutputAddress(); - dst_params.width = config.scaling != config.NoScale ? config.output_width.Value() / 2 - : config.output_width.Value(); - dst_params.height = config.scaling == config.ScaleXY ? config.output_height.Value() / 2 - : config.output_height.Value(); - dst_params.is_tiled = config.input_linear != config.dont_swizzle; - dst_params.pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(config.output_format); - dst_params.UpdateParams(); - - auto [src_surface, src_rect] = - res_cache.GetSurfaceSubRect(src_params, VideoCore::ScaleMatch::Ignore, true); - if (src_surface == nullptr) - return false; - - dst_params.res_scale = src_surface->res_scale; - - auto [dst_surface, dst_rect] = - res_cache.GetSurfaceSubRect(dst_params, VideoCore::ScaleMatch::Upscale, false); - if (dst_surface == nullptr) { - return false; - } - - if (src_surface->is_tiled != dst_surface->is_tiled) - std::swap(src_rect.top, src_rect.bottom); - - if (config.flip_vertically) - std::swap(src_rect.top, src_rect.bottom); - - if (!res_cache.BlitSurfaces(src_surface, src_rect, dst_surface, dst_rect)) - return false; - - res_cache.InvalidateRegion(dst_params.addr, dst_params.size, dst_surface); - return true; + return res_cache.AccelerateDisplayTransfer(config); } bool RasterizerOpenGL::AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) { - u32 copy_size = Common::AlignDown(config.texture_copy.size, 16); - if (copy_size == 0) { - return false; - } - - u32 input_gap = config.texture_copy.input_gap * 16; - u32 input_width = config.texture_copy.input_width * 16; - if (input_width == 0 && input_gap != 0) { - return false; - } - if (input_gap == 0 || input_width >= copy_size) { - input_width = copy_size; - input_gap = 0; - } - if (copy_size % input_width != 0) { - return false; - } - - u32 output_gap = config.texture_copy.output_gap * 16; - u32 output_width = config.texture_copy.output_width * 16; - if (output_width == 0 && output_gap != 0) { - return false; - } - if (output_gap == 0 || output_width >= copy_size) { - output_width = copy_size; - output_gap = 0; - } - if (copy_size % output_width != 0) { - return false; - } - - VideoCore::SurfaceParams src_params; - src_params.addr = config.GetPhysicalInputAddress(); - src_params.stride = input_width + input_gap; // stride in bytes - src_params.width = input_width; // width in bytes - src_params.height = copy_size / input_width; - src_params.size = ((src_params.height - 1) * src_params.stride) + src_params.width; - src_params.end = src_params.addr + src_params.size; - - auto [src_surface, src_rect] = res_cache.GetTexCopySurface(src_params); - if (src_surface == nullptr) { - return false; - } - - if (output_gap != 0 && - (output_width != src_surface->BytesInPixels(src_rect.GetWidth() / src_surface->res_scale) * - (src_surface->is_tiled ? 8 : 1) || - output_gap % src_surface->BytesInPixels(src_surface->is_tiled ? 64 : 1) != 0)) { - return false; - } - - VideoCore::SurfaceParams dst_params = *src_surface; - dst_params.addr = config.GetPhysicalOutputAddress(); - dst_params.width = src_rect.GetWidth() / src_surface->res_scale; - dst_params.stride = dst_params.width + src_surface->PixelsInBytes( - src_surface->is_tiled ? output_gap / 8 : output_gap); - dst_params.height = src_rect.GetHeight() / src_surface->res_scale; - dst_params.res_scale = src_surface->res_scale; - dst_params.UpdateParams(); - - // Since we are going to invalidate the gap if there is one, we will have to load it first - const bool load_gap = output_gap != 0; - auto [dst_surface, dst_rect] = - res_cache.GetSurfaceSubRect(dst_params, VideoCore::ScaleMatch::Upscale, load_gap); - if (dst_surface == nullptr) { - return false; - } - - if (dst_surface->type == VideoCore::SurfaceType::Texture) { - return false; - } - - if (!res_cache.BlitSurfaces(src_surface, src_rect, dst_surface, dst_rect)) { - return false; - } - - res_cache.InvalidateRegion(dst_params.addr, dst_params.size, dst_surface); - return true; + return res_cache.AccelerateTextureCopy(config); } bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) { - auto dst_surface = res_cache.GetFillSurface(config); - if (dst_surface == nullptr) - return false; - - res_cache.InvalidateRegion(dst_surface->addr, dst_surface->size, dst_surface); - return true; + return res_cache.AccelerateFill(config); } bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 512d75470..66b94d530 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -817,134 +817,15 @@ void RasterizerVulkan::ClearAll(bool flush) { bool RasterizerVulkan::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) { MICROPROFILE_SCOPE(Vulkan_Blits); - - VideoCore::SurfaceParams src_params; - src_params.addr = config.GetPhysicalInputAddress(); - src_params.width = config.output_width; - src_params.stride = config.input_width; - src_params.height = config.output_height; - src_params.is_tiled = !config.input_linear; - src_params.pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(config.input_format); - src_params.UpdateParams(); - - VideoCore::SurfaceParams dst_params; - dst_params.addr = config.GetPhysicalOutputAddress(); - dst_params.width = config.scaling != config.NoScale ? config.output_width.Value() / 2 - : config.output_width.Value(); - dst_params.height = config.scaling == config.ScaleXY ? config.output_height.Value() / 2 - : config.output_height.Value(); - dst_params.is_tiled = config.input_linear != config.dont_swizzle; - dst_params.pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(config.output_format); - dst_params.UpdateParams(); - - auto [src_surface, src_rect] = - res_cache.GetSurfaceSubRect(src_params, VideoCore::ScaleMatch::Ignore, true); - if (src_surface == nullptr) - return false; - - dst_params.res_scale = src_surface->res_scale; - - auto [dst_surface, dst_rect] = - res_cache.GetSurfaceSubRect(dst_params, VideoCore::ScaleMatch::Upscale, false); - if (dst_surface == nullptr) { - return false; - } - - if (src_surface->is_tiled != dst_surface->is_tiled) - std::swap(src_rect.top, src_rect.bottom); - - if (config.flip_vertically) - std::swap(src_rect.top, src_rect.bottom); - - if (!res_cache.BlitSurfaces(src_surface, src_rect, dst_surface, dst_rect)) - return false; - - res_cache.InvalidateRegion(dst_params.addr, dst_params.size, dst_surface); - return true; + return res_cache.AccelerateDisplayTransfer(config); } bool RasterizerVulkan::AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) { - u32 copy_size = Common::AlignDown(config.texture_copy.size, 16); - if (copy_size == 0) { - return false; - } - - u32 input_gap = config.texture_copy.input_gap * 16; - u32 input_width = config.texture_copy.input_width * 16; - if (input_width == 0 && input_gap != 0) { - return false; - } - if (input_gap == 0 || input_width >= copy_size) { - input_width = copy_size; - input_gap = 0; - } - if (copy_size % input_width != 0) { - return false; - } - - u32 output_gap = config.texture_copy.output_gap * 16; - u32 output_width = config.texture_copy.output_width * 16; - if (output_width == 0 && output_gap != 0) { - return false; - } - if (output_gap == 0 || output_width >= copy_size) { - output_width = copy_size; - output_gap = 0; - } - if (copy_size % output_width != 0) { - return false; - } - - VideoCore::SurfaceParams src_params; - src_params.addr = config.GetPhysicalInputAddress(); - src_params.stride = input_width + input_gap; // stride in bytes - src_params.width = input_width; // width in bytes - src_params.height = copy_size / input_width; - src_params.size = ((src_params.height - 1) * src_params.stride) + src_params.width; - src_params.end = src_params.addr + src_params.size; - - auto [src_surface, src_rect] = res_cache.GetTexCopySurface(src_params); - if (src_surface == nullptr) { - return false; - } - - if (output_gap != 0 && - (output_width != src_surface->BytesInPixels(src_rect.GetWidth() / src_surface->res_scale) * - (src_surface->is_tiled ? 8 : 1) || - output_gap % src_surface->BytesInPixels(src_surface->is_tiled ? 64 : 1) != 0)) { - return false; - } - - VideoCore::SurfaceParams dst_params = *src_surface; - dst_params.addr = config.GetPhysicalOutputAddress(); - dst_params.width = src_rect.GetWidth() / src_surface->res_scale; - dst_params.stride = dst_params.width + src_surface->PixelsInBytes( - src_surface->is_tiled ? output_gap / 8 : output_gap); - dst_params.height = src_rect.GetHeight() / src_surface->res_scale; - dst_params.res_scale = src_surface->res_scale; - dst_params.UpdateParams(); - - // Since we are going to invalidate the gap if there is one, we will have to load it first - const bool load_gap = output_gap != 0; - auto [dst_surface, dst_rect] = - res_cache.GetSurfaceSubRect(dst_params, VideoCore::ScaleMatch::Upscale, load_gap); - - if (!dst_surface || dst_surface->type == VideoCore::SurfaceType::Texture || - !res_cache.BlitSurfaces(src_surface, src_rect, dst_surface, dst_rect)) { - return false; - } - - res_cache.InvalidateRegion(dst_params.addr, dst_params.size, dst_surface); - return true; + return res_cache.AccelerateTextureCopy(config); } bool RasterizerVulkan::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) { - auto dst_surface = res_cache.GetFillSurface(config); - if (dst_surface == nullptr) - return false; - - res_cache.InvalidateRegion(dst_surface->addr, dst_surface->size, dst_surface); - return true; + return res_cache.AccelerateFill(config); } bool RasterizerVulkan::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config,