mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	rasterizer_cache: Factor morton swizzle and pixel format to dedicate headers
* Makes the code cleaner in general by not having to alias PixelFormat and SurfaceType everywhere
This commit is contained in:
		
							parent
							
								
									efc2db4088
								
							
						
					
					
						commit
						6a7d601e42
					
				
					 13 changed files with 427 additions and 409 deletions
				
			
		|  | @ -23,6 +23,8 @@ add_library(video_core STATIC | |||
|     regs_texturing.h | ||||
|     renderer_base.cpp | ||||
|     renderer_base.h | ||||
|     rasterizer_cache/morton_swizzle.h | ||||
|     rasterizer_cache/pixel_format.h | ||||
|     rasterizer_cache/rasterizer_cache.cpp | ||||
|     rasterizer_cache/rasterizer_cache.h | ||||
|     rasterizer_cache/surface_params.cpp | ||||
|  |  | |||
							
								
								
									
										171
									
								
								src/video_core/rasterizer_cache/morton_swizzle.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/video_core/rasterizer_cache/morton_swizzle.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,171 @@ | |||
| // Copyright 2022 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include "common/alignment.h" | ||||
| #include "core/memory.h" | ||||
| #include "video_core/rasterizer_cache/pixel_format.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| #include "video_core/utils.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| template <bool morton_to_gl, PixelFormat format> | ||||
| static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) { | ||||
|     constexpr u32 bytes_per_pixel = GetFormatBpp(format) / 8; | ||||
|     constexpr u32 aligned_bytes_per_pixel = GetBytesPerPixel(format); | ||||
|     for (u32 y = 0; y < 8; ++y) { | ||||
|         for (u32 x = 0; x < 8; ++x) { | ||||
|             u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel; | ||||
|             u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * aligned_bytes_per_pixel; | ||||
|             if constexpr (morton_to_gl) { | ||||
|                 if constexpr (format == PixelFormat::D24S8) { | ||||
|                     gl_ptr[0] = tile_ptr[3]; | ||||
|                     std::memcpy(gl_ptr + 1, tile_ptr, 3); | ||||
|                 } else if (format == PixelFormat::RGBA8 && GLES) { | ||||
|                     // because GLES does not have ABGR format
 | ||||
|                     // so we will do byteswapping here
 | ||||
|                     gl_ptr[0] = tile_ptr[3]; | ||||
|                     gl_ptr[1] = tile_ptr[2]; | ||||
|                     gl_ptr[2] = tile_ptr[1]; | ||||
|                     gl_ptr[3] = tile_ptr[0]; | ||||
|                 } else if (format == PixelFormat::RGB8 && GLES) { | ||||
|                     gl_ptr[0] = tile_ptr[2]; | ||||
|                     gl_ptr[1] = tile_ptr[1]; | ||||
|                     gl_ptr[2] = tile_ptr[0]; | ||||
|                 } else { | ||||
|                     std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel); | ||||
|                 } | ||||
|             } else { | ||||
|                 if constexpr (format == PixelFormat::D24S8) { | ||||
|                     std::memcpy(tile_ptr, gl_ptr + 1, 3); | ||||
|                     tile_ptr[3] = gl_ptr[0]; | ||||
|                 } else if (format == PixelFormat::RGBA8 && GLES) { | ||||
|                     // because GLES does not have ABGR format
 | ||||
|                     // so we will do byteswapping here
 | ||||
|                     tile_ptr[0] = gl_ptr[3]; | ||||
|                     tile_ptr[1] = gl_ptr[2]; | ||||
|                     tile_ptr[2] = gl_ptr[1]; | ||||
|                     tile_ptr[3] = gl_ptr[0]; | ||||
|                 } else if (format == PixelFormat::RGB8 && GLES) { | ||||
|                     tile_ptr[0] = gl_ptr[2]; | ||||
|                     tile_ptr[1] = gl_ptr[1]; | ||||
|                     tile_ptr[2] = gl_ptr[0]; | ||||
|                 } else { | ||||
|                     std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template <bool morton_to_gl, PixelFormat format> | ||||
| static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr start, PAddr end) { | ||||
|     constexpr u32 bytes_per_pixel = GetFormatBpp(format) / 8; | ||||
|     constexpr u32 tile_size = bytes_per_pixel * 64; | ||||
| 
 | ||||
|     constexpr u32 aligned_bytes_per_pixel = GetBytesPerPixel(format); | ||||
|     static_assert(aligned_bytes_per_pixel >= bytes_per_pixel, ""); | ||||
|     gl_buffer += aligned_bytes_per_pixel - bytes_per_pixel; | ||||
| 
 | ||||
|     const PAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size); | ||||
|     const PAddr aligned_start = base + Common::AlignUp(start - base, tile_size); | ||||
|     const PAddr aligned_end = base + Common::AlignDown(end - base, tile_size); | ||||
| 
 | ||||
|     ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end)); | ||||
| 
 | ||||
|     const u32 begin_pixel_index = (aligned_down_start - base) / bytes_per_pixel; | ||||
|     u32 x = (begin_pixel_index % (stride * 8)) / 8; | ||||
|     u32 y = (begin_pixel_index / (stride * 8)) * 8; | ||||
| 
 | ||||
|     gl_buffer += ((height - 8 - y) * stride + x) * aligned_bytes_per_pixel; | ||||
| 
 | ||||
|     auto glbuf_next_tile = [&] { | ||||
|         x = (x + 8) % stride; | ||||
|         gl_buffer += 8 * aligned_bytes_per_pixel; | ||||
|         if (!x) { | ||||
|             y += 8; | ||||
|             gl_buffer -= stride * 9 * aligned_bytes_per_pixel; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     u8* tile_buffer = VideoCore::g_memory->GetPhysicalPointer(start); | ||||
| 
 | ||||
|     if (start < aligned_start && !morton_to_gl) { | ||||
|         std::array<u8, tile_size> tmp_buf; | ||||
|         MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer); | ||||
|         std::memcpy(tile_buffer, &tmp_buf[start - aligned_down_start], | ||||
|                     std::min(aligned_start, end) - start); | ||||
| 
 | ||||
|         tile_buffer += aligned_start - start; | ||||
|         glbuf_next_tile(); | ||||
|     } | ||||
| 
 | ||||
|     const u8* const buffer_end = tile_buffer + aligned_end - aligned_start; | ||||
|     PAddr current_paddr = aligned_start; | ||||
|     while (tile_buffer < buffer_end) { | ||||
|         // Pokemon Super Mystery Dungeon will try to use textures that go beyond
 | ||||
|         // the end address of VRAM. Stop reading if reaches invalid address
 | ||||
|         if (!VideoCore::g_memory->IsValidPhysicalAddress(current_paddr) || | ||||
|             !VideoCore::g_memory->IsValidPhysicalAddress(current_paddr + tile_size)) { | ||||
|             LOG_ERROR(Render_OpenGL, "Out of bound texture"); | ||||
|             break; | ||||
|         } | ||||
|         MortonCopyTile<morton_to_gl, format>(stride, tile_buffer, gl_buffer); | ||||
|         tile_buffer += tile_size; | ||||
|         current_paddr += tile_size; | ||||
|         glbuf_next_tile(); | ||||
|     } | ||||
| 
 | ||||
|     if (end > std::max(aligned_start, aligned_end) && !morton_to_gl) { | ||||
|         std::array<u8, tile_size> tmp_buf; | ||||
|         MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer); | ||||
|         std::memcpy(tile_buffer, &tmp_buf[0], end - aligned_end); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> morton_to_gl_fns = { | ||||
|     MortonCopy<true, PixelFormat::RGBA8>,  // 0
 | ||||
|     MortonCopy<true, PixelFormat::RGB8>,   // 1
 | ||||
|     MortonCopy<true, PixelFormat::RGB5A1>, // 2
 | ||||
|     MortonCopy<true, PixelFormat::RGB565>, // 3
 | ||||
|     MortonCopy<true, PixelFormat::RGBA4>,  // 4
 | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr,                             // 5 - 13
 | ||||
|     MortonCopy<true, PixelFormat::D16>,  // 14
 | ||||
|     nullptr,                             // 15
 | ||||
|     MortonCopy<true, PixelFormat::D24>,  // 16
 | ||||
|     MortonCopy<true, PixelFormat::D24S8> // 17
 | ||||
| }; | ||||
| 
 | ||||
| static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl_to_morton_fns = { | ||||
|     MortonCopy<false, PixelFormat::RGBA8>,  // 0
 | ||||
|     MortonCopy<false, PixelFormat::RGB8>,   // 1
 | ||||
|     MortonCopy<false, PixelFormat::RGB5A1>, // 2
 | ||||
|     MortonCopy<false, PixelFormat::RGB565>, // 3
 | ||||
|     MortonCopy<false, PixelFormat::RGBA4>,  // 4
 | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr,                              // 5 - 13
 | ||||
|     MortonCopy<false, PixelFormat::D16>,  // 14
 | ||||
|     nullptr,                              // 15
 | ||||
|     MortonCopy<false, PixelFormat::D24>,  // 16
 | ||||
|     MortonCopy<false, PixelFormat::D24S8> // 17
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace OpenGL
 | ||||
							
								
								
									
										194
									
								
								src/video_core/rasterizer_cache/pixel_format.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								src/video_core/rasterizer_cache/pixel_format.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,194 @@ | |||
| // Copyright 2022 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <string_view> | ||||
| #include "core/hw/gpu.h" | ||||
| #include "video_core/regs_texturing.h" | ||||
| #include "video_core/regs_framebuffer.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| enum class PixelFormat : u8 { | ||||
|     // First 5 formats are shared between textures and color buffers
 | ||||
|     RGBA8 = 0, | ||||
|     RGB8 = 1, | ||||
|     RGB5A1 = 2, | ||||
|     RGB565 = 3, | ||||
|     RGBA4 = 4, | ||||
|     // Texture-only formats
 | ||||
|     IA8 = 5, | ||||
|     RG8 = 6, | ||||
|     I8 = 7, | ||||
|     A8 = 8, | ||||
|     IA4 = 9, | ||||
|     I4 = 10, | ||||
|     A4 = 11, | ||||
|     ETC1 = 12, | ||||
|     ETC1A4 = 13, | ||||
|     // Depth buffer-only formats
 | ||||
|     D16 = 14, | ||||
|     D24 = 16, | ||||
|     D24S8 = 17, | ||||
|     Invalid = 255, | ||||
| }; | ||||
| 
 | ||||
| enum class SurfaceType { | ||||
|     Color = 0, | ||||
|     Texture = 1, | ||||
|     Depth = 2, | ||||
|     DepthStencil = 3, | ||||
|     Fill = 4, | ||||
|     Invalid = 5 | ||||
| }; | ||||
| 
 | ||||
| static constexpr std::string_view PixelFormatAsString(PixelFormat format) { | ||||
|     switch (format) { | ||||
|     case PixelFormat::RGBA8: | ||||
|         return "RGBA8"; | ||||
|     case PixelFormat::RGB8: | ||||
|         return "RGB8"; | ||||
|     case PixelFormat::RGB5A1: | ||||
|         return "RGB5A1"; | ||||
|     case PixelFormat::RGB565: | ||||
|         return "RGB565"; | ||||
|     case PixelFormat::RGBA4: | ||||
|         return "RGBA4"; | ||||
|     case PixelFormat::IA8: | ||||
|         return "IA8"; | ||||
|     case PixelFormat::RG8: | ||||
|         return "RG8"; | ||||
|     case PixelFormat::I8: | ||||
|         return "I8"; | ||||
|     case PixelFormat::A8: | ||||
|         return "A8"; | ||||
|     case PixelFormat::IA4: | ||||
|         return "IA4"; | ||||
|     case PixelFormat::I4: | ||||
|         return "I4"; | ||||
|     case PixelFormat::A4: | ||||
|         return "A4"; | ||||
|     case PixelFormat::ETC1: | ||||
|         return "ETC1"; | ||||
|     case PixelFormat::ETC1A4: | ||||
|         return "ETC1A4"; | ||||
|     case PixelFormat::D16: | ||||
|         return "D16"; | ||||
|     case PixelFormat::D24: | ||||
|         return "D24"; | ||||
|     case PixelFormat::D24S8: | ||||
|         return "D24S8"; | ||||
|     default: | ||||
|         return "NotReal"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static constexpr PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) { | ||||
|     const u32 format_index = static_cast<u32>(format); | ||||
|     return (format_index < 14) ? static_cast<PixelFormat>(format) : PixelFormat::Invalid; | ||||
| } | ||||
| 
 | ||||
| static constexpr PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) { | ||||
|     const u32 format_index = static_cast<u32>(format); | ||||
|     return (format_index < 5) ? static_cast<PixelFormat>(format) : PixelFormat::Invalid; | ||||
| } | ||||
| 
 | ||||
| static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) { | ||||
|     const u32 format_index = static_cast<u32>(format); | ||||
|     return (format_index < 4) ? static_cast<PixelFormat>(format_index + 14) | ||||
|                               : PixelFormat::Invalid; | ||||
| } | ||||
| 
 | ||||
| static constexpr PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) { | ||||
|     switch (format) { | ||||
|     // RGB565 and RGB5A1 are switched in PixelFormat compared to ColorFormat
 | ||||
|     case GPU::Regs::PixelFormat::RGB565: | ||||
|         return PixelFormat::RGB565; | ||||
|     case GPU::Regs::PixelFormat::RGB5A1: | ||||
|         return PixelFormat::RGB5A1; | ||||
|     default: | ||||
|         return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) { | ||||
|     const u32 format_index = static_cast<u32>(pixel_format); | ||||
|     if (format_index < 5) { | ||||
|         return SurfaceType::Color; | ||||
|     } | ||||
| 
 | ||||
|     if (format_index < 14) { | ||||
|         return SurfaceType::Texture; | ||||
|     } | ||||
| 
 | ||||
|     if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) { | ||||
|         return SurfaceType::Depth; | ||||
|     } | ||||
| 
 | ||||
|     if (pixel_format == PixelFormat::D24S8) { | ||||
|         return SurfaceType::DepthStencil; | ||||
|     } | ||||
| 
 | ||||
|     return SurfaceType::Invalid; | ||||
| } | ||||
| 
 | ||||
| static constexpr bool CheckFormatsBlittable(PixelFormat source_format, PixelFormat dest_format) { | ||||
|     SurfaceType source_type = GetFormatType(source_format); | ||||
|     SurfaceType dest_type = GetFormatType(dest_format); | ||||
| 
 | ||||
|     if ((source_type == SurfaceType::Color || source_type == SurfaceType::Texture) && | ||||
|         (dest_type == SurfaceType::Color || dest_type == SurfaceType::Texture)) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     if (source_type == SurfaceType::Depth && dest_type == SurfaceType::Depth) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     if (source_type == SurfaceType::DepthStencil && dest_type == SurfaceType::DepthStencil) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static constexpr u32 GetFormatBpp(PixelFormat format) { | ||||
|     switch (format) { | ||||
|     case PixelFormat::RGBA8: | ||||
|     case PixelFormat::D24S8: | ||||
|         return 32; | ||||
|     case PixelFormat::RGB8: | ||||
|     case PixelFormat::D24: | ||||
|         return 24; | ||||
|     case PixelFormat::RGB5A1: | ||||
|     case PixelFormat::RGB565: | ||||
|     case PixelFormat::RGBA4: | ||||
|     case PixelFormat::IA8: | ||||
|     case PixelFormat::RG8: | ||||
|     case PixelFormat::D16: | ||||
|         return 16; | ||||
|     case PixelFormat::I8: | ||||
|     case PixelFormat::A8: | ||||
|     case PixelFormat::IA4: | ||||
|     case PixelFormat::ETC1A4: | ||||
|         return 8; | ||||
|     case PixelFormat::I4: | ||||
|     case PixelFormat::A4: | ||||
|     case PixelFormat::ETC1: | ||||
|         return 4; | ||||
|     case PixelFormat::Invalid: | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static constexpr u32 GetBytesPerPixel(PixelFormat format) { | ||||
|     // OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type
 | ||||
|     if (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture) { | ||||
|         return 4; | ||||
|     } | ||||
| 
 | ||||
|     return GetFormatBpp(format) / 8; | ||||
| } | ||||
| 
 | ||||
| } // namespace OpenGL
 | ||||
|  | @ -29,24 +29,17 @@ | |||
| #include "core/custom_tex_cache.h" | ||||
| #include "core/frontend/emu_window.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/memory.h" | ||||
| #include "core/settings.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/renderer_base.h" | ||||
| #include "video_core/renderer_opengl/gl_format_reinterpreter.h" | ||||
| #include "video_core/rasterizer_cache/morton_swizzle.h" | ||||
| #include "video_core/rasterizer_cache/rasterizer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| #include "video_core/renderer_opengl/texture_downloader_es.h" | ||||
| #include "video_core/renderer_opengl/texture_filters/texture_filterer.h" | ||||
| #include "video_core/utils.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| using SurfaceType = SurfaceParams::SurfaceType; | ||||
| using PixelFormat = SurfaceParams::PixelFormat; | ||||
| 
 | ||||
| static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{ | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8},     // RGBA8
 | ||||
|     {GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE},              // RGB8
 | ||||
|  | @ -67,7 +60,7 @@ static constexpr std::array<FormatTuple, 5> fb_format_tuples_oes = {{ | |||
| }}; | ||||
| 
 | ||||
| const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { | ||||
|     const SurfaceType type = SurfaceParams::GetFormatType(pixel_format); | ||||
|     const SurfaceType type = GetFormatType(pixel_format); | ||||
|     if (type == SurfaceType::Color) { | ||||
|         ASSERT(static_cast<std::size_t>(pixel_format) < fb_format_tuples.size()); | ||||
|         if (GLES) { | ||||
|  | @ -87,162 +80,6 @@ static constexpr auto RangeFromInterval(Map& map, const Interval& interval) { | |||
|     return boost::make_iterator_range(map.equal_range(interval)); | ||||
| } | ||||
| 
 | ||||
| template <bool morton_to_gl, PixelFormat format> | ||||
| static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) { | ||||
|     constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; | ||||
|     constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); | ||||
|     for (u32 y = 0; y < 8; ++y) { | ||||
|         for (u32 x = 0; x < 8; ++x) { | ||||
|             u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel; | ||||
|             u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * gl_bytes_per_pixel; | ||||
|             if constexpr (morton_to_gl) { | ||||
|                 if constexpr (format == PixelFormat::D24S8) { | ||||
|                     gl_ptr[0] = tile_ptr[3]; | ||||
|                     std::memcpy(gl_ptr + 1, tile_ptr, 3); | ||||
|                 } else if (format == PixelFormat::RGBA8 && GLES) { | ||||
|                     // because GLES does not have ABGR format
 | ||||
|                     // so we will do byteswapping here
 | ||||
|                     gl_ptr[0] = tile_ptr[3]; | ||||
|                     gl_ptr[1] = tile_ptr[2]; | ||||
|                     gl_ptr[2] = tile_ptr[1]; | ||||
|                     gl_ptr[3] = tile_ptr[0]; | ||||
|                 } else if (format == PixelFormat::RGB8 && GLES) { | ||||
|                     gl_ptr[0] = tile_ptr[2]; | ||||
|                     gl_ptr[1] = tile_ptr[1]; | ||||
|                     gl_ptr[2] = tile_ptr[0]; | ||||
|                 } else { | ||||
|                     std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel); | ||||
|                 } | ||||
|             } else { | ||||
|                 if constexpr (format == PixelFormat::D24S8) { | ||||
|                     std::memcpy(tile_ptr, gl_ptr + 1, 3); | ||||
|                     tile_ptr[3] = gl_ptr[0]; | ||||
|                 } else if (format == PixelFormat::RGBA8 && GLES) { | ||||
|                     // because GLES does not have ABGR format
 | ||||
|                     // so we will do byteswapping here
 | ||||
|                     tile_ptr[0] = gl_ptr[3]; | ||||
|                     tile_ptr[1] = gl_ptr[2]; | ||||
|                     tile_ptr[2] = gl_ptr[1]; | ||||
|                     tile_ptr[3] = gl_ptr[0]; | ||||
|                 } else if (format == PixelFormat::RGB8 && GLES) { | ||||
|                     tile_ptr[0] = gl_ptr[2]; | ||||
|                     tile_ptr[1] = gl_ptr[1]; | ||||
|                     tile_ptr[2] = gl_ptr[0]; | ||||
|                 } else { | ||||
|                     std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template <bool morton_to_gl, PixelFormat format> | ||||
| static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr start, PAddr end) { | ||||
|     constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; | ||||
|     constexpr u32 tile_size = bytes_per_pixel * 64; | ||||
| 
 | ||||
|     constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); | ||||
|     static_assert(gl_bytes_per_pixel >= bytes_per_pixel, ""); | ||||
|     gl_buffer += gl_bytes_per_pixel - bytes_per_pixel; | ||||
| 
 | ||||
|     const PAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size); | ||||
|     const PAddr aligned_start = base + Common::AlignUp(start - base, tile_size); | ||||
|     const PAddr aligned_end = base + Common::AlignDown(end - base, tile_size); | ||||
| 
 | ||||
|     ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end)); | ||||
| 
 | ||||
|     const u32 begin_pixel_index = (aligned_down_start - base) / bytes_per_pixel; | ||||
|     u32 x = (begin_pixel_index % (stride * 8)) / 8; | ||||
|     u32 y = (begin_pixel_index / (stride * 8)) * 8; | ||||
| 
 | ||||
|     gl_buffer += ((height - 8 - y) * stride + x) * gl_bytes_per_pixel; | ||||
| 
 | ||||
|     auto glbuf_next_tile = [&] { | ||||
|         x = (x + 8) % stride; | ||||
|         gl_buffer += 8 * gl_bytes_per_pixel; | ||||
|         if (!x) { | ||||
|             y += 8; | ||||
|             gl_buffer -= stride * 9 * gl_bytes_per_pixel; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     u8* tile_buffer = VideoCore::g_memory->GetPhysicalPointer(start); | ||||
| 
 | ||||
|     if (start < aligned_start && !morton_to_gl) { | ||||
|         std::array<u8, tile_size> tmp_buf; | ||||
|         MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer); | ||||
|         std::memcpy(tile_buffer, &tmp_buf[start - aligned_down_start], | ||||
|                     std::min(aligned_start, end) - start); | ||||
| 
 | ||||
|         tile_buffer += aligned_start - start; | ||||
|         glbuf_next_tile(); | ||||
|     } | ||||
| 
 | ||||
|     const u8* const buffer_end = tile_buffer + aligned_end - aligned_start; | ||||
|     PAddr current_paddr = aligned_start; | ||||
|     while (tile_buffer < buffer_end) { | ||||
|         // Pokemon Super Mystery Dungeon will try to use textures that go beyond
 | ||||
|         // the end address of VRAM. Stop reading if reaches invalid address
 | ||||
|         if (!VideoCore::g_memory->IsValidPhysicalAddress(current_paddr) || | ||||
|             !VideoCore::g_memory->IsValidPhysicalAddress(current_paddr + tile_size)) { | ||||
|             LOG_ERROR(Render_OpenGL, "Out of bound texture"); | ||||
|             break; | ||||
|         } | ||||
|         MortonCopyTile<morton_to_gl, format>(stride, tile_buffer, gl_buffer); | ||||
|         tile_buffer += tile_size; | ||||
|         current_paddr += tile_size; | ||||
|         glbuf_next_tile(); | ||||
|     } | ||||
| 
 | ||||
|     if (end > std::max(aligned_start, aligned_end) && !morton_to_gl) { | ||||
|         std::array<u8, tile_size> tmp_buf; | ||||
|         MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer); | ||||
|         std::memcpy(tile_buffer, &tmp_buf[0], end - aligned_end); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> morton_to_gl_fns = { | ||||
|     MortonCopy<true, PixelFormat::RGBA8>,  // 0
 | ||||
|     MortonCopy<true, PixelFormat::RGB8>,   // 1
 | ||||
|     MortonCopy<true, PixelFormat::RGB5A1>, // 2
 | ||||
|     MortonCopy<true, PixelFormat::RGB565>, // 3
 | ||||
|     MortonCopy<true, PixelFormat::RGBA4>,  // 4
 | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr,                             // 5 - 13
 | ||||
|     MortonCopy<true, PixelFormat::D16>,  // 14
 | ||||
|     nullptr,                             // 15
 | ||||
|     MortonCopy<true, PixelFormat::D24>,  // 16
 | ||||
|     MortonCopy<true, PixelFormat::D24S8> // 17
 | ||||
| }; | ||||
| 
 | ||||
| static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl_to_morton_fns = { | ||||
|     MortonCopy<false, PixelFormat::RGBA8>,  // 0
 | ||||
|     MortonCopy<false, PixelFormat::RGB8>,   // 1
 | ||||
|     MortonCopy<false, PixelFormat::RGB5A1>, // 2
 | ||||
|     MortonCopy<false, PixelFormat::RGB565>, // 3
 | ||||
|     MortonCopy<false, PixelFormat::RGBA4>,  // 4
 | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr, | ||||
|     nullptr,                              // 5 - 13
 | ||||
|     MortonCopy<false, PixelFormat::D16>,  // 14
 | ||||
|     nullptr,                              // 15
 | ||||
|     MortonCopy<false, PixelFormat::D24>,  // 16
 | ||||
|     MortonCopy<false, PixelFormat::D24S8> // 17
 | ||||
| }; | ||||
| 
 | ||||
| // Allocate an uninitialized texture of appropriate size and format for the surface
 | ||||
| OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& format_tuple, u32 width, | ||||
|                                                          u32 height) { | ||||
|  | @ -264,7 +101,7 @@ OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& form | |||
| 
 | ||||
|     if (GL_ARB_texture_storage) { | ||||
|         // Allocate all possible mipmap levels upfront
 | ||||
|         auto levels = std::log2(std::max(width, height)) + 1; | ||||
|         const GLsizei levels = std::log2(std::max(width, height)) + 1; | ||||
|         glTexStorage2D(GL_TEXTURE_2D, levels, format_tuple.internal_format, width, height); | ||||
|     } else { | ||||
|         glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0, | ||||
|  | @ -293,7 +130,7 @@ static void AllocateTextureCube(GLuint texture, const FormatTuple& format_tuple, | |||
|     glActiveTexture(TextureUnits::TextureCube.Enum()); | ||||
|     if (GL_ARB_texture_storage) { | ||||
|         // Allocate all possible mipmap levels in case the game uses them later
 | ||||
|         auto levels = std::log2(width) + 1; | ||||
|         const GLsizei levels = std::log2(width) + 1; | ||||
|         glTexStorage2D(GL_TEXTURE_CUBE_MAP, levels, format_tuple.internal_format, width, width); | ||||
|     } else { | ||||
|         for (auto faces : { | ||||
|  | @ -418,10 +255,10 @@ static bool FillSurface(const Surface& surface, const u8* fill_data, | |||
|         u32 value_32bit = 0; | ||||
|         GLfloat value_float; | ||||
| 
 | ||||
|         if (surface->pixel_format == SurfaceParams::PixelFormat::D16) { | ||||
|         if (surface->pixel_format == PixelFormat::D16) { | ||||
|             std::memcpy(&value_32bit, fill_data, 2); | ||||
|             value_float = value_32bit / 65535.0f; // 2^16 - 1
 | ||||
|         } else if (surface->pixel_format == SurfaceParams::PixelFormat::D24) { | ||||
|         } else if (surface->pixel_format == PixelFormat::D24) { | ||||
|             std::memcpy(&value_32bit, fill_data, 3); | ||||
|             value_float = value_32bit / 16777215.0f; // 2^24 - 1
 | ||||
|         } | ||||
|  | @ -545,7 +382,7 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { | |||
|         return; | ||||
| 
 | ||||
|     if (gl_buffer.empty()) { | ||||
|         gl_buffer.resize(width * height * GetGLBytesPerPixel(pixel_format)); | ||||
|         gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format)); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Should probably be done in ::Memory:: and check for other regions too
 | ||||
|  | @ -617,7 +454,7 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { | |||
|     if (dst_buffer == nullptr) | ||||
|         return; | ||||
| 
 | ||||
|     ASSERT(gl_buffer.size() == width * height * GetGLBytesPerPixel(pixel_format)); | ||||
|     ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format)); | ||||
| 
 | ||||
|     // TODO: Should probably be done in ::Memory:: and check for other regions too
 | ||||
|     // same as loadglbuffer()
 | ||||
|  | @ -771,7 +608,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_ | |||
| 
 | ||||
|     MICROPROFILE_SCOPE(OpenGL_TextureUL); | ||||
| 
 | ||||
|     ASSERT(gl_buffer.size() == width * height * GetGLBytesPerPixel(pixel_format)); | ||||
|     ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format)); | ||||
| 
 | ||||
|     u64 tex_hash = 0; | ||||
| 
 | ||||
|  | @ -786,7 +623,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_ | |||
|     // Load data from memory to the surface
 | ||||
|     GLint x0 = static_cast<GLint>(rect.left); | ||||
|     GLint y0 = static_cast<GLint>(rect.bottom); | ||||
|     std::size_t buffer_offset = (y0 * stride + x0) * GetGLBytesPerPixel(pixel_format); | ||||
|     std::size_t buffer_offset = (y0 * stride + x0) * GetBytesPerPixel(pixel_format); | ||||
| 
 | ||||
|     const FormatTuple& tuple = GetFormatTuple(pixel_format); | ||||
|     GLuint target_tex = texture.handle; | ||||
|  | @ -814,7 +651,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_ | |||
|     cur_state.Apply(); | ||||
| 
 | ||||
|     // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
 | ||||
|     ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0); | ||||
|     ASSERT(stride * GetBytesPerPixel(pixel_format) % 4 == 0); | ||||
|     if (is_custom) { | ||||
|         if (res_scale == 1) { | ||||
|             texture = owner.AllocateSurfaceTexture(GetFormatTuple(PixelFormat::RGBA8), | ||||
|  | @ -873,7 +710,7 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint | |||
|     MICROPROFILE_SCOPE(OpenGL_TextureDL); | ||||
| 
 | ||||
|     if (gl_buffer.empty()) { | ||||
|         gl_buffer.resize(width * height * GetGLBytesPerPixel(pixel_format)); | ||||
|         gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format)); | ||||
|     } | ||||
| 
 | ||||
|     OpenGLState state = OpenGLState::GetCurState(); | ||||
|  | @ -883,10 +720,10 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint | |||
|     const FormatTuple& tuple = GetFormatTuple(pixel_format); | ||||
| 
 | ||||
|     // Ensure no bad interactions with GL_PACK_ALIGNMENT
 | ||||
|     ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0); | ||||
|     ASSERT(stride * GetBytesPerPixel(pixel_format) % 4 == 0); | ||||
|     glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(stride)); | ||||
|     std::size_t buffer_offset = | ||||
|         (rect.bottom * stride + rect.left) * GetGLBytesPerPixel(pixel_format); | ||||
|         (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 (res_scale != 1) { | ||||
|  | @ -1084,7 +921,7 @@ bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface, | |||
|                                          const Common::Rectangle<u32>& dst_rect) { | ||||
|     MICROPROFILE_SCOPE(OpenGL_BlitSurface); | ||||
| 
 | ||||
|     if (!SurfaceParams::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) | ||||
|     if (!CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) | ||||
|         return false; | ||||
| 
 | ||||
|     dst_surface->InvalidateAllWatcher(); | ||||
|  | @ -1239,7 +1076,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInf | |||
|     params.width = info.width; | ||||
|     params.height = info.height; | ||||
|     params.is_tiled = true; | ||||
|     params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(info.format); | ||||
|     params.pixel_format = PixelFormatFromTextureFormat(info.format); | ||||
|     params.res_scale = texture_filterer->IsNull() ? 1 : resolution_scale_factor; | ||||
|     params.UpdateParams(); | ||||
| 
 | ||||
|  | @ -1411,7 +1248,7 @@ const CachedTextureCube& RasterizerCacheOpenGL::GetTextureCube(const TextureCube | |||
|         cube.texture.Create(); | ||||
|         AllocateTextureCube( | ||||
|             cube.texture.handle, | ||||
|             GetFormatTuple(CachedSurface::PixelFormatFromTextureFormat(config.format)), | ||||
|             GetFormatTuple(PixelFormatFromTextureFormat(config.format)), | ||||
|             cube.res_scale * config.width); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1459,7 +1296,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | |||
|     const auto& config = regs.framebuffer.framebuffer; | ||||
| 
 | ||||
|     // update resolution_scale_factor and reset cache if changed
 | ||||
|     if ((resolution_scale_factor != VideoCore::GetResolutionScaleFactor()) | | ||||
|     if ((resolution_scale_factor != VideoCore::GetResolutionScaleFactor()) || | ||||
|         (VideoCore::g_texture_filter_update_requested.exchange(false) && | ||||
|          texture_filterer->Reset(Settings::values.texture_filter_name, resolution_scale_factor))) { | ||||
|         resolution_scale_factor = VideoCore::GetResolutionScaleFactor(); | ||||
|  | @ -1485,11 +1322,11 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | |||
|     SurfaceParams depth_params = color_params; | ||||
| 
 | ||||
|     color_params.addr = config.GetColorBufferPhysicalAddress(); | ||||
|     color_params.pixel_format = SurfaceParams::PixelFormatFromColorFormat(config.color_format); | ||||
|     color_params.pixel_format = PixelFormatFromColorFormat(config.color_format); | ||||
|     color_params.UpdateParams(); | ||||
| 
 | ||||
|     depth_params.addr = config.GetDepthBufferPhysicalAddress(); | ||||
|     depth_params.pixel_format = SurfaceParams::PixelFormatFromDepthFormat(config.depth_format); | ||||
|     depth_params.pixel_format = PixelFormatFromDepthFormat(config.depth_format); | ||||
|     depth_params.UpdateParams(); | ||||
| 
 | ||||
|     auto color_vp_interval = color_params.GetSubRectInterval(viewport_clamped); | ||||
|  | @ -1693,7 +1530,7 @@ bool RasterizerCacheOpenGL::NoUnimplementedReinterpretations(const Surface& surf | |||
|     }; | ||||
|     bool implemented = true; | ||||
|     for (PixelFormat format : all_formats) { | ||||
|         if (SurfaceParams::GetFormatBpp(format) == surface->GetFormatBpp()) { | ||||
|         if (GetFormatBpp(format) == surface->GetFormatBpp()) { | ||||
|             params.pixel_format = format; | ||||
|             // This could potentially be expensive,
 | ||||
|             // although experimentally it hasn't been too bad
 | ||||
|  | @ -1701,8 +1538,8 @@ bool RasterizerCacheOpenGL::NoUnimplementedReinterpretations(const Surface& surf | |||
|                 FindMatch<MatchFlags::Copy>(surface_cache, params, ScaleMatch::Ignore, interval); | ||||
|             if (test_surface != nullptr) { | ||||
|                 LOG_WARNING(Render_OpenGL, "Missing pixel_format reinterpreter: {} -> {}", | ||||
|                             SurfaceParams::PixelFormatAsString(format), | ||||
|                             SurfaceParams::PixelFormatAsString(surface->pixel_format)); | ||||
|                             PixelFormatAsString(format), | ||||
|                             PixelFormatAsString(surface->pixel_format)); | ||||
|                 implemented = false; | ||||
|             } | ||||
|         } | ||||
|  | @ -1751,9 +1588,8 @@ bool RasterizerCacheOpenGL::ValidateByReinterpretation(const Surface& surface, | |||
|                 reinterpreter->second->Reinterpret(reinterpret_surface->texture.handle, src_rect, | ||||
|                                                    read_framebuffer.handle, tmp_tex.handle, | ||||
|                                                    tmp_rect, draw_framebuffer.handle); | ||||
|                 SurfaceParams::SurfaceType type = | ||||
|                     SurfaceParams::GetFormatType(reinterpreter->first.dst_format); | ||||
| 
 | ||||
|                 const SurfaceType type = GetFormatType(reinterpreter->first.dst_format); | ||||
|                 if (!texture_filterer->Filter(tmp_tex.handle, tmp_rect, surface->texture.handle, | ||||
|                                               dest_rect, type, read_framebuffer.handle, | ||||
|                                               draw_framebuffer.handle)) { | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ struct FormatTuple { | |||
| 
 | ||||
| constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; | ||||
| 
 | ||||
| const FormatTuple& GetFormatTuple(SurfaceParams::PixelFormat pixel_format); | ||||
| const FormatTuple& GetFormatTuple(PixelFormat pixel_format); | ||||
| 
 | ||||
| struct HostTextureTag { | ||||
|     FormatTuple format_tuple; | ||||
|  | @ -205,15 +205,6 @@ struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface | |||
|     bool is_custom = false; | ||||
|     Core::CustomTexInfo custom_tex_info; | ||||
| 
 | ||||
|     static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) { | ||||
|         // OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type
 | ||||
|         return format == PixelFormat::Invalid | ||||
|                    ? 0 | ||||
|                    : (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture) | ||||
|                          ? 4 | ||||
|                          : SurfaceParams::GetFormatBpp(format) / 8; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<u8> gl_buffer; | ||||
| 
 | ||||
|     // Read/Write data in 3DS memory to/from gl_buffer
 | ||||
|  |  | |||
|  | @ -12,10 +12,11 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { | |||
|     SurfaceParams params = *this; | ||||
|     const u32 tiled_size = is_tiled ? 8 : 1; | ||||
|     const u32 stride_tiled_bytes = BytesInPixels(stride * tiled_size); | ||||
| 
 | ||||
|     PAddr aligned_start = | ||||
|         addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes); | ||||
|             addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes); | ||||
|     PAddr aligned_end = | ||||
|         addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes); | ||||
|             addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes); | ||||
| 
 | ||||
|     if (aligned_end - aligned_start > stride_tiled_bytes) { | ||||
|         params.addr = aligned_start; | ||||
|  | @ -24,17 +25,19 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { | |||
|         // 1 row
 | ||||
|         ASSERT(aligned_end - aligned_start == stride_tiled_bytes); | ||||
|         const u32 tiled_alignment = BytesInPixels(is_tiled ? 8 * 8 : 1); | ||||
| 
 | ||||
|         aligned_start = | ||||
|             addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment); | ||||
|                 addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment); | ||||
|         aligned_end = | ||||
|             addr + Common::AlignUp(boost::icl::last_next(interval) - addr, tiled_alignment); | ||||
|                 addr + Common::AlignUp(boost::icl::last_next(interval) - addr, tiled_alignment); | ||||
| 
 | ||||
|         params.addr = aligned_start; | ||||
|         params.width = PixelsInBytes(aligned_end - aligned_start) / tiled_size; | ||||
|         params.stride = params.width; | ||||
|         params.height = tiled_size; | ||||
|     } | ||||
|     params.UpdateParams(); | ||||
| 
 | ||||
|     params.UpdateParams(); | ||||
|     return params; | ||||
| } | ||||
| 
 | ||||
|  | @ -158,6 +161,7 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const { | |||
|         end < texcopy_params.end) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (texcopy_params.width != texcopy_params.stride) { | ||||
|         const u32 tile_stride = BytesInPixels(stride * (is_tiled ? 8 : 1)); | ||||
|         return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 && | ||||
|  | @ -165,6 +169,7 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const { | |||
|                (texcopy_params.height == 1 || texcopy_params.stride == tile_stride) && | ||||
|                ((texcopy_params.addr - addr) % tile_stride) + texcopy_params.width <= tile_stride; | ||||
|     } | ||||
| 
 | ||||
|     return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,11 +7,8 @@ | |||
| #include <array> | ||||
| #include <climits> | ||||
| #include <boost/icl/interval.hpp> | ||||
| #include "common/assert.h" | ||||
| #include "common/math_util.h" | ||||
| #include "core/hw/gpu.h" | ||||
| #include "video_core/regs_framebuffer.h" | ||||
| #include "video_core/regs_texturing.h" | ||||
| #include "video_core/rasterizer_cache/pixel_format.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
|  | @ -21,180 +18,8 @@ using Surface = std::shared_ptr<CachedSurface>; | |||
| using SurfaceInterval = boost::icl::right_open_interval<PAddr>; | ||||
| 
 | ||||
| struct SurfaceParams { | ||||
| private: | ||||
|     static constexpr std::array<unsigned int, 18> BPP_TABLE = { | ||||
|         32, // RGBA8
 | ||||
|         24, // RGB8
 | ||||
|         16, // RGB5A1
 | ||||
|         16, // RGB565
 | ||||
|         16, // RGBA4
 | ||||
|         16, // IA8
 | ||||
|         16, // RG8
 | ||||
|         8,  // I8
 | ||||
|         8,  // A8
 | ||||
|         8,  // IA4
 | ||||
|         4,  // I4
 | ||||
|         4,  // A4
 | ||||
|         4,  // ETC1
 | ||||
|         8,  // ETC1A4
 | ||||
|         16, // D16
 | ||||
|         0, | ||||
|         24, // D24
 | ||||
|         32, // D24S8
 | ||||
|     }; | ||||
| 
 | ||||
| public: | ||||
|     enum class PixelFormat { | ||||
|         // First 5 formats are shared between textures and color buffers
 | ||||
|         RGBA8 = 0, | ||||
|         RGB8 = 1, | ||||
|         RGB5A1 = 2, | ||||
|         RGB565 = 3, | ||||
|         RGBA4 = 4, | ||||
| 
 | ||||
|         // Texture-only formats
 | ||||
|         IA8 = 5, | ||||
|         RG8 = 6, | ||||
|         I8 = 7, | ||||
|         A8 = 8, | ||||
|         IA4 = 9, | ||||
|         I4 = 10, | ||||
|         A4 = 11, | ||||
|         ETC1 = 12, | ||||
|         ETC1A4 = 13, | ||||
| 
 | ||||
|         // Depth buffer-only formats
 | ||||
|         D16 = 14, | ||||
|         // gap
 | ||||
|         D24 = 16, | ||||
|         D24S8 = 17, | ||||
| 
 | ||||
|         Invalid = 255, | ||||
|     }; | ||||
| 
 | ||||
|     enum class SurfaceType { | ||||
|         Color = 0, | ||||
|         Texture = 1, | ||||
|         Depth = 2, | ||||
|         DepthStencil = 3, | ||||
|         Fill = 4, | ||||
|         Invalid = 5 | ||||
|     }; | ||||
| 
 | ||||
|     static constexpr unsigned int GetFormatBpp(PixelFormat format) { | ||||
|         const auto format_idx = static_cast<std::size_t>(format); | ||||
|         DEBUG_ASSERT_MSG(format_idx < BPP_TABLE.size(), "Invalid pixel format {}", format_idx); | ||||
|         return BPP_TABLE[format_idx]; | ||||
|     } | ||||
| 
 | ||||
|     unsigned int GetFormatBpp() const { | ||||
|         return GetFormatBpp(pixel_format); | ||||
|     } | ||||
| 
 | ||||
|     static std::string_view PixelFormatAsString(PixelFormat format) { | ||||
|         switch (format) { | ||||
|         case PixelFormat::RGBA8: | ||||
|             return "RGBA8"; | ||||
|         case PixelFormat::RGB8: | ||||
|             return "RGB8"; | ||||
|         case PixelFormat::RGB5A1: | ||||
|             return "RGB5A1"; | ||||
|         case PixelFormat::RGB565: | ||||
|             return "RGB565"; | ||||
|         case PixelFormat::RGBA4: | ||||
|             return "RGBA4"; | ||||
|         case PixelFormat::IA8: | ||||
|             return "IA8"; | ||||
|         case PixelFormat::RG8: | ||||
|             return "RG8"; | ||||
|         case PixelFormat::I8: | ||||
|             return "I8"; | ||||
|         case PixelFormat::A8: | ||||
|             return "A8"; | ||||
|         case PixelFormat::IA4: | ||||
|             return "IA4"; | ||||
|         case PixelFormat::I4: | ||||
|             return "I4"; | ||||
|         case PixelFormat::A4: | ||||
|             return "A4"; | ||||
|         case PixelFormat::ETC1: | ||||
|             return "ETC1"; | ||||
|         case PixelFormat::ETC1A4: | ||||
|             return "ETC1A4"; | ||||
|         case PixelFormat::D16: | ||||
|             return "D16"; | ||||
|         case PixelFormat::D24: | ||||
|             return "D24"; | ||||
|         case PixelFormat::D24S8: | ||||
|             return "D24S8"; | ||||
|         default: | ||||
|             return "Not a real pixel format"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) { | ||||
|         return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) { | ||||
|         return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) { | ||||
|         return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) | ||||
|                                           : PixelFormat::Invalid; | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) { | ||||
|         switch (format) { | ||||
|         // RGB565 and RGB5A1 are switched in PixelFormat compared to ColorFormat
 | ||||
|         case GPU::Regs::PixelFormat::RGB565: | ||||
|             return PixelFormat::RGB565; | ||||
|         case GPU::Regs::PixelFormat::RGB5A1: | ||||
|             return PixelFormat::RGB5A1; | ||||
|         default: | ||||
|             return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { | ||||
|         SurfaceType a_type = GetFormatType(pixel_format_a); | ||||
|         SurfaceType b_type = GetFormatType(pixel_format_b); | ||||
| 
 | ||||
|         if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && | ||||
|             (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         if (a_type == SurfaceType::Depth && b_type == SurfaceType::Depth) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         if (a_type == SurfaceType::DepthStencil && b_type == SurfaceType::DepthStencil) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) { | ||||
|         if ((unsigned int)pixel_format < 5) { | ||||
|             return SurfaceType::Color; | ||||
|         } | ||||
| 
 | ||||
|         if ((unsigned int)pixel_format < 14) { | ||||
|             return SurfaceType::Texture; | ||||
|         } | ||||
| 
 | ||||
|         if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) { | ||||
|             return SurfaceType::Depth; | ||||
|         } | ||||
| 
 | ||||
|         if (pixel_format == PixelFormat::D24S8) { | ||||
|             return SurfaceType::DepthStencil; | ||||
|         } | ||||
| 
 | ||||
|         return SurfaceType::Invalid; | ||||
|         return OpenGL::GetFormatBpp(pixel_format); | ||||
|     } | ||||
| 
 | ||||
|     /// Update the params "size", "end" and "type" from the already set "addr", "width", "height"
 | ||||
|  | @ -238,11 +63,11 @@ public: | |||
|     } | ||||
| 
 | ||||
|     u32 PixelsInBytes(u32 size) const { | ||||
|         return size * CHAR_BIT / GetFormatBpp(pixel_format); | ||||
|         return size * 8 / GetFormatBpp(); | ||||
|     } | ||||
| 
 | ||||
|     u32 BytesInPixels(u32 pixels) const { | ||||
|         return pixels * GetFormatBpp(pixel_format) / CHAR_BIT; | ||||
|         return pixels * GetFormatBpp() / 8; | ||||
|     } | ||||
| 
 | ||||
|     bool ExactMatch(const SurfaceParams& other_surface) const; | ||||
|  |  | |||
|  | @ -12,8 +12,6 @@ | |||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| using PixelFormat = SurfaceParams::PixelFormat; | ||||
| 
 | ||||
| class RGBA4toRGB5A1 final : public FormatReinterpreterBase { | ||||
| public: | ||||
|     RGBA4toRGB5A1() { | ||||
|  |  | |||
|  | @ -9,27 +9,27 @@ | |||
| #include <glad/glad.h> | ||||
| #include "common/common_types.h" | ||||
| #include "common/math_util.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/rasterizer_cache/surface_params.h" | ||||
| #include "video_core/rasterizer_cache/pixel_format.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| class RasterizerCacheOpenGL; | ||||
| 
 | ||||
| struct PixelFormatPair { | ||||
|     const SurfaceParams::PixelFormat dst_format, src_format; | ||||
|     const PixelFormat dst_format, src_format; | ||||
| 
 | ||||
|     struct less { | ||||
|         using is_transparent = void; | ||||
|         constexpr bool operator()(OpenGL::PixelFormatPair lhs, OpenGL::PixelFormatPair rhs) const { | ||||
|         constexpr bool operator()(PixelFormatPair lhs, PixelFormatPair rhs) const { | ||||
|             return std::tie(lhs.dst_format, lhs.src_format) < | ||||
|                    std::tie(rhs.dst_format, rhs.src_format); | ||||
|         } | ||||
|         constexpr bool operator()(OpenGL::SurfaceParams::PixelFormat lhs, | ||||
|                                   OpenGL::PixelFormatPair rhs) const { | ||||
| 
 | ||||
|         constexpr bool operator()(PixelFormat lhs, PixelFormatPair rhs) const { | ||||
|             return lhs < rhs.dst_format; | ||||
|         } | ||||
|         constexpr bool operator()(OpenGL::PixelFormatPair lhs, | ||||
|                                   OpenGL::SurfaceParams::PixelFormat rhs) const { | ||||
| 
 | ||||
|         constexpr bool operator()(PixelFormatPair lhs, PixelFormat rhs) const { | ||||
|             return lhs.dst_format < rhs; | ||||
|         } | ||||
|     }; | ||||
|  | @ -52,8 +52,8 @@ public: | |||
|     explicit FormatReinterpreterOpenGL(); | ||||
|     ~FormatReinterpreterOpenGL(); | ||||
| 
 | ||||
|     std::pair<ReinterpreterMap::iterator, ReinterpreterMap::iterator> GetPossibleReinterpretations( | ||||
|         SurfaceParams::PixelFormat dst_format); | ||||
|     auto GetPossibleReinterpretations(PixelFormat dst_format) -> | ||||
|     std::pair<ReinterpreterMap::iterator, ReinterpreterMap::iterator>; | ||||
| 
 | ||||
| private: | ||||
|     ReinterpreterMap reinterpreters; | ||||
|  |  | |||
|  | @ -29,9 +29,6 @@ | |||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| using PixelFormat = SurfaceParams::PixelFormat; | ||||
| using SurfaceType = SurfaceParams::SurfaceType; | ||||
| 
 | ||||
| MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(255, 128, 0)); | ||||
| MICROPROFILE_DEFINE(OpenGL_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(192, 128, 128)); | ||||
| MICROPROFILE_DEFINE(OpenGL_GS, "OpenGL", "Geometry Shader Setup", MP_RGB(128, 192, 128)); | ||||
|  | @ -1445,7 +1442,7 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe | |||
|     src_params.stride = config.input_width; | ||||
|     src_params.height = config.output_height; | ||||
|     src_params.is_tiled = !config.input_linear; | ||||
|     src_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.input_format); | ||||
|     src_params.pixel_format = PixelFormatFromGPUPixelFormat(config.input_format); | ||||
|     src_params.UpdateParams(); | ||||
| 
 | ||||
|     SurfaceParams dst_params; | ||||
|  | @ -1455,7 +1452,7 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe | |||
|     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 = SurfaceParams::PixelFormatFromGPUPixelFormat(config.output_format); | ||||
|     dst_params.pixel_format = PixelFormatFromGPUPixelFormat(config.output_format); | ||||
|     dst_params.UpdateParams(); | ||||
| 
 | ||||
|     Common::Rectangle<u32> src_rect; | ||||
|  | @ -1595,7 +1592,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con | |||
|     src_params.height = config.height; | ||||
|     src_params.stride = pixel_stride; | ||||
|     src_params.is_tiled = false; | ||||
|     src_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.color_format); | ||||
|     src_params.pixel_format = PixelFormatFromGPUPixelFormat(config.color_format); | ||||
|     src_params.UpdateParams(); | ||||
| 
 | ||||
|     Common::Rectangle<u32> src_rect; | ||||
|  |  | |||
|  | @ -4,9 +4,9 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <glad/glad.h> | ||||
| #include "common/common_types.h" | ||||
| #include "common/math_util.h" | ||||
| #include "video_core/rasterizer_cache/surface_params.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
|  |  | |||
|  | @ -60,12 +60,13 @@ bool TextureFilterer::IsNull() const { | |||
| 
 | ||||
| bool TextureFilterer::Filter(GLuint src_tex, const Common::Rectangle<u32>& src_rect, GLuint dst_tex, | ||||
|                              const Common::Rectangle<u32>& dst_rect, | ||||
|                              SurfaceParams::SurfaceType type, GLuint read_fb_handle, | ||||
|                              SurfaceType type, GLuint read_fb_handle, | ||||
|                              GLuint draw_fb_handle) { | ||||
|     // depth / stencil texture filtering is not supported for now
 | ||||
|     if (IsNull() || | ||||
|         (type != SurfaceParams::SurfaceType::Color && type != SurfaceParams::SurfaceType::Texture)) | ||||
|     if (IsNull() || (type != SurfaceType::Color && type != SurfaceType::Texture)) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     filter->Filter(src_tex, src_rect, dst_tex, dst_rect, read_fb_handle, draw_fb_handle); | ||||
|     return true; | ||||
| } | ||||
|  | @ -85,4 +86,4 @@ std::vector<std::string_view> TextureFilterer::GetFilterNames() { | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| } // namespace OpenGL
 | ||||
| } // namespace OpenGL
 | ||||
|  |  | |||
|  | @ -7,9 +7,7 @@ | |||
| #include <memory> | ||||
| #include <string_view> | ||||
| #include <vector> | ||||
| #include <glad/glad.h> | ||||
| #include "common/common_types.h" | ||||
| #include "common/math_util.h" | ||||
| #include "video_core/rasterizer_cache/pixel_format.h" | ||||
| #include "video_core/renderer_opengl/texture_filters/texture_filter_base.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
|  | @ -25,7 +23,7 @@ public: | |||
|     bool IsNull() const; | ||||
|     // returns true if the texture was able to be filtered
 | ||||
|     bool Filter(GLuint src_tex, const Common::Rectangle<u32>& src_rect, GLuint dst_tex, | ||||
|                 const Common::Rectangle<u32>& dst_rect, SurfaceParams::SurfaceType type, | ||||
|                 const Common::Rectangle<u32>& dst_rect, SurfaceType type, | ||||
|                 GLuint read_fb_handle, GLuint draw_fb_handle); | ||||
| 
 | ||||
|     static std::vector<std::string_view> GetFilterNames(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue