decode_bc4.cpp 3.3 KB

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