surface_base.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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_funcs.h"
  10. #include "common/common_types.h"
  11. #include "video_core/gpu.h"
  12. #include "video_core/morton.h"
  13. #include "video_core/texture_cache/copy_params.h"
  14. #include "video_core/texture_cache/surface_params.h"
  15. #include "video_core/texture_cache/surface_view.h"
  16. namespace Tegra {
  17. class MemoryManager;
  18. }
  19. namespace VideoCommon {
  20. using VideoCore::MortonSwizzleMode;
  21. using VideoCore::Surface::SurfaceTarget;
  22. enum class MatchStructureResult : u32 {
  23. FullMatch = 0,
  24. SemiMatch = 1,
  25. None = 2,
  26. };
  27. class SurfaceBaseImpl {
  28. public:
  29. void LoadBuffer(Tegra::MemoryManager& memory_manager, std::vector<u8>& staging_buffer);
  30. void FlushBuffer(Tegra::MemoryManager& memory_manager, std::vector<u8>& staging_buffer);
  31. GPUVAddr GetGpuAddr() const {
  32. return gpu_addr;
  33. }
  34. bool Overlaps(const CacheAddr start, const CacheAddr end) const {
  35. return (cache_addr < end) && (cache_addr_end > start);
  36. }
  37. bool IsInside(const GPUVAddr other_start, const GPUVAddr other_end) {
  38. const GPUVAddr gpu_addr_end = gpu_addr + guest_memory_size;
  39. return (gpu_addr <= other_start && other_end <= gpu_addr_end);
  40. }
  41. // Use only when recycling a surface
  42. void SetGpuAddr(const GPUVAddr new_addr) {
  43. gpu_addr = new_addr;
  44. }
  45. VAddr GetCpuAddr() const {
  46. return cpu_addr;
  47. }
  48. void SetCpuAddr(const VAddr new_addr) {
  49. cpu_addr = new_addr;
  50. }
  51. CacheAddr GetCacheAddr() const {
  52. return cache_addr;
  53. }
  54. CacheAddr GetCacheAddrEnd() const {
  55. return cache_addr_end;
  56. }
  57. void SetCacheAddr(const CacheAddr new_addr) {
  58. cache_addr = new_addr;
  59. cache_addr_end = new_addr + guest_memory_size;
  60. }
  61. const SurfaceParams& GetSurfaceParams() const {
  62. return params;
  63. }
  64. std::size_t GetSizeInBytes() const {
  65. return guest_memory_size;
  66. }
  67. std::size_t GetHostSizeInBytes() const {
  68. return host_memory_size;
  69. }
  70. std::size_t GetMipmapSize(const u32 level) const {
  71. return mipmap_sizes[level];
  72. }
  73. bool IsLinear() const {
  74. return !params.is_tiled;
  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 MatchesSubTexture(const SurfaceParams& rhs, const GPUVAddr other_gpu_addr) const {
  83. return std::tie(gpu_addr, params.target, params.num_levels) ==
  84. std::tie(other_gpu_addr, rhs.target, rhs.num_levels) &&
  85. params.target == SurfaceTarget::Texture2D && params.num_levels == 1;
  86. }
  87. bool MatchesTopology(const SurfaceParams& rhs) const {
  88. const u32 src_bpp{params.GetBytesPerPixel()};
  89. const u32 dst_bpp{rhs.GetBytesPerPixel()};
  90. const bool ib1 = params.IsBuffer();
  91. const bool ib2 = rhs.IsBuffer();
  92. return std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2);
  93. }
  94. MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const {
  95. // Buffer surface Check
  96. if (params.IsBuffer()) {
  97. const std::size_t wd1 = params.width*params.GetBytesPerPixel();
  98. const std::size_t wd2 = rhs.width*rhs.GetBytesPerPixel();
  99. if (wd1 == wd2) {
  100. return MatchStructureResult::FullMatch;
  101. }
  102. return MatchStructureResult::None;
  103. }
  104. // Linear Surface check
  105. if (!params.is_tiled) {
  106. if (std::tie(params.width, params.height, params.pitch) ==
  107. std::tie(rhs.width, rhs.height, rhs.pitch)) {
  108. return MatchStructureResult::FullMatch;
  109. }
  110. return MatchStructureResult::None;
  111. }
  112. // Tiled Surface check
  113. if (std::tie(params.depth, params.block_width, params.block_height, params.block_depth,
  114. params.tile_width_spacing, params.num_levels) ==
  115. std::tie(rhs.depth, rhs.block_width, rhs.block_height, rhs.block_depth,
  116. rhs.tile_width_spacing, rhs.num_levels)) {
  117. if (std::tie(params.width, params.height) == std::tie(rhs.width, rhs.height)) {
  118. return MatchStructureResult::FullMatch;
  119. }
  120. const u32 ws = SurfaceParams::ConvertWidth(rhs.GetBlockAlignedWidth(),
  121. params.pixel_format, rhs.pixel_format);
  122. const u32 hs =
  123. SurfaceParams::ConvertHeight(rhs.height, params.pixel_format, rhs.pixel_format);
  124. const u32 w1 = params.GetBlockAlignedWidth();
  125. if (std::tie(w1, params.height) == std::tie(ws, hs)) {
  126. return MatchStructureResult::SemiMatch;
  127. }
  128. }
  129. return MatchStructureResult::None;
  130. }
  131. std::optional<std::pair<u32, u32>> GetLayerMipmap(const GPUVAddr candidate_gpu_addr) const {
  132. if (candidate_gpu_addr < gpu_addr) {
  133. return {};
  134. }
  135. const auto relative_address{static_cast<GPUVAddr>(candidate_gpu_addr - gpu_addr)};
  136. const auto layer{static_cast<u32>(relative_address / layer_size)};
  137. const GPUVAddr mipmap_address = relative_address - layer_size * layer;
  138. const auto mipmap_it =
  139. Common::BinaryFind(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address);
  140. if (mipmap_it == mipmap_offsets.end()) {
  141. return {};
  142. }
  143. const auto level{static_cast<u32>(std::distance(mipmap_offsets.begin(), mipmap_it))};
  144. return std::make_pair(layer, level);
  145. }
  146. std::vector<CopyParams> BreakDown(const SurfaceParams& in_params) const {
  147. return params.is_layered ? BreakDownLayered(in_params) : BreakDownNonLayered(in_params);
  148. }
  149. protected:
  150. explicit SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params);
  151. ~SurfaceBaseImpl() = default;
  152. virtual void DecorateSurfaceName() = 0;
  153. const SurfaceParams params;
  154. std::size_t layer_size;
  155. std::size_t guest_memory_size;
  156. const std::size_t host_memory_size;
  157. GPUVAddr gpu_addr{};
  158. CacheAddr cache_addr{};
  159. CacheAddr cache_addr_end{};
  160. VAddr cpu_addr{};
  161. std::vector<std::size_t> mipmap_sizes;
  162. std::vector<std::size_t> mipmap_offsets;
  163. private:
  164. void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
  165. u32 level);
  166. std::vector<CopyParams> BreakDownLayered(const SurfaceParams& in_params) const {
  167. const u32 layers{params.depth};
  168. const u32 mipmaps{params.num_levels};
  169. std::vector<CopyParams> result;
  170. result.reserve(static_cast<std::size_t>(layers) * static_cast<std::size_t>(mipmaps));
  171. for (u32 layer = 0; layer < layers; layer++) {
  172. for (u32 level = 0; level < mipmaps; level++) {
  173. const u32 width{std::min(params.GetMipWidth(level), in_params.GetMipWidth(level))};
  174. const u32 height{
  175. std::min(params.GetMipHeight(level), in_params.GetMipHeight(level))};
  176. result.emplace_back(width, height, layer, level);
  177. }
  178. }
  179. return result;
  180. }
  181. std::vector<CopyParams> BreakDownNonLayered(const SurfaceParams& in_params) const {
  182. const u32 mipmaps{params.num_levels};
  183. std::vector<CopyParams> result;
  184. result.reserve(mipmaps);
  185. for (u32 level = 0; level < mipmaps; level++) {
  186. const u32 width{std::min(params.GetMipWidth(level), in_params.GetMipWidth(level))};
  187. const u32 height{std::min(params.GetMipHeight(level), in_params.GetMipHeight(level))};
  188. const u32 depth{std::min(params.GetMipDepth(level), in_params.GetMipDepth(level))};
  189. result.emplace_back(width, height, depth, level);
  190. }
  191. return result;
  192. }
  193. };
  194. template <typename TView>
  195. class SurfaceBase : public SurfaceBaseImpl {
  196. public:
  197. virtual void UploadTexture(std::vector<u8>& staging_buffer) = 0;
  198. virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;
  199. void MarkAsModified(const bool is_modified_, const u64 tick) {
  200. is_modified = is_modified_ || is_target;
  201. modification_tick = tick;
  202. }
  203. void MarkAsRenderTarget(const bool is_target) {
  204. this->is_target = is_target;
  205. }
  206. void MarkAsPicked(const bool is_picked) {
  207. this->is_picked = is_picked;
  208. }
  209. bool IsModified() const {
  210. return is_modified;
  211. }
  212. bool IsProtected() const {
  213. // Only 3D Slices are to be protected
  214. return is_target && params.block_depth > 0;
  215. }
  216. bool IsRenderTarget() const {
  217. return is_target;
  218. }
  219. bool IsRegistered() const {
  220. return is_registered;
  221. }
  222. bool IsPicked() const {
  223. return is_picked;
  224. }
  225. void MarkAsRegistered(bool is_reg) {
  226. is_registered = is_reg;
  227. }
  228. u64 GetModificationTick() const {
  229. return modification_tick;
  230. }
  231. TView EmplaceOverview(const SurfaceParams& overview_params) {
  232. const u32 num_layers{(params.is_layered && !overview_params.is_layered) ? 1 : params.depth};
  233. return GetView(ViewParams(overview_params.target, 0, num_layers, 0, params.num_levels));
  234. }
  235. std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr,
  236. const std::size_t candidate_size) {
  237. if (params.target == SurfaceTarget::Texture3D ||
  238. (params.num_levels == 1 && !params.is_layered) ||
  239. view_params.target == SurfaceTarget::Texture3D) {
  240. return {};
  241. }
  242. const auto layer_mipmap{GetLayerMipmap(view_addr)};
  243. if (!layer_mipmap) {
  244. return {};
  245. }
  246. const u32 layer{layer_mipmap->first};
  247. const u32 mipmap{layer_mipmap->second};
  248. if (GetMipmapSize(mipmap) != candidate_size) {
  249. // TODO: The view may cover many mimaps, this case can still go on.
  250. // This edge-case can be safely be ignored since it will just result in worse
  251. // performance.
  252. return {};
  253. }
  254. return GetView(ViewParams(view_params.target, layer, 1, mipmap, 1));
  255. }
  256. TView GetMainView() const {
  257. return main_view;
  258. }
  259. protected:
  260. explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params)
  261. : SurfaceBaseImpl(gpu_addr, params) {}
  262. ~SurfaceBase() = default;
  263. virtual TView CreateView(const ViewParams& view_key) = 0;
  264. std::unordered_map<ViewParams, TView> views;
  265. TView main_view;
  266. private:
  267. TView GetView(const ViewParams& key) {
  268. const auto [entry, is_cache_miss] = views.try_emplace(key);
  269. auto& view{entry->second};
  270. if (is_cache_miss) {
  271. view = CreateView(key);
  272. }
  273. return view;
  274. }
  275. bool is_modified{};
  276. bool is_target{};
  277. bool is_registered{};
  278. bool is_picked{};
  279. u64 modification_tick{};
  280. };
  281. } // namespace VideoCommon