summaryrefslogtreecommitdiff
path: root/src/video_core/texture_cache
diff options
context:
space:
mode:
authorGravatar GPUCode2023-06-06 23:10:06 +0300
committerGravatar bunnei2023-06-27 18:00:09 -0700
commiteac46ad7ceca5e35b396a8b80bfc38dc6ef1a4fe (patch)
tree761e98947d8e26a6409e24befa99cd127f67458d /src/video_core/texture_cache
parentrenderer_vulkan: Add more feature checking (diff)
downloadyuzu-eac46ad7ceca5e35b396a8b80bfc38dc6ef1a4fe.tar.gz
yuzu-eac46ad7ceca5e35b396a8b80bfc38dc6ef1a4fe.tar.xz
yuzu-eac46ad7ceca5e35b396a8b80bfc38dc6ef1a4fe.zip
video_core: Add BCn decoding support
Diffstat (limited to 'src/video_core/texture_cache')
-rw-r--r--src/video_core/texture_cache/decode_bc.cpp129
-rw-r--r--src/video_core/texture_cache/decode_bc.h (renamed from src/video_core/texture_cache/decode_bc4.h)6
-rw-r--r--src/video_core/texture_cache/decode_bc4.cpp96
-rw-r--r--src/video_core/texture_cache/util.cpp24
4 files changed, 149 insertions, 106 deletions
diff --git a/src/video_core/texture_cache/decode_bc.cpp b/src/video_core/texture_cache/decode_bc.cpp
new file mode 100644
index 000000000..3e26474a3
--- /dev/null
+++ b/src/video_core/texture_cache/decode_bc.cpp
@@ -0,0 +1,129 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include <span>
7#include <bc_decoder.h>
8
9#include "common/common_types.h"
10#include "video_core/texture_cache/decode_bc.h"
11
12namespace VideoCommon {
13
14namespace {
15constexpr u32 BLOCK_SIZE = 4;
16
17using VideoCore::Surface::PixelFormat;
18
19constexpr bool IsSigned(PixelFormat pixel_format) {
20 switch (pixel_format) {
21 case PixelFormat::BC4_SNORM:
22 case PixelFormat::BC4_UNORM:
23 case PixelFormat::BC5_SNORM:
24 case PixelFormat::BC5_UNORM:
25 case PixelFormat::BC6H_SFLOAT:
26 case PixelFormat::BC6H_UFLOAT:
27 return true;
28 default:
29 return false;
30 }
31}
32
33constexpr u32 BlockSize(PixelFormat pixel_format) {
34 switch (pixel_format) {
35 case PixelFormat::BC1_RGBA_SRGB:
36 case PixelFormat::BC1_RGBA_UNORM:
37 case PixelFormat::BC4_SNORM:
38 case PixelFormat::BC4_UNORM:
39 return 8;
40 default:
41 return 16;
42 }
43}
44} // Anonymous namespace
45
46u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
47 switch (pixel_format) {
48 case PixelFormat::BC4_SNORM:
49 case PixelFormat::BC4_UNORM:
50 return 1;
51 case PixelFormat::BC5_SNORM:
52 case PixelFormat::BC5_UNORM:
53 return 2;
54 case PixelFormat::BC6H_SFLOAT:
55 case PixelFormat::BC6H_UFLOAT:
56 return 8;
57 default:
58 return 4;
59 }
60}
61
62template <auto decompress, PixelFormat pixel_format>
63void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent,
64 bool is_signed = false) {
65 const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
66 const u32 block_width = std::min(extent.width, BLOCK_SIZE);
67 const u32 block_height = std::min(extent.height, BLOCK_SIZE);
68 const u32 pitch = extent.width * out_bpp;
69 size_t input_offset = 0;
70 size_t output_offset = 0;
71 for (u32 slice = 0; slice < extent.depth; ++slice) {
72 for (u32 y = 0; y < extent.height; y += block_height) {
73 size_t row_offset = 0;
74 for (u32 x = 0; x < extent.width;
75 x += block_width, row_offset += block_width * out_bpp) {
76 const u8* src = input.data() + input_offset;
77 u8* const dst = output.data() + output_offset + row_offset;
78 if constexpr (IsSigned(pixel_format)) {
79 decompress(src, dst, x, y, extent.width, extent.height, is_signed);
80 } else {
81 decompress(src, dst, x, y, extent.width, extent.height);
82 }
83 input_offset += BlockSize(pixel_format);
84 }
85 output_offset += block_height * pitch;
86 }
87 }
88}
89
90void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
91 VideoCore::Surface::PixelFormat pixel_format) {
92 switch (pixel_format) {
93 case PixelFormat::BC1_RGBA_UNORM:
94 case PixelFormat::BC1_RGBA_SRGB:
95 DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent);
96 break;
97 case PixelFormat::BC2_UNORM:
98 case PixelFormat::BC2_SRGB:
99 DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent);
100 break;
101 case PixelFormat::BC3_UNORM:
102 case PixelFormat::BC3_SRGB:
103 DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent);
104 break;
105 case PixelFormat::BC4_SNORM:
106 case PixelFormat::BC4_UNORM:
107 DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
108 input, output, extent, pixel_format == PixelFormat::BC4_SNORM);
109 break;
110 case PixelFormat::BC5_SNORM:
111 case PixelFormat::BC5_UNORM:
112 DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
113 input, output, extent, pixel_format == PixelFormat::BC5_SNORM);
114 break;
115 case PixelFormat::BC6H_SFLOAT:
116 case PixelFormat::BC6H_UFLOAT:
117 DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
118 input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT);
119 break;
120 case PixelFormat::BC7_SRGB:
121 case PixelFormat::BC7_UNORM:
122 DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent);
123 break;
124 default:
125 LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
126 }
127}
128
129} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/decode_bc4.h b/src/video_core/texture_cache/decode_bc.h
index ab2f735be..41d1ec0a3 100644
--- a/src/video_core/texture_cache/decode_bc4.h
+++ b/src/video_core/texture_cache/decode_bc.h
@@ -6,10 +6,14 @@
6#include <span> 6#include <span>
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "video_core/surface.h"
9#include "video_core/texture_cache/types.h" 10#include "video_core/texture_cache/types.h"
10 11
11namespace VideoCommon { 12namespace VideoCommon {
12 13
13void DecompressBC4(std::span<const u8> data, Extent3D extent, std::span<u8> output); 14[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
15
16void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
17 VideoCore::Surface::PixelFormat pixel_format);
14 18
15} // namespace VideoCommon 19} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/decode_bc4.cpp b/src/video_core/texture_cache/decode_bc4.cpp
deleted file mode 100644
index ef98afdca..000000000
--- a/src/video_core/texture_cache/decode_bc4.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include <span>
7
8#include "common/assert.h"
9#include "common/common_types.h"
10#include "video_core/texture_cache/decode_bc4.h"
11#include "video_core/texture_cache/types.h"
12
13namespace VideoCommon {
14
15// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt
16[[nodiscard]] constexpr u32 DecompressBlock(u64 bits, u32 x, u32 y) {
17 const u32 code_offset = 16 + 3 * (4 * y + x);
18 const u32 code = (bits >> code_offset) & 7;
19 const u32 red0 = (bits >> 0) & 0xff;
20 const u32 red1 = (bits >> 8) & 0xff;
21 if (red0 > red1) {
22 switch (code) {
23 case 0:
24 return red0;
25 case 1:
26 return red1;
27 case 2:
28 return (6 * red0 + 1 * red1) / 7;
29 case 3:
30 return (5 * red0 + 2 * red1) / 7;
31 case 4:
32 return (4 * red0 + 3 * red1) / 7;
33 case 5:
34 return (3 * red0 + 4 * red1) / 7;
35 case 6:
36 return (2 * red0 + 5 * red1) / 7;
37 case 7:
38 return (1 * red0 + 6 * red1) / 7;
39 }
40 } else {
41 switch (code) {
42 case 0:
43 return red0;
44 case 1:
45 return red1;
46 case 2:
47 return (4 * red0 + 1 * red1) / 5;
48 case 3:
49 return (3 * red0 + 2 * red1) / 5;
50 case 4:
51 return (2 * red0 + 3 * red1) / 5;
52 case 5:
53 return (1 * red0 + 4 * red1) / 5;
54 case 6:
55 return 0;
56 case 7:
57 return 0xff;
58 }
59 }
60 return 0;
61}
62
63void DecompressBC4(std::span<const u8> input, Extent3D extent, std::span<u8> output) {
64 UNIMPLEMENTED_IF_MSG(extent.width % 4 != 0, "Unaligned width={}", extent.width);
65 UNIMPLEMENTED_IF_MSG(extent.height % 4 != 0, "Unaligned height={}", extent.height);
66 static constexpr u32 BLOCK_SIZE = 4;
67 size_t input_offset = 0;
68 for (u32 slice = 0; slice < extent.depth; ++slice) {
69 for (u32 block_y = 0; block_y < extent.height / 4; ++block_y) {
70 for (u32 block_x = 0; block_x < extent.width / 4; ++block_x) {
71 u64 bits;
72 std::memcpy(&bits, &input[input_offset], sizeof(bits));
73 input_offset += sizeof(bits);
74
75 for (u32 y = 0; y < BLOCK_SIZE; ++y) {
76 for (u32 x = 0; x < BLOCK_SIZE; ++x) {
77 const u32 linear_z = slice;
78 const u32 linear_y = block_y * BLOCK_SIZE + y;
79 const u32 linear_x = block_x * BLOCK_SIZE + x;
80 const u32 offset_z = linear_z * extent.width * extent.height;
81 const u32 offset_y = linear_y * extent.width;
82 const u32 offset_x = linear_x;
83 const u32 output_offset = (offset_z + offset_y + offset_x) * 4ULL;
84 const u32 color = DecompressBlock(bits, x, y);
85 output[output_offset + 0] = static_cast<u8>(color);
86 output[output_offset + 1] = 0;
87 output[output_offset + 2] = 0;
88 output[output_offset + 3] = 0xff;
89 }
90 }
91 }
92 }
93 }
94}
95
96} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index f781cb7a0..9a618a57a 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -24,7 +24,7 @@
24#include "video_core/engines/maxwell_3d.h" 24#include "video_core/engines/maxwell_3d.h"
25#include "video_core/memory_manager.h" 25#include "video_core/memory_manager.h"
26#include "video_core/surface.h" 26#include "video_core/surface.h"
27#include "video_core/texture_cache/decode_bc4.h" 27#include "video_core/texture_cache/decode_bc.h"
28#include "video_core/texture_cache/format_lookup_table.h" 28#include "video_core/texture_cache/format_lookup_table.h"
29#include "video_core/texture_cache/formatter.h" 29#include "video_core/texture_cache/formatter.h"
30#include "video_core/texture_cache/samples_helper.h" 30#include "video_core/texture_cache/samples_helper.h"
@@ -61,8 +61,6 @@ using VideoCore::Surface::PixelFormatFromDepthFormat;
61using VideoCore::Surface::PixelFormatFromRenderTargetFormat; 61using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
62using VideoCore::Surface::SurfaceType; 62using VideoCore::Surface::SurfaceType;
63 63
64constexpr u32 CONVERTED_BYTES_PER_BLOCK = BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
65
66struct LevelInfo { 64struct LevelInfo {
67 Extent3D size; 65 Extent3D size;
68 Extent3D block; 66 Extent3D block;
@@ -612,7 +610,8 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept {
612 } 610 }
613 return output_size; 611 return output_size;
614 } 612 }
615 return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * CONVERTED_BYTES_PER_BLOCK; 613 return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers *
614 ConvertedBytesPerBlock(info.format);
616} 615}
617 616
618u32 CalculateLayerStride(const ImageInfo& info) noexcept { 617u32 CalculateLayerStride(const ImageInfo& info) noexcept {
@@ -945,7 +944,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
945 tile_size.height, output.subspan(output_offset)); 944 tile_size.height, output.subspan(output_offset));
946 945
947 output_offset += copy.image_extent.width * copy.image_extent.height * 946 output_offset += copy.image_extent.width * copy.image_extent.height *
948 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 947 copy.image_subresource.num_layers *
948 BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
949 } else if (astc) { 949 } else if (astc) {
950 // BC1 uses 0.5 bytes per texel 950 // BC1 uses 0.5 bytes per texel
951 // BC3 uses 1 byte per texel 951 // BC3 uses 1 byte per texel
@@ -956,7 +956,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
956 956
957 const u32 plane_dim = copy.image_extent.width * copy.image_extent.height; 957 const u32 plane_dim = copy.image_extent.width * copy.image_extent.height;
958 const u32 level_size = plane_dim * copy.image_extent.depth * 958 const u32 level_size = plane_dim * copy.image_extent.depth *
959 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 959 copy.image_subresource.num_layers *
960 BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
960 decode_scratch.resize_destructive(level_size); 961 decode_scratch.resize_destructive(level_size);
961 962
962 Tegra::Texture::ASTC::Decompress( 963 Tegra::Texture::ASTC::Decompress(
@@ -976,10 +977,15 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
976 bpp_div; 977 bpp_div;
977 output_offset += static_cast<u32>(copy.buffer_size); 978 output_offset += static_cast<u32>(copy.buffer_size);
978 } else { 979 } else {
979 DecompressBC4(input_offset, copy.image_extent, output.subspan(output_offset)); 980 const Extent3D image_extent{
980 981 .width = copy.image_extent.width,
982 .height = copy.image_extent.height * copy.image_subresource.num_layers,
983 .depth = copy.image_extent.depth,
984 };
985 DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
981 output_offset += copy.image_extent.width * copy.image_extent.height * 986 output_offset += copy.image_extent.width * copy.image_extent.height *
982 copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; 987 copy.image_subresource.num_layers *
988 ConvertedBytesPerBlock(info.format);
983 } 989 }
984 } 990 }
985} 991}