surface_base.h 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <algorithm>
  6. #include <unordered_map>
  7. #include <vector>
  8. #include "common/assert.h"
  9. #include "common/common_types.h"
  10. #include "video_core/gpu.h"
  11. #include "video_core/morton.h"
  12. #include "video_core/texture_cache/copy_params.h"
  13. #include "video_core/texture_cache/surface_params.h"
  14. #include "video_core/texture_cache/surface_view.h"
  15. template <class ForwardIt, class T, class Compare = std::less<>>
  16. ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp = {}) {
  17. // Note: BOTH type T and the type after ForwardIt is dereferenced
  18. // must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
  19. // This is stricter than lower_bound requirement (see above)
  20. first = std::lower_bound(first, last, value, comp);
  21. return first != last && !comp(value, *first) ? first : last;
  22. }
  23. namespace Tegra {
  24. class MemoryManager;
  25. }
  26. namespace VideoCommon {
  27. using VideoCore::MortonSwizzleMode;
  28. using VideoCore::Surface::SurfaceTarget;
  29. enum class MatchStructureResult : u32 {
  30. FullMatch = 0,
  31. SemiMatch = 1,
  32. None = 2,
  33. };
  34. class SurfaceBaseImpl {
  35. public:
  36. void LoadBuffer(Tegra::MemoryManager& memory_manager, std::vector<u8>& staging_buffer);
  37. void FlushBuffer(Tegra::MemoryManager& memory_manager, std::vector<u8>& staging_buffer);
  38. GPUVAddr GetGpuAddr() const {
  39. return gpu_addr;
  40. }
  41. bool Overlaps(const CacheAddr start, const CacheAddr end) const {
  42. return (cache_addr < end) && (cache_addr_end > start);
  43. }
  44. // Use only when recycling a surface
  45. void SetGpuAddr(const GPUVAddr new_addr) {
  46. gpu_addr = new_addr;
  47. }
  48. VAddr GetCpuAddr() const {
  49. return cpu_addr;
  50. }
  51. void SetCpuAddr(const VAddr new_addr) {
  52. cpu_addr = new_addr;
  53. }
  54. CacheAddr GetCacheAddr() const {
  55. return cache_addr;
  56. }
  57. CacheAddr GetCacheAddrEnd() const {
  58. return cache_addr_end;
  59. }
  60. void SetCacheAddr(const CacheAddr new_addr) {
  61. cache_addr = new_addr;
  62. cache_addr_end = new_addr + guest_memory_size;
  63. }
  64. const SurfaceParams& GetSurfaceParams() const {
  65. return params;
  66. }
  67. std::size_t GetSizeInBytes() const {
  68. return guest_memory_size;
  69. }
  70. std::size_t GetHostSizeInBytes() const {
  71. return host_memory_size;
  72. }
  73. std::size_t GetMipmapSize(const u32 level) const {
  74. return mipmap_sizes[level];
  75. }
  76. bool MatchFormat(VideoCore::Surface::PixelFormat pixel_format) const {
  77. return params.pixel_format == pixel_format;
  78. }
  79. bool MatchTarget(VideoCore::Surface::SurfaceTarget target) const {
  80. return params.target == target;
  81. }
  82. bool MatchesTopology(const SurfaceParams& rhs) const {
  83. const u32 src_bpp = params.GetBytesPerPixel();
  84. const u32 dst_bpp = rhs.GetBytesPerPixel();
  85. return std::tie(src_bpp, params.is_tiled) == std::tie(dst_bpp, rhs.is_tiled);
  86. }
  87. MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const {
  88. if (params.is_tiled) {
  89. if (std::tie(params.height, params.depth, params.block_width, params.block_height,
  90. params.block_depth, params.tile_width_spacing) ==
  91. std::tie(rhs.height, rhs.depth, rhs.block_width, rhs.block_height, rhs.block_depth,
  92. rhs.tile_width_spacing)) {
  93. if (params.width == rhs.width) {
  94. return MatchStructureResult::FullMatch;
  95. }
  96. if (params.GetBlockAlignedWidth() == rhs.GetBlockAlignedWidth()) {
  97. return MatchStructureResult::SemiMatch;
  98. }
  99. }
  100. return MatchStructureResult::None;
  101. } else {
  102. if (std::tie(params.width, params.height, params.pitch) ==
  103. std::tie(rhs.width, rhs.height, rhs.pitch)) {
  104. return MatchStructureResult::FullMatch;
  105. }
  106. return MatchStructureResult::None;
  107. }
  108. }
  109. std::optional<std::pair<u32, u32>> GetLayerMipmap(const GPUVAddr candidate_gpu_addr) const {
  110. if (candidate_gpu_addr < gpu_addr) {
  111. return {};
  112. }
  113. const auto relative_address{static_cast<GPUVAddr>(candidate_gpu_addr - gpu_addr)};
  114. const auto layer{static_cast<u32>(relative_address / layer_size)};
  115. const GPUVAddr mipmap_address = relative_address - layer_size * layer;
  116. const auto mipmap_it =
  117. binary_find(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address);
  118. if (mipmap_it == mipmap_offsets.end()) {
  119. return {};
  120. }
  121. const auto level{static_cast<u32>(std::distance(mipmap_offsets.begin(), mipmap_it))};
  122. return std::make_pair(layer, level);
  123. }
  124. std::vector<CopyParams> BreakDown(const SurfaceParams& in_params) const {
  125. std::vector<CopyParams> result;
  126. const u32 layers{params.depth};
  127. const u32 mipmaps{params.num_levels};
  128. if (params.is_layered) {
  129. result.reserve(static_cast<std::size_t>(layers) * static_cast<std::size_t>(mipmaps));
  130. for (u32 layer = 0; layer < layers; layer++) {
  131. const u32 layer_offset{layer * mipmaps};
  132. for (u32 level = 0; level < mipmaps; level++) {
  133. const u32 width{
  134. std::min(params.GetMipWidth(level), in_params.GetMipWidth(level))};
  135. const u32 height{
  136. std::min(params.GetMipHeight(level), in_params.GetMipHeight(level))};
  137. result.emplace_back(width, height, layer, level);
  138. }
  139. }
  140. return result;
  141. } else {
  142. result.reserve(mipmaps);
  143. for (u32 level = 0; level < mipmaps; level++) {
  144. const u32 width{std::min(params.GetMipWidth(level), in_params.GetMipWidth(level))};
  145. const u32 height{
  146. std::min(params.GetMipHeight(level), in_params.GetMipHeight(level))};
  147. const u32 depth{std::min(params.GetMipDepth(level), in_params.GetMipDepth(level))};
  148. result.emplace_back(width, height, depth, level);
  149. }
  150. return result;
  151. }
  152. }
  153. protected:
  154. explicit SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params);
  155. ~SurfaceBaseImpl() = default;
  156. virtual void DecorateSurfaceName() = 0;
  157. const SurfaceParams params;
  158. const std::size_t layer_size;
  159. const std::size_t guest_memory_size;
  160. const std::size_t host_memory_size;
  161. GPUVAddr gpu_addr{};
  162. CacheAddr cache_addr{};
  163. CacheAddr cache_addr_end{};
  164. VAddr cpu_addr{};
  165. std::vector<std::size_t> mipmap_sizes;
  166. std::vector<std::size_t> mipmap_offsets;
  167. private:
  168. void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
  169. u32 level);
  170. };
  171. template <typename TView>
  172. class SurfaceBase : public SurfaceBaseImpl {
  173. public:
  174. virtual void UploadTexture(std::vector<u8>& staging_buffer) = 0;
  175. virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;
  176. void MarkAsModified(const bool is_modified_, const u64 tick) {
  177. is_modified = is_modified_ || is_protected;
  178. modification_tick = tick;
  179. }
  180. void MarkAsProtected(const bool is_protected) {
  181. this->is_protected = is_protected;
  182. }
  183. void MarkAsPicked(const bool is_picked) {
  184. this->is_picked = is_picked;
  185. }
  186. bool IsModified() const {
  187. return is_modified;
  188. }
  189. bool IsProtected() const {
  190. return is_protected;
  191. }
  192. bool IsRegistered() const {
  193. return is_registered;
  194. }
  195. bool IsPicked() const {
  196. return is_picked;
  197. }
  198. void MarkAsRegistered(bool is_reg) {
  199. is_registered = is_reg;
  200. }
  201. u64 GetModificationTick() const {
  202. return modification_tick;
  203. }
  204. TView EmplaceOverview(const SurfaceParams& overview_params) {
  205. ViewParams vp{};
  206. vp.base_level = 0;
  207. vp.num_levels = params.num_levels;
  208. vp.target = overview_params.target;
  209. if (params.is_layered && !overview_params.is_layered) {
  210. vp.base_layer = 0;
  211. vp.num_layers = 1;
  212. } else {
  213. vp.base_layer = 0;
  214. vp.num_layers = params.depth;
  215. }
  216. return GetView(vp);
  217. }
  218. std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr) {
  219. if (view_addr < gpu_addr)
  220. return {};
  221. if (params.target == SurfaceTarget::Texture3D ||
  222. view_params.target == SurfaceTarget::Texture3D) {
  223. return {};
  224. }
  225. const std::size_t size = view_params.GetGuestSizeInBytes();
  226. auto layer_mipmap = GetLayerMipmap(view_addr);
  227. if (!layer_mipmap) {
  228. return {};
  229. }
  230. const u32 layer = (*layer_mipmap).first;
  231. const u32 mipmap = (*layer_mipmap).second;
  232. if (GetMipmapSize(mipmap) != size) {
  233. // TODO: the view may cover many mimaps, this case can still go on
  234. return {};
  235. }
  236. ViewParams vp{};
  237. vp.base_layer = layer;
  238. vp.num_layers = 1;
  239. vp.base_level = mipmap;
  240. vp.num_levels = 1;
  241. vp.target = view_params.target;
  242. return {GetView(vp)};
  243. }
  244. TView GetMainView() const {
  245. return main_view;
  246. }
  247. protected:
  248. explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params)
  249. : SurfaceBaseImpl(gpu_addr, params) {}
  250. ~SurfaceBase() = default;
  251. virtual TView CreateView(const ViewParams& view_key) = 0;
  252. std::unordered_map<ViewParams, TView> views;
  253. TView main_view;
  254. private:
  255. TView GetView(const ViewParams& key) {
  256. const auto [entry, is_cache_miss] = views.try_emplace(key);
  257. auto& view{entry->second};
  258. if (is_cache_miss) {
  259. view = CreateView(key);
  260. }
  261. return view;
  262. }
  263. bool is_modified{};
  264. bool is_protected{};
  265. bool is_registered{};
  266. bool is_picked{};
  267. u64 modification_tick{};
  268. };
  269. } // namespace VideoCommon