diff --git a/src/video_core/rasterizer_cache/cached_surface.cpp b/src/video_core/rasterizer_cache/cached_surface.cpp index 2719660b2..197d74a61 100644 --- a/src/video_core/rasterizer_cache/cached_surface.cpp +++ b/src/video_core/rasterizer_cache/cached_surface.cpp @@ -33,12 +33,17 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { const bool need_swap = GLES && (pixel_format == PixelFormat::RGBA8 || pixel_format == PixelFormat::RGB8); - const u8* const texture_src_data = VideoCore::g_memory->GetPhysicalPointer(addr); - if (texture_src_data == nullptr) + const u8* texture_ptr = VideoCore::g_memory->GetPhysicalPointer(addr); + if (texture_ptr == nullptr) { return; + } + + const u32 byte_size = width * height * GetBytesPerPixel(pixel_format); + const auto texture_data = std::span{reinterpret_cast(texture_ptr), + byte_size}; if (gl_buffer.empty()) { - gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format)); + gl_buffer.resize(byte_size); } // TODO: Should probably be done in ::Memory:: and check for other regions too @@ -60,48 +65,26 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { // cannot fully test this if (pixel_format == PixelFormat::RGBA8) { for (std::size_t i = start_offset; i < load_end - addr; i += 4) { - gl_buffer[i] = texture_src_data[i + 3]; - gl_buffer[i + 1] = texture_src_data[i + 2]; - gl_buffer[i + 2] = texture_src_data[i + 1]; - gl_buffer[i + 3] = texture_src_data[i]; + gl_buffer[i] = texture_ptr[i + 3]; + gl_buffer[i + 1] = texture_ptr[i + 2]; + gl_buffer[i + 2] = texture_ptr[i + 1]; + gl_buffer[i + 3] = texture_ptr[i]; } } else if (pixel_format == PixelFormat::RGB8) { for (std::size_t i = start_offset; i < load_end - addr; i += 3) { - gl_buffer[i] = texture_src_data[i + 2]; - gl_buffer[i + 1] = texture_src_data[i + 1]; - gl_buffer[i + 2] = texture_src_data[i]; + gl_buffer[i] = texture_ptr[i + 2]; + gl_buffer[i + 1] = texture_ptr[i + 1]; + gl_buffer[i + 2] = texture_ptr[i]; } } } else { - std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset, + std::memcpy(&gl_buffer[start_offset], texture_ptr + start_offset, load_end - load_start); } } else { - if (type == SurfaceType::Texture) { - Pica::Texture::TextureInfo tex_info{}; - tex_info.width = width; - tex_info.height = height; - tex_info.format = static_cast(pixel_format); - tex_info.SetDefaultStride(); - tex_info.physical_address = addr; - - const SurfaceInterval load_interval(load_start, load_end); - const auto rect = GetSubRect(FromInterval(load_interval)); - ASSERT(FromInterval(load_interval).GetInterval() == load_interval); - - for (unsigned y = rect.bottom; y < rect.top; ++y) { - for (unsigned x = rect.left; x < rect.right; ++x) { - auto vec4 = - Pica::Texture::LookupTexture(texture_src_data, x, height - 1 - y, tex_info); - const std::size_t offset = (x + (width * y)) * 4; - std::memcpy(&gl_buffer[offset], vec4.AsArray(), 4); - } - } - } else { - const u32 func_index = static_cast(pixel_format); - const MortonFunc func = UNSWIZZLE_TABLE[func_index]; - func(stride, height, &gl_buffer[0], addr, load_start, load_end); - } + const auto dest_data = std::span{reinterpret_cast(gl_buffer.data()), + byte_size}; + UnswizzleTexture(*this, load_start, load_end, texture_data, dest_data); } } @@ -109,10 +92,12 @@ MICROPROFILE_DEFINE(RasterizerCache_SurfaceFlush, "RasterizerCache", "Surface Fl MP_RGB(128, 192, 64)); void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { u8* const dst_buffer = VideoCore::g_memory->GetPhysicalPointer(addr); - if (dst_buffer == nullptr) + if (dst_buffer == nullptr) { return; + } - ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format)); + const u32 byte_size = width * height * GetBytesPerPixel(pixel_format); + DEBUG_ASSERT(gl_buffer.size() == byte_size); // TODO: Should probably be done in ::Memory:: and check for other regions too // same as loadglbuffer() @@ -132,8 +117,9 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { const u32 coarse_start_offset = start_offset - (start_offset % fill_size); const u32 backup_bytes = start_offset % fill_size; std::array backup_data; - if (backup_bytes) + if (backup_bytes) { std::memcpy(&backup_data[0], &dst_buffer[coarse_start_offset], backup_bytes); + } for (u32 offset = coarse_start_offset; offset < end_offset; offset += fill_size) { std::memcpy(&dst_buffer[offset], &fill_data[0], @@ -162,9 +148,9 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { flush_end - flush_start); } } else { - const u32 func_index = static_cast(pixel_format); - const MortonFunc func = SWIZZLE_TABLE[func_index]; - func(stride, height, &gl_buffer[0], addr, flush_start, flush_end); + const auto source_data = std::span{reinterpret_cast(gl_buffer.data()), + byte_size}; + SwizzleTexture(*this, flush_start, flush_end, source_data, {}); } } diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.cpp b/src/video_core/rasterizer_cache/rasterizer_cache.cpp index 3bd15198c..a9e09838b 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.cpp +++ b/src/video_core/rasterizer_cache/rasterizer_cache.cpp @@ -451,7 +451,8 @@ Surface RasterizerCache::GetTextureSurface(const Pica::Texture::TextureInfo& inf const Subresource dst_subresource = { .aspect = aspect, - .region = surface_params.GetScaledRect() + .region = surface_params.GetScaledRect(), + .level = level }; runtime.BlitTextures(level_surface->texture, src_subresource, diff --git a/src/video_core/rasterizer_cache/utils.cpp b/src/video_core/rasterizer_cache/utils.cpp index c341f8910..4e4dc9031 100644 --- a/src/video_core/rasterizer_cache/utils.cpp +++ b/src/video_core/rasterizer_cache/utils.cpp @@ -5,6 +5,8 @@ #pragma once #include #include "video_core/texture/texture_decode.h" +#include "video_core/rasterizer_cache/morton_swizzle.h" +#include "video_core/rasterizer_cache/surface_params.h" #include "video_core/rasterizer_cache/utils.h" #include "video_core/renderer_opengl/gl_vars.h" @@ -54,6 +56,49 @@ const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { return tex_tuple; } +void SwizzleTexture(const SurfaceParams& params, u32 flush_start, u32 flush_end, + std::span source, std::span dest) { + const u32 func_index = static_cast(params.pixel_format); + const MortonFunc swizzle = SWIZZLE_TABLE[func_index]; + u8* source_data = reinterpret_cast(source.data()); + + // TODO: Move memory access out of the morton function + swizzle(params.stride, params.height, source_data, params.addr, flush_start, flush_end); +} + +void UnswizzleTexture(const SurfaceParams& params, u32 load_start, u32 load_end, + std::span source, std::span dest) { + // TODO: Integrate this to UNSWIZZLE_TABLE + if (params.type == SurfaceType::Texture) { + Pica::Texture::TextureInfo tex_info{}; + tex_info.width = params.width; + tex_info.height = params.height; + tex_info.format = static_cast(params.pixel_format); + tex_info.SetDefaultStride(); + tex_info.physical_address = params.addr; + + const SurfaceInterval load_interval(load_start, load_end); + const auto rect = params.GetSubRect(params.FromInterval(load_interval)); + DEBUG_ASSERT(params.FromInterval(load_interval).GetInterval() == load_interval); + + const u8* source_data = reinterpret_cast(source.data()); + for (u32 y = rect.bottom; y < rect.top; y++) { + for (u32 x = rect.left; x < rect.right; x++) { + auto vec4 = + Pica::Texture::LookupTexture(source_data, x, params.height - 1 - y, tex_info); + const std::size_t offset = (x + (params.width * y)) * 4; + std::memcpy(dest.data() + offset, vec4.AsArray(), 4); + } + } + } else { + const u32 func_index = static_cast(params.pixel_format); + const MortonFunc deswizzle = UNSWIZZLE_TABLE[func_index]; + u8* dest_data = reinterpret_cast(dest.data()); + + deswizzle(params.stride, params.height, dest_data, params.addr, load_start, load_end); + } +} + ClearValue MakeClearValue(Aspect aspect, PixelFormat format, const u8* fill_data) { ClearValue result{}; switch (aspect) { diff --git a/src/video_core/rasterizer_cache/utils.h b/src/video_core/rasterizer_cache/utils.h index d3aa1c283..7070586b0 100644 --- a/src/video_core/rasterizer_cache/utils.h +++ b/src/video_core/rasterizer_cache/utils.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include "common/hash.h" #include "video_core/rasterizer_cache/pixel_format.h" #include "video_core/rasterizer_cache/types.h" @@ -47,6 +48,14 @@ struct TextureCubeConfig { } }; +class SurfaceParams; + +void SwizzleTexture(const SurfaceParams& params, u32 flush_start, u32 flush_end, + std::span source, std::span dest); + +void UnswizzleTexture(const SurfaceParams& params, u32 load_start, u32 load_end, + std::span source, std::span dest); + [[nodiscard]] ClearValue MakeClearValue(Aspect aspect, PixelFormat format, const u8* fill_data); [[nodiscard]] Aspect ToAspect(SurfaceType type); diff --git a/src/video_core/texture/texture_decode.cpp b/src/video_core/texture/texture_decode.cpp index e36b789ca..f6406a578 100644 --- a/src/video_core/texture/texture_decode.cpp +++ b/src/video_core/texture/texture_decode.cpp @@ -2,10 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/assert.h" #include "common/color.h" #include "common/logging/log.h" -#include "common/math_util.h" #include "common/swap.h" #include "common/vector_math.h" #include "video_core/regs_texturing.h" @@ -223,4 +223,23 @@ TextureInfo TextureInfo::FromPicaRegister(const TexturingRegs::TextureConfig& co return info; } +void ConvertBGRToRGBA(std::span source, std::span dest) { + u32 j = 0; + for (u32 i = 0; i < source.size(); i += 3) { + dest[j] = source[i + 2]; + dest[j + 1] = source[i + 1]; + dest[j + 2] = source[i]; + dest[j + 3] = std::byte{0xFF}; + j += 4; + } +} + +void ConvertABGRToRGBA(std::span source, std::span dest) { + for (u32 i = 0; i < source.size(); i += 4) { + const u32 abgr = *reinterpret_cast(source.data() + i); + const u32 rgba = std::byteswap(abgr); + std::memcpy(dest.data() + i, &rgba, 4); + } +} + } // namespace Pica::Texture diff --git a/src/video_core/texture/texture_decode.h b/src/video_core/texture/texture_decode.h index 9e6c216f2..82911e50a 100644 --- a/src/video_core/texture/texture_decode.h +++ b/src/video_core/texture/texture_decode.h @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #pragma once - +#include #include "common/common_types.h" #include "common/vector_math.h" #include "video_core/regs_texturing.h" @@ -55,4 +55,21 @@ Common::Vec4 LookupTexture(const u8* source, unsigned int x, unsigned int y, Common::Vec4 LookupTexelInTile(const u8* source, unsigned int x, unsigned int y, const TextureInfo& info, bool disable_alpha); +/** + * Converts pixel data encoded in BGR format to RGBA + * + * @param source Span to the source pixel data + * @param dest Span to the destination pixel data + */ +void ConvertBGRToRGBA(std::span source, std::span dest); + + +/** + * Converts pixel data encoded in ABGR format to RGBA + * + * @param source Span to the source pixel data + * @param dest Span to the destination pixel data + */ +void ConvertABGRToRGBA(std::span source, std::span dest); + } // namespace Pica::Texture