decode_bc4.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <array>
  5. #include <span>
  6. #include "common/assert.h"
  7. #include "common/common_types.h"
  8. #include "video_core/texture_cache/decode_bc4.h"
  9. #include "video_core/texture_cache/types.h"
  10. namespace VideoCommon {
  11. // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt
  12. [[nodiscard]] constexpr u32 DecompressBlock(u64 bits, u32 x, u32 y) {
  13. const u32 code_offset = 16 + 3 * (4 * y + x);
  14. const u32 code = (bits >> code_offset) & 7;
  15. const u32 red0 = (bits >> 0) & 0xff;
  16. const u32 red1 = (bits >> 8) & 0xff;
  17. if (red0 > red1) {
  18. switch (code) {
  19. case 0:
  20. return red0;
  21. case 1:
  22. return red1;
  23. case 2:
  24. return (6 * red0 + 1 * red1) / 7;
  25. case 3:
  26. return (5 * red0 + 2 * red1) / 7;
  27. case 4:
  28. return (4 * red0 + 3 * red1) / 7;
  29. case 5:
  30. return (3 * red0 + 4 * red1) / 7;
  31. case 6:
  32. return (2 * red0 + 5 * red1) / 7;
  33. case 7:
  34. return (1 * red0 + 6 * red1) / 7;
  35. }
  36. } else {
  37. switch (code) {
  38. case 0:
  39. return red0;
  40. case 1:
  41. return red1;
  42. case 2:
  43. return (4 * red0 + 1 * red1) / 5;
  44. case 3:
  45. return (3 * red0 + 2 * red1) / 5;
  46. case 4:
  47. return (2 * red0 + 3 * red1) / 5;
  48. case 5:
  49. return (1 * red0 + 4 * red1) / 5;
  50. case 6:
  51. return 0;
  52. case 7:
  53. return 0xff;
  54. }
  55. }
  56. return 0;
  57. }
  58. void DecompressBC4(std::span<const u8> input, Extent3D extent, std::span<u8> output) {
  59. UNIMPLEMENTED_IF_MSG(extent.width % 4 != 0, "Unaligned width={}", extent.width);
  60. UNIMPLEMENTED_IF_MSG(extent.height % 4 != 0, "Unaligned height={}", extent.height);
  61. static constexpr u32 BLOCK_SIZE = 4;
  62. size_t input_offset = 0;
  63. for (u32 slice = 0; slice < extent.depth; ++slice) {
  64. for (u32 block_y = 0; block_y < extent.height / 4; ++block_y) {
  65. for (u32 block_x = 0; block_x < extent.width / 4; ++block_x) {
  66. u64 bits;
  67. std::memcpy(&bits, &input[input_offset], sizeof(bits));
  68. input_offset += sizeof(bits);
  69. for (u32 y = 0; y < BLOCK_SIZE; ++y) {
  70. for (u32 x = 0; x < BLOCK_SIZE; ++x) {
  71. const u32 linear_z = slice;
  72. const u32 linear_y = block_y * BLOCK_SIZE + y;
  73. const u32 linear_x = block_x * BLOCK_SIZE + x;
  74. const u32 offset_z = linear_z * extent.width * extent.height;
  75. const u32 offset_y = linear_y * extent.width;
  76. const u32 offset_x = linear_x;
  77. const u32 output_offset = (offset_z + offset_y + offset_x) * 4ULL;
  78. const u32 color = DecompressBlock(bits, x, y);
  79. output[output_offset + 0] = static_cast<u8>(color);
  80. output[output_offset + 1] = 0;
  81. output[output_offset + 2] = 0;
  82. output[output_offset + 3] = 0xff;
  83. }
  84. }
  85. }
  86. }
  87. }
  88. }
  89. } // namespace VideoCommon