texture_cache.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/alignment.h"
  5. #include "common/assert.h"
  6. #include "common/cityhash.h"
  7. #include "common/common_types.h"
  8. #include "core/core.h"
  9. #include "video_core/surface.h"
  10. #include "video_core/texture_cache.h"
  11. #include "video_core/textures/decoders.h"
  12. #include "video_core/textures/texture.h"
  13. namespace VideoCommon {
  14. using VideoCore::Surface::SurfaceTarget;
  15. using VideoCore::Surface::ComponentTypeFromDepthFormat;
  16. using VideoCore::Surface::ComponentTypeFromRenderTarget;
  17. using VideoCore::Surface::ComponentTypeFromTexture;
  18. using VideoCore::Surface::PixelFormatFromDepthFormat;
  19. using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
  20. using VideoCore::Surface::PixelFormatFromTextureFormat;
  21. using VideoCore::Surface::SurfaceTargetFromTextureType;
  22. constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
  23. return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
  24. }
  25. SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
  26. const Tegra::Texture::FullTextureInfo& config) {
  27. SurfaceParams params;
  28. params.is_tiled = config.tic.IsTiled();
  29. params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0,
  30. params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0,
  31. params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0,
  32. params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1;
  33. params.pixel_format =
  34. PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), false);
  35. params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value());
  36. params.type = GetFormatType(params.pixel_format);
  37. params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
  38. params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
  39. params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
  40. params.depth = config.tic.Depth();
  41. if (params.target == SurfaceTarget::TextureCubemap ||
  42. params.target == SurfaceTarget::TextureCubeArray) {
  43. params.depth *= 6;
  44. }
  45. params.pitch = params.is_tiled ? 0 : config.tic.Pitch();
  46. params.unaligned_height = config.tic.Height();
  47. params.num_levels = config.tic.max_mip_level + 1;
  48. params.CalculateCachedValues();
  49. return params;
  50. }
  51. SurfaceParams SurfaceParams::CreateForDepthBuffer(
  52. Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,
  53. u32 block_width, u32 block_height, u32 block_depth,
  54. Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) {
  55. SurfaceParams params;
  56. params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
  57. params.block_width = 1 << std::min(block_width, 5U);
  58. params.block_height = 1 << std::min(block_height, 5U);
  59. params.block_depth = 1 << std::min(block_depth, 5U);
  60. params.tile_width_spacing = 1;
  61. params.pixel_format = PixelFormatFromDepthFormat(format);
  62. params.component_type = ComponentTypeFromDepthFormat(format);
  63. params.type = GetFormatType(params.pixel_format);
  64. params.width = zeta_width;
  65. params.height = zeta_height;
  66. params.unaligned_height = zeta_height;
  67. params.target = SurfaceTarget::Texture2D;
  68. params.depth = 1;
  69. params.num_levels = 1;
  70. params.CalculateCachedValues();
  71. return params;
  72. }
  73. SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::size_t index) {
  74. const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
  75. SurfaceParams params;
  76. params.is_tiled =
  77. config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
  78. params.block_width = 1 << config.memory_layout.block_width;
  79. params.block_height = 1 << config.memory_layout.block_height;
  80. params.block_depth = 1 << config.memory_layout.block_depth;
  81. params.tile_width_spacing = 1;
  82. params.pixel_format = PixelFormatFromRenderTargetFormat(config.format);
  83. params.component_type = ComponentTypeFromRenderTarget(config.format);
  84. params.type = GetFormatType(params.pixel_format);
  85. if (params.is_tiled) {
  86. params.width = config.width;
  87. } else {
  88. const u32 bpp = GetFormatBpp(params.pixel_format) / CHAR_BIT;
  89. params.pitch = config.width;
  90. params.width = params.pitch / bpp;
  91. }
  92. params.height = config.height;
  93. params.depth = 1;
  94. params.unaligned_height = config.height;
  95. params.target = SurfaceTarget::Texture2D;
  96. params.num_levels = 1;
  97. params.CalculateCachedValues();
  98. return params;
  99. }
  100. SurfaceParams SurfaceParams::CreateForFermiCopySurface(
  101. const Tegra::Engines::Fermi2D::Regs::Surface& config) {
  102. SurfaceParams params{};
  103. params.is_tiled = !config.linear;
  104. params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0,
  105. params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0,
  106. params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0,
  107. params.tile_width_spacing = 1;
  108. params.pixel_format = PixelFormatFromRenderTargetFormat(config.format);
  109. params.component_type = ComponentTypeFromRenderTarget(config.format);
  110. params.type = GetFormatType(params.pixel_format);
  111. params.width = config.width;
  112. params.height = config.height;
  113. params.unaligned_height = config.height;
  114. // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters
  115. params.target = SurfaceTarget::Texture2D;
  116. params.depth = 1;
  117. params.num_levels = 1;
  118. params.CalculateCachedValues();
  119. return params;
  120. }
  121. u32 SurfaceParams::GetMipWidth(u32 level) const {
  122. return std::max(1U, width >> level);
  123. }
  124. u32 SurfaceParams::GetMipHeight(u32 level) const {
  125. return std::max(1U, height >> level);
  126. }
  127. u32 SurfaceParams::GetMipDepth(u32 level) const {
  128. return IsLayered() ? depth : std::max(1U, depth >> level);
  129. }
  130. bool SurfaceParams::IsLayered() const {
  131. switch (target) {
  132. case SurfaceTarget::Texture1DArray:
  133. case SurfaceTarget::Texture2DArray:
  134. case SurfaceTarget::TextureCubeArray:
  135. case SurfaceTarget::TextureCubemap:
  136. return true;
  137. default:
  138. return false;
  139. }
  140. }
  141. u32 SurfaceParams::GetMipBlockHeight(u32 level) const {
  142. // Auto block resizing algorithm from:
  143. // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c
  144. if (level == 0) {
  145. return block_height;
  146. }
  147. const u32 height{GetMipHeight(level)};
  148. const u32 default_block_height{GetDefaultBlockHeight(pixel_format)};
  149. const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height};
  150. u32 block_height = 16;
  151. while (block_height > 1 && blocks_in_y <= block_height * 4) {
  152. block_height >>= 1;
  153. }
  154. return block_height;
  155. }
  156. u32 SurfaceParams::GetMipBlockDepth(u32 level) const {
  157. if (level == 0)
  158. return block_depth;
  159. if (target != SurfaceTarget::Texture3D)
  160. return 1;
  161. const u32 depth{GetMipDepth(level)};
  162. u32 block_depth = 32;
  163. while (block_depth > 1 && depth * 2 <= block_depth) {
  164. block_depth >>= 1;
  165. }
  166. if (block_depth == 32 && GetMipBlockHeight(level) >= 4) {
  167. return 16;
  168. }
  169. return block_depth;
  170. }
  171. std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const {
  172. std::size_t offset = 0;
  173. for (u32 i = 0; i < level; i++) {
  174. offset += GetInnerMipmapMemorySize(i, false, IsLayered(), false);
  175. }
  176. return offset;
  177. }
  178. std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const {
  179. std::size_t offset = 0;
  180. for (u32 i = 0; i < level; i++) {
  181. offset += GetInnerMipmapMemorySize(i, true, false, false);
  182. }
  183. return offset;
  184. }
  185. std::size_t SurfaceParams::GetGuestLayerSize() const {
  186. return GetInnerMemorySize(false, true, false);
  187. }
  188. std::size_t SurfaceParams::GetHostLayerSize(u32 level) const {
  189. return GetInnerMipmapMemorySize(level, true, IsLayered(), false);
  190. }
  191. bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const {
  192. if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) !=
  193. std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format,
  194. view_params.component_type, view_params.type)) {
  195. return false;
  196. }
  197. const SurfaceTarget view_target{view_params.target};
  198. if (view_target == target) {
  199. return true;
  200. }
  201. switch (target) {
  202. case SurfaceTarget::Texture1D:
  203. case SurfaceTarget::Texture2D:
  204. case SurfaceTarget::Texture3D:
  205. return false;
  206. case SurfaceTarget::Texture1DArray:
  207. return view_target == SurfaceTarget::Texture1D;
  208. case SurfaceTarget::Texture2DArray:
  209. return view_target == SurfaceTarget::Texture2D;
  210. case SurfaceTarget::TextureCubemap:
  211. return view_target == SurfaceTarget::Texture2D ||
  212. view_target == SurfaceTarget::Texture2DArray;
  213. case SurfaceTarget::TextureCubeArray:
  214. return view_target == SurfaceTarget::Texture2D ||
  215. view_target == SurfaceTarget::Texture2DArray ||
  216. view_target == SurfaceTarget::TextureCubemap;
  217. default:
  218. UNIMPLEMENTED_MSG("Unimplemented texture family={}", static_cast<u32>(target));
  219. return false;
  220. }
  221. }
  222. bool SurfaceParams::IsPixelFormatZeta() const {
  223. return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat &&
  224. pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat;
  225. }
  226. void SurfaceParams::CalculateCachedValues() {
  227. guest_size_in_bytes = GetInnerMemorySize(false, false, false);
  228. // ASTC is uncompressed in software, in emulated as RGBA8
  229. if (IsPixelFormatASTC(pixel_format)) {
  230. host_size_in_bytes = width * height * depth * 4;
  231. } else {
  232. host_size_in_bytes = GetInnerMemorySize(true, false, false);
  233. }
  234. switch (target) {
  235. case SurfaceTarget::Texture1D:
  236. case SurfaceTarget::Texture2D:
  237. case SurfaceTarget::Texture3D:
  238. num_layers = 1;
  239. break;
  240. case SurfaceTarget::Texture1DArray:
  241. case SurfaceTarget::Texture2DArray:
  242. case SurfaceTarget::TextureCubemap:
  243. case SurfaceTarget::TextureCubeArray:
  244. num_layers = depth;
  245. break;
  246. default:
  247. UNREACHABLE();
  248. }
  249. }
  250. std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only,
  251. bool uncompressed) const {
  252. const bool tiled{as_host_size ? false : is_tiled};
  253. const u32 tile_x{GetDefaultBlockWidth(pixel_format)};
  254. const u32 tile_y{GetDefaultBlockHeight(pixel_format)};
  255. const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), tile_x)};
  256. const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), tile_y)};
  257. const u32 depth{layer_only ? 1U : GetMipDepth(level)};
  258. return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(pixel_format), width, height,
  259. depth, GetMipBlockHeight(level), GetMipBlockDepth(level));
  260. }
  261. std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only,
  262. bool uncompressed) const {
  263. std::size_t size = 0;
  264. for (u32 level = 0; level < num_levels; ++level) {
  265. size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed);
  266. }
  267. if (!as_host_size && is_tiled) {
  268. size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
  269. }
  270. return size;
  271. }
  272. std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const {
  273. std::map<u64, std::pair<u32, u32>> view_offset_map;
  274. switch (target) {
  275. case SurfaceTarget::Texture1D:
  276. case SurfaceTarget::Texture2D:
  277. case SurfaceTarget::Texture3D: {
  278. constexpr u32 layer = 0;
  279. for (u32 level = 0; level < num_levels; ++level) {
  280. const std::size_t offset{GetGuestMipmapLevelOffset(level)};
  281. view_offset_map.insert({offset, {layer, level}});
  282. }
  283. break;
  284. }
  285. case SurfaceTarget::Texture1DArray:
  286. case SurfaceTarget::Texture2DArray:
  287. case SurfaceTarget::TextureCubemap:
  288. case SurfaceTarget::TextureCubeArray: {
  289. const std::size_t layer_size{GetGuestLayerSize()};
  290. for (u32 level = 0; level < num_levels; ++level) {
  291. const std::size_t level_offset{GetGuestMipmapLevelOffset(level)};
  292. for (u32 layer = 0; layer < num_layers; ++layer) {
  293. const auto layer_offset{static_cast<std::size_t>(layer_size * layer)};
  294. const std::size_t offset{level_offset + layer_offset};
  295. view_offset_map.insert({offset, {layer, level}});
  296. }
  297. }
  298. break;
  299. }
  300. default:
  301. UNIMPLEMENTED_MSG("Unimplemented surface target {}", static_cast<u32>(target));
  302. }
  303. return view_offset_map;
  304. }
  305. bool SurfaceParams::IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const {
  306. return IsDimensionValid(view_params, level) && IsDepthValid(view_params, level) &&
  307. IsInBounds(view_params, layer, level);
  308. }
  309. bool SurfaceParams::IsDimensionValid(const SurfaceParams& view_params, u32 level) const {
  310. return view_params.width == GetMipWidth(level) && view_params.height == GetMipHeight(level);
  311. }
  312. bool SurfaceParams::IsDepthValid(const SurfaceParams& view_params, u32 level) const {
  313. if (view_params.target != SurfaceTarget::Texture3D) {
  314. return true;
  315. }
  316. return view_params.depth == GetMipDepth(level);
  317. }
  318. bool SurfaceParams::IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const {
  319. return layer + view_params.num_layers <= num_layers &&
  320. level + view_params.num_levels <= num_levels;
  321. }
  322. std::size_t HasheableSurfaceParams::Hash() const {
  323. return static_cast<std::size_t>(
  324. Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
  325. }
  326. bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const {
  327. return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width,
  328. height, depth, pitch, unaligned_height, num_levels, pixel_format,
  329. component_type, type, target) ==
  330. std::tie(rhs.is_tiled, rhs.block_width, rhs.block_height, rhs.block_depth,
  331. rhs.tile_width_spacing, rhs.width, rhs.height, rhs.depth, rhs.pitch,
  332. rhs.unaligned_height, rhs.num_levels, rhs.pixel_format, rhs.component_type,
  333. rhs.type, rhs.target);
  334. }
  335. std::size_t ViewKey::Hash() const {
  336. return static_cast<std::size_t>(
  337. Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
  338. }
  339. bool ViewKey::operator==(const ViewKey& rhs) const {
  340. return std::tie(base_layer, num_layers, base_level, num_levels) ==
  341. std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels);
  342. }
  343. } // namespace VideoCommon