TextureInfo.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. // Copyright 2021 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoCommon/TextureInfo.h"
  4. #include <span>
  5. #include <fmt/format.h>
  6. #include <xxhash.h>
  7. #include "Common/Align.h"
  8. #include "Common/Assert.h"
  9. #include "Common/Logging/Log.h"
  10. #include "Common/SpanUtils.h"
  11. #include "Core/HW/Memmap.h"
  12. #include "Core/System.h"
  13. #include "VideoCommon/BPMemory.h"
  14. #include "VideoCommon/TextureDecoder.h"
  15. TextureInfo TextureInfo::FromStage(u32 stage)
  16. {
  17. const auto tex = bpmem.tex.GetUnit(stage);
  18. const auto texture_format = tex.texImage0.format;
  19. const auto tlut_format = tex.texTlut.tlut_format;
  20. const auto width = tex.texImage0.width + 1;
  21. const auto height = tex.texImage0.height + 1;
  22. const u32 address = (tex.texImage3.image_base /* & 0x1FFFFF*/) << 5;
  23. const u32 tlutaddr = tex.texTlut.tmem_offset << 9;
  24. std::span<const u8> tlut_data = TexDecoder_GetTmemSpan(tlutaddr);
  25. std::optional<u32> mip_count;
  26. const bool has_mipmaps = tex.texMode0.mipmap_filter != MipMode::None;
  27. if (has_mipmaps)
  28. {
  29. mip_count = (tex.texMode1.max_lod + 0xf) / 0x10;
  30. }
  31. const bool from_tmem = tex.texImage1.cache_manually_managed != 0;
  32. const u32 tmem_address_even = from_tmem ? tex.texImage1.tmem_even * TMEM_LINE_SIZE : 0;
  33. const u32 tmem_address_odd = from_tmem ? tex.texImage2.tmem_odd * TMEM_LINE_SIZE : 0;
  34. if (from_tmem)
  35. {
  36. return TextureInfo(stage, TexDecoder_GetTmemSpan(tmem_address_even), tlut_data, address,
  37. texture_format, tlut_format, width, height, true,
  38. TexDecoder_GetTmemSpan(tmem_address_odd),
  39. TexDecoder_GetTmemSpan(tmem_address_even), mip_count);
  40. }
  41. auto& system = Core::System::GetInstance();
  42. auto& memory = system.GetMemory();
  43. return TextureInfo(stage, memory.GetSpanForAddress(address), tlut_data, address, texture_format,
  44. tlut_format, width, height, false, {}, {}, mip_count);
  45. }
  46. TextureInfo::TextureInfo(u32 stage, std::span<const u8> data, std::span<const u8> tlut_data,
  47. u32 address, TextureFormat texture_format, TLUTFormat tlut_format,
  48. u32 width, u32 height, bool from_tmem, std::span<const u8> tmem_odd,
  49. std::span<const u8> tmem_even, std::optional<u32> mip_count)
  50. : m_ptr(data.data()), m_tlut_ptr(tlut_data.data()), m_address(address), m_from_tmem(from_tmem),
  51. m_tmem_odd(tmem_odd.data()), m_texture_format(texture_format), m_tlut_format(tlut_format),
  52. m_raw_width(width), m_raw_height(height), m_stage(stage)
  53. {
  54. const bool is_palette_texture = IsColorIndexed(m_texture_format);
  55. if (is_palette_texture)
  56. m_palette_size = TexDecoder_GetPaletteSize(m_texture_format);
  57. // TexelSizeInNibbles(format) * width * height / 16;
  58. m_block_width = TexDecoder_GetBlockWidthInTexels(m_texture_format);
  59. m_block_height = TexDecoder_GetBlockHeightInTexels(m_texture_format);
  60. m_expanded_width = Common::AlignUp(m_raw_width, m_block_width);
  61. m_expanded_height = Common::AlignUp(m_raw_height, m_block_height);
  62. m_texture_size =
  63. TexDecoder_GetTextureSizeInBytes(m_expanded_width, m_expanded_height, m_texture_format);
  64. if (data.size() < m_texture_size)
  65. {
  66. ERROR_LOG_FMT(VIDEO, "Trying to use an invalid texture address {:#010x}", GetRawAddress());
  67. m_data_valid = false;
  68. }
  69. else if (m_palette_size && tlut_data.size() < *m_palette_size)
  70. {
  71. ERROR_LOG_FMT(VIDEO, "Trying to use an invalid TLUT address {:#010x}", GetRawAddress());
  72. m_data_valid = false;
  73. }
  74. else
  75. {
  76. m_data_valid = true;
  77. }
  78. if (mip_count)
  79. {
  80. m_mipmaps_enabled = true;
  81. const u32 raw_mip_count = *mip_count;
  82. // GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in
  83. // the mipmap chain
  84. // e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so
  85. // we limit the mipmap count to 6 there
  86. const u32 limited_mip_count =
  87. std::min<u32>(MathUtil::IntLog2(std::max(width, height)) + 1, raw_mip_count + 1) - 1;
  88. // load mips
  89. std::span<const u8> src_data = Common::SafeSubspan(data, GetTextureSize());
  90. tmem_even = Common::SafeSubspan(tmem_even, GetTextureSize());
  91. for (u32 i = 0; i < limited_mip_count; i++)
  92. {
  93. MipLevel mip_level(i + 1, *this, m_from_tmem, &src_data, &tmem_even, &tmem_odd);
  94. if (!mip_level.IsDataValid())
  95. {
  96. ERROR_LOG_FMT(VIDEO, "Trying to use an invalid mipmap address {:#010x}", GetRawAddress());
  97. break;
  98. }
  99. m_mip_levels.push_back(std::move(mip_level));
  100. }
  101. }
  102. }
  103. std::string TextureInfo::NameDetails::GetFullName() const
  104. {
  105. return fmt::format("{}_{}{}_{}", base_name, texture_name, tlut_name, format_name);
  106. }
  107. TextureInfo::NameDetails TextureInfo::CalculateTextureName() const
  108. {
  109. if (!IsDataValid())
  110. return NameDetails{};
  111. const u8* tlut = m_tlut_ptr;
  112. size_t tlut_size = m_palette_size ? *m_palette_size : 0;
  113. // checking for min/max on paletted textures
  114. u32 min = 0xffff;
  115. u32 max = 0;
  116. switch (tlut_size)
  117. {
  118. case 0:
  119. break;
  120. case 16 * 2:
  121. for (size_t i = 0; i < m_texture_size; i++)
  122. {
  123. const u32 low_nibble = m_ptr[i] & 0xf;
  124. const u32 high_nibble = m_ptr[i] >> 4;
  125. min = std::min({min, low_nibble, high_nibble});
  126. max = std::max({max, low_nibble, high_nibble});
  127. }
  128. break;
  129. case 256 * 2:
  130. for (size_t i = 0; i < m_texture_size; i++)
  131. {
  132. const u32 texture_byte = m_ptr[i];
  133. min = std::min(min, texture_byte);
  134. max = std::max(max, texture_byte);
  135. }
  136. break;
  137. case 16384 * 2:
  138. for (size_t i = 0; i < m_texture_size; i += sizeof(u16))
  139. {
  140. const u32 texture_halfword = Common::swap16(m_ptr[i]) & 0x3fff;
  141. min = std::min(min, texture_halfword);
  142. max = std::max(max, texture_halfword);
  143. }
  144. break;
  145. }
  146. if (tlut_size > 0)
  147. {
  148. tlut_size = 2 * (max + 1 - min);
  149. tlut += 2 * min;
  150. }
  151. DEBUG_ASSERT(tlut_size <= m_palette_size.value_or(0));
  152. const u64 tex_hash = XXH64(m_ptr, m_texture_size, 0);
  153. const u64 tlut_hash = tlut_size ? XXH64(tlut, tlut_size, 0) : 0;
  154. NameDetails result;
  155. result.base_name = fmt::format("{}{}x{}{}", format_prefix, m_raw_width, m_raw_height,
  156. m_mipmaps_enabled ? "_m" : "");
  157. result.texture_name = fmt::format("{:016x}", tex_hash);
  158. result.tlut_name = tlut_size ? fmt::format("_{:016x}", tlut_hash) : "";
  159. result.format_name = fmt::to_string(static_cast<int>(m_texture_format));
  160. return result;
  161. }
  162. bool TextureInfo::IsDataValid() const
  163. {
  164. return m_data_valid;
  165. }
  166. const u8* TextureInfo::GetData() const
  167. {
  168. return m_ptr;
  169. }
  170. const u8* TextureInfo::GetTlutAddress() const
  171. {
  172. return m_tlut_ptr;
  173. }
  174. u32 TextureInfo::GetRawAddress() const
  175. {
  176. return m_address;
  177. }
  178. bool TextureInfo::IsFromTmem() const
  179. {
  180. return m_from_tmem;
  181. }
  182. const u8* TextureInfo::GetTmemOddAddress() const
  183. {
  184. return m_tmem_odd;
  185. }
  186. TextureFormat TextureInfo::GetTextureFormat() const
  187. {
  188. return m_texture_format;
  189. }
  190. TLUTFormat TextureInfo::GetTlutFormat() const
  191. {
  192. return m_tlut_format;
  193. }
  194. std::optional<u32> TextureInfo::GetPaletteSize() const
  195. {
  196. return m_palette_size;
  197. }
  198. u32 TextureInfo::GetTextureSize() const
  199. {
  200. return m_texture_size;
  201. }
  202. u32 TextureInfo::GetBlockWidth() const
  203. {
  204. return m_block_width;
  205. }
  206. u32 TextureInfo::GetBlockHeight() const
  207. {
  208. return m_block_height;
  209. }
  210. u32 TextureInfo::GetExpandedWidth() const
  211. {
  212. return m_expanded_width;
  213. }
  214. u32 TextureInfo::GetExpandedHeight() const
  215. {
  216. return m_expanded_height;
  217. }
  218. u32 TextureInfo::GetRawWidth() const
  219. {
  220. return m_raw_width;
  221. }
  222. u32 TextureInfo::GetRawHeight() const
  223. {
  224. return m_raw_height;
  225. }
  226. u32 TextureInfo::GetStage() const
  227. {
  228. return m_stage;
  229. }
  230. bool TextureInfo::HasMipMaps() const
  231. {
  232. return !m_mip_levels.empty();
  233. }
  234. u32 TextureInfo::GetLevelCount() const
  235. {
  236. return static_cast<u32>(m_mip_levels.size()) + 1;
  237. }
  238. const TextureInfo::MipLevel* TextureInfo::GetMipMapLevel(u32 level) const
  239. {
  240. if (level < m_mip_levels.size())
  241. return &m_mip_levels[level];
  242. return nullptr;
  243. }
  244. TextureInfo::MipLevel::MipLevel(u32 level, const TextureInfo& parent, bool from_tmem,
  245. std::span<const u8>* src_data, std::span<const u8>* tmem_even,
  246. std::span<const u8>* tmem_odd)
  247. {
  248. m_raw_width = std::max(parent.GetRawWidth() >> level, 1u);
  249. m_raw_height = std::max(parent.GetRawHeight() >> level, 1u);
  250. m_expanded_width = Common::AlignUp(m_raw_width, parent.GetBlockWidth());
  251. m_expanded_height = Common::AlignUp(m_raw_height, parent.GetBlockHeight());
  252. m_texture_size = TexDecoder_GetTextureSizeInBytes(m_expanded_width, m_expanded_height,
  253. parent.GetTextureFormat());
  254. std::span<const u8>* data = from_tmem ? ((level % 2) ? tmem_odd : tmem_even) : src_data;
  255. m_ptr = data->data();
  256. m_data_valid = data->size() >= m_texture_size;
  257. *data = Common::SafeSubspan(*data, m_texture_size);
  258. }
  259. u32 TextureInfo::GetFullLevelSize() const
  260. {
  261. u32 all_mips_size = 0;
  262. for (const auto& mip_map : m_mip_levels)
  263. {
  264. all_mips_size += mip_map.GetTextureSize();
  265. }
  266. return m_texture_size + all_mips_size;
  267. }
  268. bool TextureInfo::MipLevel::IsDataValid() const
  269. {
  270. return m_data_valid;
  271. }
  272. const u8* TextureInfo::MipLevel::GetData() const
  273. {
  274. return m_ptr;
  275. }
  276. u32 TextureInfo::MipLevel::GetTextureSize() const
  277. {
  278. return m_texture_size;
  279. }
  280. u32 TextureInfo::MipLevel::GetExpandedWidth() const
  281. {
  282. return m_expanded_width;
  283. }
  284. u32 TextureInfo::MipLevel::GetExpandedHeight() const
  285. {
  286. return m_expanded_height;
  287. }
  288. u32 TextureInfo::MipLevel::GetRawWidth() const
  289. {
  290. return m_raw_width;
  291. }
  292. u32 TextureInfo::MipLevel::GetRawHeight() const
  293. {
  294. return m_raw_height;
  295. }