decoders.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cmath>
  5. #include <cstring>
  6. #include "common/assert.h"
  7. #include "core/memory.h"
  8. #include "video_core/gpu.h"
  9. #include "video_core/textures/decoders.h"
  10. #include "video_core/textures/texture.h"
  11. namespace Tegra::Texture {
  12. /**
  13. * Calculates the offset of an (x, y) position within a swizzled texture.
  14. * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
  15. */
  16. static u32 GetSwizzleOffset(u32 x, u32 y, u32 bytes_per_pixel, u32 gob_address) {
  17. // Round up to the next gob
  18. x *= bytes_per_pixel;
  19. u32 address = gob_address + ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
  20. (y % 2) * 16 + (x % 16);
  21. return address;
  22. }
  23. void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
  24. u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) {
  25. std::array<u8*, 2> data_ptrs;
  26. const u32 stride = width * bytes_per_pixel;
  27. const u32 gobs_in_x = 64;
  28. const u32 gobs_in_y = 8;
  29. const u32 gobs_size = gobs_in_x * gobs_in_y;
  30. const u32 image_width_in_gobs{(stride + gobs_in_x - 1) / gobs_in_x};
  31. for (unsigned y = 0; y < height; ++y) {
  32. const u32 gob_y_address =
  33. (y / (gobs_in_y * block_height)) * gobs_size * block_height * image_width_in_gobs +
  34. (y % (gobs_in_y * block_height) / gobs_in_y) * gobs_size;
  35. for (unsigned x = 0; x < width; ++x) {
  36. const u32 gob_address =
  37. gob_y_address + (x * bytes_per_pixel / gobs_in_x) * gobs_size * block_height;
  38. const u32 swizzle_offset = GetSwizzleOffset(x, y, bytes_per_pixel, gob_address);
  39. const u32 pixel_index = (x + y * width) * out_bytes_per_pixel;
  40. data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
  41. data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
  42. std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
  43. }
  44. }
  45. }
  46. // This table represents the internal swizzle of a gob.
  47. template <std::size_t N, std::size_t M>
  48. struct alignas(64) SwizzleTable {
  49. constexpr SwizzleTable() {
  50. for (u32 y = 0; y < N; ++y) {
  51. for (u32 x = 0; x < M; ++x) {
  52. const u32 x2 = x * 16;
  53. values[y][x] = static_cast<u16>(((x2 % 64) / 32) * 256 + ((y % 8) / 2) * 64 +
  54. ((x2 % 32) / 16) * 32 + (y % 2) * 16);
  55. }
  56. }
  57. }
  58. const std::array<u16, M>& operator[](std::size_t index) const {
  59. return values[index];
  60. }
  61. std::array<std::array<u16, M>, N> values{};
  62. };
  63. constexpr auto swizzle_table = SwizzleTable<8, 4>();
  64. void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, u8* swizzled_data,
  65. u8* unswizzled_data, bool unswizzle, u32 block_height) {
  66. std::array<u8*, 2> data_ptrs;
  67. const std::size_t stride{width * bytes_per_pixel};
  68. const std::size_t gobs_in_x = 64;
  69. const std::size_t gobs_in_y = 8;
  70. const std::size_t gobs_size = gobs_in_x * gobs_in_y;
  71. const std::size_t image_width_in_gobs{(stride + gobs_in_x - 1) / gobs_in_x};
  72. const std::size_t copy_size{16};
  73. for (std::size_t y = 0; y < height; ++y) {
  74. const std::size_t initial_gob =
  75. (y / (gobs_in_y * block_height)) * gobs_size * block_height * image_width_in_gobs +
  76. (y % (gobs_in_y * block_height) / gobs_in_y) * gobs_size;
  77. const std::size_t pixel_base{y * width * out_bytes_per_pixel};
  78. const auto& table = swizzle_table[y % gobs_in_y];
  79. for (std::size_t xb = 0; xb < stride; xb += copy_size) {
  80. const std::size_t truncated_copy = std::min(copy_size, stride - xb);
  81. const std::size_t gob_address{initial_gob +
  82. (xb / gobs_in_x) * gobs_size * block_height};
  83. const std::size_t swizzle_offset{gob_address + table[(xb / 16) % 4]};
  84. const std::size_t out_x = xb*out_bytes_per_pixel / bytes_per_pixel;
  85. const std::size_t pixel_index{out_x + pixel_base};
  86. data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
  87. data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
  88. std::memcpy(data_ptrs[0], data_ptrs[1], truncated_copy);
  89. }
  90. }
  91. }
  92. u32 BytesPerPixel(TextureFormat format) {
  93. switch (format) {
  94. case TextureFormat::DXT1:
  95. case TextureFormat::DXN1:
  96. // In this case a 'pixel' actually refers to a 4x4 tile.
  97. return 8;
  98. case TextureFormat::DXT23:
  99. case TextureFormat::DXT45:
  100. case TextureFormat::DXN2:
  101. case TextureFormat::BC7U:
  102. case TextureFormat::BC6H_UF16:
  103. case TextureFormat::BC6H_SF16:
  104. // In this case a 'pixel' actually refers to a 4x4 tile.
  105. return 16;
  106. case TextureFormat::R32_G32_B32:
  107. return 12;
  108. case TextureFormat::ASTC_2D_4X4:
  109. case TextureFormat::ASTC_2D_8X8:
  110. case TextureFormat::A8R8G8B8:
  111. case TextureFormat::A2B10G10R10:
  112. case TextureFormat::BF10GF11RF11:
  113. case TextureFormat::R32:
  114. case TextureFormat::R16_G16:
  115. return 4;
  116. case TextureFormat::A1B5G5R5:
  117. case TextureFormat::B5G6R5:
  118. case TextureFormat::G8R8:
  119. case TextureFormat::R16:
  120. return 2;
  121. case TextureFormat::R8:
  122. return 1;
  123. case TextureFormat::R16_G16_B16_A16:
  124. return 8;
  125. case TextureFormat::R32_G32_B32_A32:
  126. return 16;
  127. case TextureFormat::R32_G32:
  128. return 8;
  129. default:
  130. UNIMPLEMENTED_MSG("Format not implemented");
  131. break;
  132. }
  133. }
  134. std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
  135. u32 height, u32 block_height) {
  136. std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
  137. if (bytes_per_pixel % 3 != 0) {
  138. FastSwizzleData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
  139. Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
  140. } else {
  141. CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
  142. Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
  143. }
  144. return unswizzled_data;
  145. }
  146. std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width,
  147. u32 height) {
  148. std::vector<u8> rgba_data;
  149. // TODO(Subv): Implement.
  150. switch (format) {
  151. case TextureFormat::DXT1:
  152. case TextureFormat::DXT23:
  153. case TextureFormat::DXT45:
  154. case TextureFormat::DXN1:
  155. case TextureFormat::DXN2:
  156. case TextureFormat::BC7U:
  157. case TextureFormat::BC6H_UF16:
  158. case TextureFormat::BC6H_SF16:
  159. case TextureFormat::ASTC_2D_4X4:
  160. case TextureFormat::ASTC_2D_8X8:
  161. case TextureFormat::A8R8G8B8:
  162. case TextureFormat::A2B10G10R10:
  163. case TextureFormat::A1B5G5R5:
  164. case TextureFormat::B5G6R5:
  165. case TextureFormat::R8:
  166. case TextureFormat::G8R8:
  167. case TextureFormat::BF10GF11RF11:
  168. case TextureFormat::R32_G32_B32_A32:
  169. case TextureFormat::R32_G32:
  170. case TextureFormat::R32:
  171. case TextureFormat::R16:
  172. case TextureFormat::R16_G16:
  173. case TextureFormat::R32_G32_B32:
  174. // TODO(Subv): For the time being just forward the same data without any decoding.
  175. rgba_data = texture_data;
  176. break;
  177. default:
  178. UNIMPLEMENTED_MSG("Format not implemented");
  179. break;
  180. }
  181. return rgba_data;
  182. }
  183. } // namespace Tegra::Texture