From a0040e6fb1236be0f9bf2911e4f887dccb15a80a Mon Sep 17 00:00:00 2001 From: nastys Date: Fri, 24 Dec 2021 13:46:37 +0100 Subject: [PATCH] macOS: Implement texture converter for Metal (2) (#11289) * macOS: Implement texture converter for Metal (2) * Fix texture conversion formatting --- rpcs3/Emu/RSX/Common/TextureUtils.cpp | 160 +++++++++++++++++++++++++- rpcs3/Emu/RSX/VK/VKFormats.cpp | 20 +++- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 23 +++- rpcs3/Emu/RSX/VK/VKTextureCache.cpp | 10 +- 4 files changed, 195 insertions(+), 18 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index 3c59ab6d35..fe3c70148d 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -24,12 +24,128 @@ namespace utils namespace { +#ifndef __APPLE__ u16 convert_rgb655_to_rgb565(const u16 bits) { // g6 = g5 // r5 = (((bits & 0xFC00) >> 1) & 0xFC00) << 1 is equivalent to truncating the least significant bit return (bits & 0xF81F) | (bits & 0x3E0) << 1; } +#else +u32 convert_rgb565_to_bgra8(const u16 bits) +{ + const u8 r5 = ((bits >> 11) & 0x1F); + const u8 g6 = ((bits >> 5) & 0x3F); + const u8 b5 = (bits & 0x1F); + + const u8 b8 = ((b5 * 527) + 23) >> 6; + const u8 g8 = ((g6 * 259) + 33) >> 6; + const u8 r8 = ((r5 * 527) + 23) >> 6; + const u8 a8 = 255; + + return b8 | (g8 << 8) | (r8 << 16) | (a8 << 24); +} + +u32 convert_argb4_to_bgra8(const u16 bits) +{ + const u8 b8 = (bits & 0xF0); + const u8 g8 = ((bits >> 4) & 0xF0); + const u8 r8 = ((bits >> 8) & 0xF0); + const u8 a8 = ((bits << 4) & 0xF0); + + return b8 | (g8 << 8) | (r8 << 16) | (a8 << 24); +} + +u32 convert_a1rgb5_to_bgra8(const u16 bits) +{ + const u8 a1 = ((bits >> 11) & 0x80); + const u8 r5 = ((bits >> 10) & 0x1F); + const u8 g5 = ((bits >> 5) & 0x1F); + const u8 b5 = (bits & 0x1F); + + const u8 b8 = ((b5 * 527) + 23) >> 6; + const u8 g8 = ((g5 * 527) + 23) >> 6; + const u8 r8 = ((r5 * 527) + 23) >> 6; + const u8 a8 = a1; + + return b8 | (g8 << 8) | (r8 << 16) | (a8 << 24); +} + +u32 convert_rgb5a1_to_bgra8(const u16 bits) +{ + const u8 r5 = ((bits >> 11) & 0x1F); + const u8 g5 = ((bits >> 6) & 0x1F); + const u8 b5 = ((bits >> 1) & 0x1F); + const u8 a1 = (bits & 0x80); + + const u8 b8 = ((b5 * 527) + 23) >> 6; + const u8 g8 = ((g5 * 527) + 23) >> 6; + const u8 r8 = ((r5 * 527) + 23) >> 6; + const u8 a8 = a1; + + return b8 | (g8 << 8) | (r8 << 16) | (a8 << 24); +} + +u32 convert_rgb655_to_bgra8(const u16 bits) +{ + const u8 r6 = ((bits >> 10) & 0x3F); + const u8 g5 = ((bits >> 5) & 0x1F); + const u8 b5 = ((bits) & 0x1F); + + const u8 b8 = ((b5 * 527) + 23) >> 6; + const u8 g8 = ((g5 * 527) + 23) >> 6; + const u8 r8 = ((r6 * 259) + 33) >> 6; + const u8 a8 = 1; + + return b8 | (g8 << 8) | (r8 << 16) | (a8 << 24); +} + +u32 convert_d1rgb5_to_bgra8(const u16 bits) +{ + const u8 r5 = ((bits >> 10) & 0x1F); + const u8 g5 = ((bits >> 5) & 0x1F); + const u8 b5 = (bits & 0x1F); + + const u8 b8 = ((b5 * 527) + 23) >> 6; + const u8 g8 = ((g5 * 527) + 23) >> 6; + const u8 r8 = ((r5 * 527) + 23) >> 6; + const u8 a8 = 1; + + return b8 | (g8 << 8) | (r8 << 16) | (a8 << 24); +} + +struct convert_16_block_32 +{ + template + static void copy_mipmap_level(std::span dst, std::span src, u16 width_in_block, u16 row_count, u16 depth, u8 border, u32 dst_pitch_in_block, u32 src_pitch_in_block, u32 (*converter)(const u16)) + { + static_assert(sizeof(T) == 2, "Type size doesn't match."); + + u32 src_offset = 0, dst_offset = 0; + const u32 v_porch = src_pitch_in_block * border; + + for (int layer = 0; layer < depth; ++layer) + { + // Front + src_offset += v_porch; + + for (u32 row = 0; row < row_count; ++row) + { + for (int col = 0; col < width_in_block; ++col) + { + dst[dst_offset + col] = converter(src[src_offset + col + border]); + } + + src_offset += src_pitch_in_block; + dst_offset += dst_pitch_in_block; + } + + // Back + src_offset += v_porch; + } + } +}; +#endif struct copy_unmodified_block { @@ -692,6 +808,7 @@ namespace rsx break; } +#ifndef __APPLE__ case CELL_GCM_TEXTURE_R6G5B5: { if (is_swizzled) @@ -701,16 +818,49 @@ namespace rsx break; } - case CELL_GCM_TEXTURE_COMPRESSED_HILO8: - case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: - // TODO: Test if the HILO compressed formats support swizzling (other compressed_* formats ignore this option) - case CELL_GCM_TEXTURE_DEPTH16: - case CELL_GCM_TEXTURE_DEPTH16_FLOAT: // Untested case CELL_GCM_TEXTURE_D1R5G5B5: case CELL_GCM_TEXTURE_A1R5G5B5: case CELL_GCM_TEXTURE_A4R4G4B4: case CELL_GCM_TEXTURE_R5G5B5A1: case CELL_GCM_TEXTURE_R5G6B5: +#else + // convert the following formats to B8G8R8A8_UNORM, because they are not supported by Metal + case CELL_GCM_TEXTURE_R6G5B5: + { + convert_16_block_32::copy_mipmap_level(utils::bless(dst_buffer), utils::bless>(src_layout.data), w, h, depth, src_layout.border, get_row_pitch_in_block(w, caps.alignment), src_layout.pitch_in_block, &convert_rgb655_to_bgra8); + break; + } + case CELL_GCM_TEXTURE_D1R5G5B5: + { + convert_16_block_32::copy_mipmap_level(utils::bless(dst_buffer), utils::bless>(src_layout.data), w, h, depth, src_layout.border, get_row_pitch_in_block(w, caps.alignment), src_layout.pitch_in_block, &convert_d1rgb5_to_bgra8); + break; + } + case CELL_GCM_TEXTURE_A1R5G5B5: + { + convert_16_block_32::copy_mipmap_level(utils::bless(dst_buffer), utils::bless>(src_layout.data), w, h, depth, src_layout.border, get_row_pitch_in_block(w, caps.alignment), src_layout.pitch_in_block, &convert_a1rgb5_to_bgra8); + break; + } + case CELL_GCM_TEXTURE_A4R4G4B4: + { + convert_16_block_32::copy_mipmap_level(utils::bless(dst_buffer), utils::bless>(src_layout.data), w, h, depth, src_layout.border, get_row_pitch_in_block(w, caps.alignment), src_layout.pitch_in_block, &convert_argb4_to_bgra8); + break; + } + case CELL_GCM_TEXTURE_R5G5B5A1: + { + convert_16_block_32::copy_mipmap_level(utils::bless(dst_buffer), utils::bless>(src_layout.data), w, h, depth, src_layout.border, get_row_pitch_in_block(w, caps.alignment), src_layout.pitch_in_block, &convert_rgb5a1_to_bgra8); + break; + } + case CELL_GCM_TEXTURE_R5G6B5: + { + convert_16_block_32::copy_mipmap_level(utils::bless(dst_buffer), utils::bless>(src_layout.data), w, h, depth, src_layout.border, get_row_pitch_in_block(w, caps.alignment), src_layout.pitch_in_block, &convert_rgb565_to_bgra8); + break; + } +#endif + case CELL_GCM_TEXTURE_COMPRESSED_HILO8: + case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: + // TODO: Test if the HILO compressed formats support swizzling (other compressed_* formats ignore this option) + case CELL_GCM_TEXTURE_DEPTH16: + case CELL_GCM_TEXTURE_DEPTH16_FLOAT: // Untested case CELL_GCM_TEXTURE_G8B8: { word_size = 2; diff --git a/rpcs3/Emu/RSX/VK/VKFormats.cpp b/rpcs3/Emu/RSX/VK/VKFormats.cpp index f94cc2e2fe..6c5ee7c0a8 100644 --- a/rpcs3/Emu/RSX/VK/VKFormats.cpp +++ b/rpcs3/Emu/RSX/VK/VKFormats.cpp @@ -205,16 +205,28 @@ namespace vk { switch (format) { - case CELL_GCM_TEXTURE_B8: return VK_FORMAT_R8_UNORM; +#ifndef __APPLE__ + case CELL_GCM_TEXTURE_R5G6B5: return VK_FORMAT_R5G6B5_UNORM_PACK16; + case CELL_GCM_TEXTURE_R6G5B5: return VK_FORMAT_R5G6B5_UNORM_PACK16; // Expand, discard high bit? + case CELL_GCM_TEXTURE_R5G5B5A1: return VK_FORMAT_R5G5B5A1_UNORM_PACK16; + case CELL_GCM_TEXTURE_D1R5G5B5: return VK_FORMAT_A1R5G5B5_UNORM_PACK16; case CELL_GCM_TEXTURE_A1R5G5B5: return VK_FORMAT_A1R5G5B5_UNORM_PACK16; case CELL_GCM_TEXTURE_A4R4G4B4: return VK_FORMAT_R4G4B4A4_UNORM_PACK16; - case CELL_GCM_TEXTURE_R5G6B5: return VK_FORMAT_R5G6B5_UNORM_PACK16; +#else + // assign B8G8R8A8_UNORM to formats that are not supported by Metal + case CELL_GCM_TEXTURE_R6G5B5: return VK_FORMAT_B8G8R8A8_UNORM; + case CELL_GCM_TEXTURE_R5G6B5: return VK_FORMAT_B8G8R8A8_UNORM; + case CELL_GCM_TEXTURE_R5G5B5A1: return VK_FORMAT_B8G8R8A8_UNORM; + case CELL_GCM_TEXTURE_D1R5G5B5: return VK_FORMAT_B8G8R8A8_UNORM; + case CELL_GCM_TEXTURE_A1R5G5B5: return VK_FORMAT_B8G8R8A8_UNORM; + case CELL_GCM_TEXTURE_A4R4G4B4: return VK_FORMAT_B8G8R8A8_UNORM; +#endif + case CELL_GCM_TEXTURE_B8: return VK_FORMAT_R8_UNORM; case CELL_GCM_TEXTURE_A8R8G8B8: return VK_FORMAT_B8G8R8A8_UNORM; case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return VK_FORMAT_BC2_UNORM_BLOCK; case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return VK_FORMAT_BC3_UNORM_BLOCK; case CELL_GCM_TEXTURE_G8B8: return VK_FORMAT_R8G8_UNORM; - case CELL_GCM_TEXTURE_R6G5B5: return VK_FORMAT_R5G6B5_UNORM_PACK16; // Expand, discard high bit? case CELL_GCM_TEXTURE_DEPTH24_D8: return support.d24_unorm_s8? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT; case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: return VK_FORMAT_D32_SFLOAT_S8_UINT; case CELL_GCM_TEXTURE_DEPTH16: return VK_FORMAT_D16_UNORM; @@ -222,11 +234,9 @@ namespace vk case CELL_GCM_TEXTURE_X16: return VK_FORMAT_R16_UNORM; case CELL_GCM_TEXTURE_Y16_X16: return VK_FORMAT_R16G16_UNORM; case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return VK_FORMAT_R16G16_SFLOAT; - case CELL_GCM_TEXTURE_R5G5B5A1: return VK_FORMAT_R5G5B5A1_UNORM_PACK16; case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: return VK_FORMAT_R16G16B16A16_SFLOAT; case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: return VK_FORMAT_R32G32B32A32_SFLOAT; case CELL_GCM_TEXTURE_X32_FLOAT: return VK_FORMAT_R32_SFLOAT; - case CELL_GCM_TEXTURE_D1R5G5B5: return VK_FORMAT_A1R5G5B5_UNORM_PACK16; case CELL_GCM_TEXTURE_D8R8G8B8: return VK_FORMAT_B8G8R8A8_UNORM; case CELL_GCM_TEXTURE_COMPRESSED_HILO8: return VK_FORMAT_R8G8_UNORM; case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: return VK_FORMAT_R8G8_SNORM; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index a18b1d3dfc..c0fd46b50f 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -32,9 +32,26 @@ namespace vk switch (color_format) { +#ifndef __APPLE__ case rsx::surface_color_format::r5g6b5: return std::make_pair(VK_FORMAT_R5G6B5_UNORM_PACK16, vk::default_component_map); + case rsx::surface_color_format::x1r5g5b5_o1r5g5b5: + return std::make_pair(VK_FORMAT_A1R5G5B5_UNORM_PACK16, o_rgb); + + case rsx::surface_color_format::x1r5g5b5_z1r5g5b5: + return std::make_pair(VK_FORMAT_A1R5G5B5_UNORM_PACK16, z_rgb); +#else + // assign B8G8R8A8_UNORM to formats that are not supported by Metal + case rsx::surface_color_format::r5g6b5: + return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, vk::default_component_map); + + case rsx::surface_color_format::x1r5g5b5_o1r5g5b5: + return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, o_rgb); + + case rsx::surface_color_format::x1r5g5b5_z1r5g5b5: + return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, z_rgb); +#endif case rsx::surface_color_format::a8r8g8b8: return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, vk::default_component_map); @@ -59,12 +76,6 @@ namespace vk case rsx::surface_color_format::w32z32y32x32: return std::make_pair(VK_FORMAT_R32G32B32A32_SFLOAT, vk::default_component_map); - case rsx::surface_color_format::x1r5g5b5_o1r5g5b5: - return std::make_pair(VK_FORMAT_A1R5G5B5_UNORM_PACK16, o_rgb); - - case rsx::surface_color_format::x1r5g5b5_z1r5g5b5: - return std::make_pair(VK_FORMAT_A1R5G5B5_UNORM_PACK16, z_rgb); - case rsx::surface_color_format::b8: { const VkComponentMapping no_alpha = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }; diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp index edadd92198..cf7ecbb313 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp @@ -999,14 +999,20 @@ namespace vk //TODO warn_once("Format incompatibility detected, reporting failure to force data copy (VK_FORMAT=0x%X, GCM_FORMAT=0x%X)", static_cast(vk_format), gcm_format); return false; +#ifndef __APPLE__ + case CELL_GCM_TEXTURE_R5G6B5: + return (vk_format == VK_FORMAT_R5G6B5_UNORM_PACK16); +#else + // R5G6B5 is not supported by Metal + case CELL_GCM_TEXTURE_R5G6B5: + return (vk_format == VK_FORMAT_B8G8R8A8_UNORM); +#endif case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: return (vk_format == VK_FORMAT_R16G16B16A16_SFLOAT); case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: return (vk_format == VK_FORMAT_R32G32B32A32_SFLOAT); case CELL_GCM_TEXTURE_X32_FLOAT: return (vk_format == VK_FORMAT_R32_SFLOAT); - case CELL_GCM_TEXTURE_R5G6B5: - return (vk_format == VK_FORMAT_R5G6B5_UNORM_PACK16); case CELL_GCM_TEXTURE_A8R8G8B8: case CELL_GCM_TEXTURE_D8R8G8B8: return (vk_format == VK_FORMAT_B8G8R8A8_UNORM || vk_format == VK_FORMAT_D24_UNORM_S8_UINT || vk_format == VK_FORMAT_D32_SFLOAT_S8_UINT);