From 77a99506cb6a2a61d94d588df638eb9e5331ebff Mon Sep 17 00:00:00 2001 From: emufan4568 Date: Fri, 9 Sep 2022 21:29:23 +0300 Subject: [PATCH] cached_surface: Remove custom texture logic * Makes things more complicated and is in the way. It's probably already broken by recent changes, so I'll need to reimplement it anyway --- src/common/memory_ref.h | 6 + .../rasterizer_cache/cached_surface.cpp | 197 ++---------------- .../rasterizer_cache/cached_surface.h | 8 - .../rasterizer_cache/morton_swizzle.h | 7 +- .../rasterizer_cache/rasterizer_cache.cpp | 4 +- src/video_core/rasterizer_cache/utils.cpp | 19 +- src/video_core/texture/texture_decode.cpp | 8 + src/video_core/texture/texture_decode.h | 8 + 8 files changed, 61 insertions(+), 196 deletions(-) diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h index 77a118ade..4ae45dc51 100644 --- a/src/common/memory_ref.h +++ b/src/common/memory_ref.h @@ -89,12 +89,18 @@ public: u8* GetPtr() { return cptr; } + std::byte* GetBytes() { + return reinterpret_cast(cptr); + } operator const u8*() const { return cptr; } const u8* GetPtr() const { return cptr; } + const std::byte* GetBytes() const { + return reinterpret_cast(cptr); + } std::size_t GetSize() const { return csize; } diff --git a/src/video_core/rasterizer_cache/cached_surface.cpp b/src/video_core/rasterizer_cache/cached_surface.cpp index 40b6f4b4f..de69f89db 100644 --- a/src/video_core/rasterizer_cache/cached_surface.cpp +++ b/src/video_core/rasterizer_cache/cached_surface.cpp @@ -20,69 +20,41 @@ namespace OpenGL { CachedSurface::~CachedSurface() { if (texture.handle) { - auto tag = is_custom ? HostTextureTag{PixelFormat::RGBA8, - custom_tex_info.width, custom_tex_info.height} - : HostTextureTag{pixel_format, GetScaledWidth(), - GetScaledHeight()}; - + const auto tag = HostTextureTag{pixel_format, GetScaledWidth(), GetScaledHeight()}; owner.host_texture_recycler.emplace(tag, std::move(texture)); } } MICROPROFILE_DEFINE(RasterizerCache_SurfaceLoad, "RasterizerCache", "Surface Load", MP_RGB(128, 192, 64)); void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { - ASSERT(type != SurfaceType::Fill); - const bool need_swap = - GLES && (pixel_format == PixelFormat::RGBA8 || pixel_format == PixelFormat::RGB8); + DEBUG_ASSERT(load_start >= addr && load_end <= end); - u8* texture_ptr = VideoCore::g_memory->GetPhysicalPointer(addr); - if (texture_ptr == nullptr) { + auto texture_ptr = VideoCore::g_memory->GetPhysicalRef(load_start); + if (!texture_ptr) { return; } - // TODO: Should probably be done in ::Memory:: and check for other regions too - if (load_start < Memory::VRAM_VADDR_END && load_end > Memory::VRAM_VADDR_END) - load_end = Memory::VRAM_VADDR_END; - - if (load_start < Memory::VRAM_VADDR && load_end > Memory::VRAM_VADDR) - load_start = Memory::VRAM_VADDR; - - ASSERT(load_start >= addr && load_end <= end); - - const u32 start_offset = load_start - addr; - const u32 byte_size = width * height * GetBytesPerPixel(pixel_format); + const u32 upload_size = std::clamp(load_end - load_start, 0u, static_cast(texture_ptr.GetSize())); + const u32 texture_size = width * height * GetBytesPerPixel(pixel_format); + const auto upload_data = std::span{texture_ptr.GetBytes(), upload_size}; if (gl_buffer.empty()) { - gl_buffer.resize(byte_size); + gl_buffer.resize(texture_size); } MICROPROFILE_SCOPE(RasterizerCache_SurfaceLoad); if (!is_tiled) { ASSERT(type == SurfaceType::Color); - if (need_swap) { - // TODO(liushuyu): check if the byteswap here is 100% correct - // 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] = (std::byte)texture_ptr[i + 3]; - gl_buffer[i + 1] = (std::byte)texture_ptr[i + 2]; - gl_buffer[i + 2] = (std::byte)texture_ptr[i + 1]; - gl_buffer[i + 3] = (std::byte)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] = (std::byte)texture_ptr[i + 2]; - gl_buffer[i + 1] = (std::byte)texture_ptr[i + 1]; - gl_buffer[i + 2] = (std::byte)texture_ptr[i]; - } - } + if (pixel_format == PixelFormat::RGBA8 && GLES) { + Pica::Texture::ConvertABGRToRGBA(upload_data, gl_buffer); + } else if (pixel_format == PixelFormat::RGB8 && GLES) { + Pica::Texture::ConvertBGRToRGB(upload_data, gl_buffer); } else { - std::memcpy(gl_buffer.data() + start_offset, texture_ptr + start_offset, load_end - load_start); + std::memcpy(gl_buffer.data() + load_start - addr, texture_ptr, upload_size); } } else { - std::span texture_data{(std::byte*)texture_ptr, byte_size}; - UnswizzleTexture(*this, load_start, load_end, texture_data, gl_buffer); + UnswizzleTexture(*this, load_start, load_end, upload_data, gl_buffer); } } @@ -150,92 +122,6 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { } } -bool CachedSurface::LoadCustomTexture(u64 tex_hash) { - Core::System& system = Core::System::GetInstance(); - auto& custom_tex_cache = system.CustomTexCache(); - const auto& image_interface = system.GetImageInterface(); - - if (custom_tex_cache.IsTextureCached(tex_hash)) { - custom_tex_info = custom_tex_cache.LookupTexture(tex_hash); - return true; - } - - if (!custom_tex_cache.CustomTextureExists(tex_hash)) { - return false; - } - - const auto& path_info = custom_tex_cache.LookupTexturePathInfo(tex_hash); - if (!image_interface->DecodePNG(custom_tex_info.tex, custom_tex_info.width, - custom_tex_info.height, path_info.path)) { - LOG_ERROR(Render_OpenGL, "Failed to load custom texture {}", path_info.path); - return false; - } - - if (std::popcount(custom_tex_info.width) != 1 || std::popcount(custom_tex_info.height) != 1) { - LOG_ERROR(Render_OpenGL, "Texture {} size is not a power of 2", path_info.path); - return false; - } - - LOG_DEBUG(Render_OpenGL, "Loaded custom texture from {}", path_info.path); - Common::FlipRGBA8Texture(custom_tex_info.tex, custom_tex_info.width, custom_tex_info.height); - custom_tex_cache.CacheTexture(tex_hash, custom_tex_info.tex, custom_tex_info.width, - custom_tex_info.height); - return true; -} - -void CachedSurface::DumpTexture(GLuint target_tex, u64 tex_hash) { - // Make sure the texture size is a power of 2 - // If not, the surface is actually a framebuffer - if (std::popcount(width) != 1 || std::popcount(height) != 1) { - LOG_WARNING(Render_OpenGL, "Not dumping {:016X} because size isn't a power of 2 ({}x{})", - tex_hash, width, height); - return; - } - - // Dump texture to RGBA8 and encode as PNG - Core::System& system = Core::System::GetInstance(); - const auto& image_interface = system.GetImageInterface(); - auto& custom_tex_cache = system.CustomTexCache(); - std::string dump_path = - fmt::format("{}textures/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), - system.Kernel().GetCurrentProcess()->codeset->program_id); - if (!FileUtil::CreateFullPath(dump_path)) { - LOG_ERROR(Render, "Unable to create {}", dump_path); - return; - } - - dump_path += fmt::format("tex1_{}x{}_{:016X}_{}.png", width, height, tex_hash, pixel_format); - if (!custom_tex_cache.IsTextureDumped(tex_hash) && !FileUtil::Exists(dump_path)) { - custom_tex_cache.SetTextureDumped(tex_hash); - - LOG_INFO(Render_OpenGL, "Dumping texture to {}", dump_path); - std::vector decoded_texture; - decoded_texture.resize(width * height * 4); - OpenGLState state = OpenGLState::GetCurState(); - GLuint old_texture = state.texture_units[0].texture_2d; - state.Apply(); - /* - GetTexImageOES is used even if not using OpenGL ES to work around a small issue that - happens if using custom textures with texture dumping at the same. - Let's say there's 2 textures that are both 32x32 and one of them gets replaced with a - higher quality 256x256 texture. If the 256x256 texture is displayed first and the - 32x32 texture gets uploaded to the same underlying OpenGL texture, the 32x32 texture - will appear in the corner of the 256x256 texture. If texture dumping is enabled and - the 32x32 is undumped, Citra will attempt to dump it. Since the underlying OpenGL - texture is still 256x256, Citra crashes because it thinks the texture is only 32x32. - GetTexImageOES conveniently only dumps the specified region, and works on both - desktop and ES. - */ - owner.texture_downloader_es->GetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, - height, width, &decoded_texture[0]); - state.texture_units[0].texture_2d = old_texture; - state.Apply(); - Common::FlipRGBA8Texture(decoded_texture, width, height); - if (!image_interface->EncodePNG(dump_path, decoded_texture, width, height)) - LOG_ERROR(Render_OpenGL, "Failed to save decoded texture"); - } -} - MICROPROFILE_DEFINE(RasterizerCache_TextureUL, "RasterizerCache", "Texture Upload", MP_RGB(128, 192, 64)); void CachedSurface::UploadGLTexture(Common::Rectangle rect) { if (type == SurfaceType::Fill) { @@ -245,16 +131,6 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect) { MICROPROFILE_SCOPE(RasterizerCache_TextureUL); ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format)); - u64 tex_hash = 0; - - if (Settings::values.dump_textures || Settings::values.custom_textures) { - tex_hash = Common::ComputeHash64(gl_buffer.data(), gl_buffer.size()); - } - - if (Settings::values.custom_textures) { - is_custom = LoadCustomTexture(tex_hash); - } - // Load data from memory to the surface GLint x0 = static_cast(rect.left); GLint y0 = static_cast(rect.bottom); @@ -265,16 +141,11 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect) { // If not 1x scale, create 1x texture that we will blit from to replace texture subrect in // surface OGLTexture unscaled_tex; - if (IsScaled()) { + if (res_scale != 1) { x0 = 0; y0 = 0; - if (is_custom) { - unscaled_tex = - owner.AllocateSurfaceTexture(PixelFormat::RGBA8, custom_tex_info.width, custom_tex_info.height); - } else { - unscaled_tex = owner.AllocateSurfaceTexture(pixel_format, rect.GetWidth(), rect.GetHeight()); - } + unscaled_tex = owner.AllocateSurfaceTexture(pixel_format, rect.GetWidth(), rect.GetHeight()); target_tex = unscaled_tex.handle; } @@ -289,34 +160,15 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect) { // Ensure no bad interactions with GL_UNPACK_ALIGNMENT ASSERT(stride * GetBytesPerPixel(pixel_format) % 4 == 0); - if (is_custom) { - if (res_scale == 1) { - texture = owner.AllocateSurfaceTexture(PixelFormat::RGBA8, - custom_tex_info.width, custom_tex_info.height); - cur_state.texture_units[0].texture_2d = texture.handle; - cur_state.Apply(); - } + glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast(stride)); - // Always going to be using rgba8 - glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast(custom_tex_info.width)); + glActiveTexture(GL_TEXTURE0); - glActiveTexture(GL_TEXTURE0); - glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, custom_tex_info.width, custom_tex_info.height, - GL_RGBA, GL_UNSIGNED_BYTE, custom_tex_info.tex.data()); - } else { - glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast(stride)); - - glActiveTexture(GL_TEXTURE0); - - glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast(rect.GetWidth()), - static_cast(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[buffer_offset]); - } + glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast(rect.GetWidth()), + static_cast(rect.GetHeight()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - if (Settings::values.dump_textures && !is_custom) { - DumpTexture(target_tex, tex_hash); - } cur_state.texture_units[0].texture_2d = old_tex; cur_state.Apply(); @@ -328,10 +180,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect) { scaled_rect.right *= res_scale; scaled_rect.bottom *= res_scale; - const u32 width = is_custom ? custom_tex_info.width : rect.GetWidth(); - const u32 height = is_custom ? custom_tex_info.height : rect.GetHeight(); - const Common::Rectangle from_rect{0, height, width, 0}; - + const Common::Rectangle from_rect{0, rect.GetHeight(), rect.GetWidth(), 0}; if (!owner.texture_filterer->Filter(unscaled_tex, from_rect, texture, scaled_rect, type)) { const TextureBlit texture_blit = { .surface_type = type, @@ -374,7 +223,7 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle& rect) { const u32 buffer_offset = (rect.bottom * stride + rect.left) * GetBytesPerPixel(pixel_format); // If not 1x scale, blit scaled texture to a new 1x texture and use that to flush - if (IsScaled()) { + if (res_scale != 1) { auto scaled_rect = rect; scaled_rect.left *= res_scale; scaled_rect.top *= res_scale; diff --git a/src/video_core/rasterizer_cache/cached_surface.h b/src/video_core/rasterizer_cache/cached_surface.h index d268222b7..092fcef49 100644 --- a/src/video_core/rasterizer_cache/cached_surface.h +++ b/src/video_core/rasterizer_cache/cached_surface.h @@ -55,10 +55,6 @@ public: void LoadGLBuffer(PAddr load_start, PAddr load_end); void FlushGLBuffer(PAddr flush_start, PAddr flush_end); - /// Custom texture loading and dumping - bool LoadCustomTexture(u64 tex_hash); - void DumpTexture(GLuint target_tex, u64 tex_hash); - /// Upload/Download data in gl_buffer in/to this surface's texture void UploadGLTexture(Common::Rectangle rect); void DownloadGLTexture(const Common::Rectangle& rect); @@ -114,10 +110,6 @@ public: std::array, 7> level_watchers; u32 max_level = 0; - // Information about custom textures - bool is_custom = false; - Core::CustomTexInfo custom_tex_info; - private: RasterizerCache& owner; TextureRuntime& runtime; diff --git a/src/video_core/rasterizer_cache/morton_swizzle.h b/src/video_core/rasterizer_cache/morton_swizzle.h index 372d1f823..138f7c52c 100644 --- a/src/video_core/rasterizer_cache/morton_swizzle.h +++ b/src/video_core/rasterizer_cache/morton_swizzle.h @@ -113,7 +113,12 @@ static void MortonCopy(u32 stride, u32 height, } }; - u8* tile_buffer = VideoCore::g_memory->GetPhysicalPointer(start); + u8* tile_buffer; + if constexpr (morton_to_linear) { + tile_buffer = (u8*)tiled_buffer.data(); + } else { + tile_buffer = VideoCore::g_memory->GetPhysicalPointer(start); + } // If during a texture download the start coordinate is inside a tile, swizzle // the tile to a temporary buffer and copy the part we are interested in diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.cpp b/src/video_core/rasterizer_cache/rasterizer_cache.cpp index e10f62daf..c0f8dff6e 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.cpp +++ b/src/video_core/rasterizer_cache/rasterizer_cache.cpp @@ -421,7 +421,7 @@ Surface RasterizerCache::GetTextureSurface(const Pica::Texture::TextureInfo& inf // Allocate more mipmap level if necessary if (surface->max_level < max_level) { - if (surface->is_custom || !texture_filterer->IsNull()) { + if (!texture_filterer->IsNull()) { // TODO: proper mipmap support for custom textures runtime.GenerateMipmaps(surface->texture, max_level); } @@ -456,7 +456,7 @@ Surface RasterizerCache::GetTextureSurface(const Pica::Texture::TextureInfo& inf ValidateSurface(level_surface, level_surface->addr, level_surface->size); } - if (!surface->is_custom && texture_filterer->IsNull()) { + if (texture_filterer->IsNull()) { const auto src_rect = level_surface->GetScaledRect(); const auto dst_rect = surface_params.GetScaledRect(); const TextureBlit texture_blit = { diff --git a/src/video_core/rasterizer_cache/utils.cpp b/src/video_core/rasterizer_cache/utils.cpp index 7f67b65a2..40b2137c3 100644 --- a/src/video_core/rasterizer_cache/utils.cpp +++ b/src/video_core/rasterizer_cache/utils.cpp @@ -77,19 +77,16 @@ void UnswizzleTexture(const SurfaceParams& params, u32 load_start, u32 load_end, 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 u32 start_pixel = params.PixelsInBytes(load_start - params.addr); const u8* source_data = reinterpret_cast(source_tiled.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_linear.data() + offset, vec4.AsArray(), 4); - } + for (u32 i = 0; i < params.PixelsInBytes(load_end - load_start); i++) { + const u32 x = (i + start_pixel) % params.stride; + const u32 y = (i + start_pixel) / params.stride; + + auto vec4 = Pica::Texture::LookupTexture(source_data, x, params.height - 1 - y, tex_info); + std::memcpy(dest_linear.data() + i * sizeof(u32), vec4.AsArray(), sizeof(u32)); } + } else { const u32 func_index = static_cast(params.pixel_format); const MortonFunc UnswizzleImpl = UNSWIZZLE_TABLE[func_index]; diff --git a/src/video_core/texture/texture_decode.cpp b/src/video_core/texture/texture_decode.cpp index 7bac1fcc6..bce17939b 100644 --- a/src/video_core/texture/texture_decode.cpp +++ b/src/video_core/texture/texture_decode.cpp @@ -222,6 +222,14 @@ TextureInfo TextureInfo::FromPicaRegister(const TexturingRegs::TextureConfig& co return info; } +void ConvertBGRToRGB(std::span source, std::span dest) { + for (std::size_t i = 0; i < source.size(); i += 3) { + dest[i] = source[i + 2]; + dest[i + 1] = source[i + 1]; + dest[i + 2] = source[i]; + } +} + void ConvertBGRToRGBA(std::span source, std::span dest) { u32 j = 0; for (u32 i = 0; i < source.size(); i += 3) { diff --git a/src/video_core/texture/texture_decode.h b/src/video_core/texture/texture_decode.h index 82911e50a..d8b8238c7 100644 --- a/src/video_core/texture/texture_decode.h +++ b/src/video_core/texture/texture_decode.h @@ -55,6 +55,14 @@ 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 ConvertBGRToRGB(std::span source, std::span dest); + /** * Converts pixel data encoded in BGR format to RGBA *