diff options
Diffstat (limited to 'src/video_core/textures/bcn.cpp')
| -rw-r--r-- | src/video_core/textures/bcn.cpp | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/video_core/textures/bcn.cpp b/src/video_core/textures/bcn.cpp new file mode 100644 index 000000000..671212a49 --- /dev/null +++ b/src/video_core/textures/bcn.cpp | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <stb_dxt.h> | ||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | #include "common/alignment.h" | ||
| 8 | #include "video_core/textures/bcn.h" | ||
| 9 | #include "video_core/textures/workers.h" | ||
| 10 | |||
| 11 | namespace Tegra::Texture::BCN { | ||
| 12 | |||
| 13 | using BCNCompressor = void(u8* block_output, const u8* block_input, bool any_alpha); | ||
| 14 | |||
| 15 | template <u32 BytesPerBlock, bool ThresholdAlpha = false> | ||
| 16 | void CompressBCN(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, | ||
| 17 | std::span<uint8_t> output, BCNCompressor f) { | ||
| 18 | constexpr u8 alpha_threshold = 128; | ||
| 19 | constexpr u32 bytes_per_px = 4; | ||
| 20 | const u32 plane_dim = width * height; | ||
| 21 | |||
| 22 | Common::ThreadWorker& workers{GetThreadWorkers()}; | ||
| 23 | |||
| 24 | for (u32 z = 0; z < depth; z++) { | ||
| 25 | for (u32 y = 0; y < height; y += 4) { | ||
| 26 | auto compress_row = [z, y, width, height, plane_dim, f, data, output]() { | ||
| 27 | for (u32 x = 0; x < width; x += 4) { | ||
| 28 | // Gather 4x4 block of RGBA texels | ||
| 29 | u8 input_colors[4][4][4]; | ||
| 30 | bool any_alpha = false; | ||
| 31 | |||
| 32 | for (u32 j = 0; j < 4; j++) { | ||
| 33 | for (u32 i = 0; i < 4; i++) { | ||
| 34 | const size_t coord = | ||
| 35 | (z * plane_dim + (y + j) * width + (x + i)) * bytes_per_px; | ||
| 36 | |||
| 37 | if ((x + i < width) && (y + j < height)) { | ||
| 38 | if constexpr (ThresholdAlpha) { | ||
| 39 | if (data[coord + 3] >= alpha_threshold) { | ||
| 40 | input_colors[j][i][0] = data[coord + 0]; | ||
| 41 | input_colors[j][i][1] = data[coord + 1]; | ||
| 42 | input_colors[j][i][2] = data[coord + 2]; | ||
| 43 | input_colors[j][i][3] = 255; | ||
| 44 | } else { | ||
| 45 | any_alpha = true; | ||
| 46 | memset(input_colors[j][i], 0, bytes_per_px); | ||
| 47 | } | ||
| 48 | } else { | ||
| 49 | memcpy(input_colors[j][i], &data[coord], bytes_per_px); | ||
| 50 | } | ||
| 51 | } else { | ||
| 52 | memset(input_colors[j][i], 0, bytes_per_px); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | const u32 bytes_per_row = BytesPerBlock * Common::DivideUp(width, 4U); | ||
| 58 | const u32 bytes_per_plane = bytes_per_row * Common::DivideUp(height, 4U); | ||
| 59 | f(output.data() + z * bytes_per_plane + (y / 4) * bytes_per_row + | ||
| 60 | (x / 4) * BytesPerBlock, | ||
| 61 | reinterpret_cast<u8*>(input_colors), any_alpha); | ||
| 62 | } | ||
| 63 | }; | ||
| 64 | workers.QueueWork(std::move(compress_row)); | ||
| 65 | } | ||
| 66 | workers.WaitForRequests(); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | void CompressBC1(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, | ||
| 71 | std::span<uint8_t> output) { | ||
| 72 | CompressBCN<8, true>(data, width, height, depth, output, | ||
| 73 | [](u8* block_output, const u8* block_input, bool any_alpha) { | ||
| 74 | stb_compress_bc1_block(block_output, block_input, any_alpha, | ||
| 75 | STB_DXT_NORMAL); | ||
| 76 | }); | ||
| 77 | } | ||
| 78 | |||
| 79 | void CompressBC3(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, | ||
| 80 | std::span<uint8_t> output) { | ||
| 81 | CompressBCN<16, false>(data, width, height, depth, output, | ||
| 82 | [](u8* block_output, const u8* block_input, bool any_alpha) { | ||
| 83 | stb_compress_bc3_block(block_output, block_input, STB_DXT_NORMAL); | ||
| 84 | }); | ||
| 85 | } | ||
| 86 | |||
| 87 | } // namespace Tegra::Texture::BCN | ||