surface_base.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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 <optional>
  6. #include <tuple>
  7. #include <unordered_map>
  8. #include <vector>
  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. namespace Tegra {
  16. class MemoryManager;
  17. }
  18. namespace VideoCommon {
  19. using VideoCore::MortonSwizzleMode;
  20. using VideoCore::Surface::SurfaceTarget;
  21. enum class MatchStructureResult : u32 {
  22. FullMatch = 0,
  23. SemiMatch = 1,
  24. None = 2,
  25. };
  26. enum class MatchTopologyResult : u32 {
  27. FullMatch = 0,
  28. CompressUnmatch = 1,
  29. None = 2,
  30. };
  31. class StagingCache {
  32. public:
  33. explicit StagingCache();
  34. ~StagingCache();
  35. std::vector<u8>& GetBuffer(std::size_t index) {
  36. return staging_buffer[index];
  37. }
  38. const std::vector<u8>& GetBuffer(std::size_t index) const {
  39. return staging_buffer[index];
  40. }
  41. void SetSize(std::size_t size) {
  42. staging_buffer.resize(size);
  43. }
  44. private:
  45. std::vector<std::vector<u8>> staging_buffer;
  46. };
  47. class SurfaceBaseImpl {
  48. public:
  49. void LoadBuffer(Tegra::MemoryManager& memory_manager, StagingCache& staging_cache);
  50. void FlushBuffer(Tegra::MemoryManager& memory_manager, StagingCache& staging_cache);
  51. GPUVAddr GetGpuAddr() const {
  52. return gpu_addr;
  53. }
  54. bool Overlaps(const VAddr start, const VAddr end) const {
  55. return (cpu_addr < end) && (cpu_addr_end > start);
  56. }
  57. bool IsInside(const GPUVAddr other_start, const GPUVAddr other_end) const {
  58. const GPUVAddr gpu_addr_end = gpu_addr + guest_memory_size;
  59. return gpu_addr <= other_start && other_end <= gpu_addr_end;
  60. }
  61. // Use only when recycling a surface
  62. void SetGpuAddr(const GPUVAddr new_addr) {
  63. gpu_addr = new_addr;
  64. }
  65. VAddr GetCpuAddr() const {
  66. return cpu_addr;
  67. }
  68. VAddr GetCpuAddrEnd() const {
  69. return cpu_addr_end;
  70. }
  71. void SetCpuAddr(const VAddr new_addr) {
  72. cpu_addr = new_addr;
  73. cpu_addr_end = new_addr + guest_memory_size;
  74. }
  75. const SurfaceParams& GetSurfaceParams() const {
  76. return params;
  77. }
  78. std::size_t GetSizeInBytes() const {
  79. return guest_memory_size;
  80. }
  81. std::size_t GetHostSizeInBytes() const {
  82. return host_memory_size;
  83. }
  84. std::size_t GetMipmapSize(const u32 level) const {
  85. return mipmap_sizes[level];
  86. }
  87. bool IsLinear() const {
  88. return !params.is_tiled;
  89. }
  90. bool IsConverted() const {
  91. return is_converted;
  92. }
  93. bool MatchFormat(VideoCore::Surface::PixelFormat pixel_format) const {
  94. return params.pixel_format == pixel_format;
  95. }
  96. VideoCore::Surface::PixelFormat GetFormat() const {
  97. return params.pixel_format;
  98. }
  99. bool MatchTarget(VideoCore::Surface::SurfaceTarget target) const {
  100. return params.target == target;
  101. }
  102. MatchTopologyResult MatchesTopology(const SurfaceParams& rhs) const;
  103. MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const;
  104. bool MatchesSubTexture(const SurfaceParams& rhs, const GPUVAddr other_gpu_addr) const {
  105. return std::tie(gpu_addr, params.target, params.num_levels) ==
  106. std::tie(other_gpu_addr, rhs.target, rhs.num_levels) &&
  107. params.target == SurfaceTarget::Texture2D && params.num_levels == 1;
  108. }
  109. std::optional<std::pair<u32, u32>> GetLayerMipmap(const GPUVAddr candidate_gpu_addr) const;
  110. std::vector<CopyParams> BreakDown(const SurfaceParams& in_params) const {
  111. return params.is_layered ? BreakDownLayered(in_params) : BreakDownNonLayered(in_params);
  112. }
  113. protected:
  114. explicit SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params,
  115. bool is_astc_supported);
  116. ~SurfaceBaseImpl() = default;
  117. virtual void DecorateSurfaceName() = 0;
  118. const SurfaceParams params;
  119. std::size_t layer_size;
  120. std::size_t guest_memory_size;
  121. std::size_t host_memory_size;
  122. GPUVAddr gpu_addr{};
  123. VAddr cpu_addr{};
  124. VAddr cpu_addr_end{};
  125. bool is_converted{};
  126. std::vector<std::size_t> mipmap_sizes;
  127. std::vector<std::size_t> mipmap_offsets;
  128. private:
  129. void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
  130. u32 level);
  131. std::vector<CopyParams> BreakDownLayered(const SurfaceParams& in_params) const;
  132. std::vector<CopyParams> BreakDownNonLayered(const SurfaceParams& in_params) const;
  133. };
  134. template <typename TView>
  135. class SurfaceBase : public SurfaceBaseImpl {
  136. public:
  137. virtual void UploadTexture(const std::vector<u8>& staging_buffer) = 0;
  138. virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;
  139. void MarkAsModified(bool is_modified_, u64 tick) {
  140. is_modified = is_modified_ || is_target;
  141. modification_tick = tick;
  142. }
  143. void MarkAsRenderTarget(bool is_target_, u32 index_) {
  144. is_target = is_target_;
  145. index = index_;
  146. }
  147. void MarkAsPicked(bool is_picked_) {
  148. is_picked = is_picked_;
  149. }
  150. bool IsModified() const {
  151. return is_modified;
  152. }
  153. bool IsProtected() const {
  154. // Only 3D Slices are to be protected
  155. return is_target && params.block_depth > 0;
  156. }
  157. bool IsRenderTarget() const {
  158. return is_target;
  159. }
  160. u32 GetRenderTarget() const {
  161. return index;
  162. }
  163. bool IsRegistered() const {
  164. return is_registered;
  165. }
  166. bool IsPicked() const {
  167. return is_picked;
  168. }
  169. void MarkAsRegistered(bool is_reg) {
  170. is_registered = is_reg;
  171. }
  172. u64 GetModificationTick() const {
  173. return modification_tick;
  174. }
  175. TView EmplaceOverview(const SurfaceParams& overview_params) {
  176. const u32 num_layers{(params.is_layered && !overview_params.is_layered) ? 1 : params.depth};
  177. return GetView(ViewParams(overview_params.target, 0, num_layers, 0, params.num_levels));
  178. }
  179. std::optional<TView> EmplaceIrregularView(const SurfaceParams& view_params,
  180. const GPUVAddr view_addr,
  181. const std::size_t candidate_size, const u32 mipmap,
  182. const u32 layer) {
  183. const auto layer_mipmap{GetLayerMipmap(view_addr + candidate_size)};
  184. if (!layer_mipmap) {
  185. return {};
  186. }
  187. const auto [end_layer, end_mipmap] = *layer_mipmap;
  188. if (layer != end_layer) {
  189. if (mipmap == 0 && end_mipmap == 0) {
  190. return GetView(ViewParams(view_params.target, layer, end_layer - layer, 0, 1));
  191. }
  192. return {};
  193. } else {
  194. return GetView(ViewParams(view_params.target, layer, 1, mipmap, end_mipmap - mipmap));
  195. }
  196. }
  197. std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr,
  198. const std::size_t candidate_size) {
  199. if (params.target == SurfaceTarget::Texture3D ||
  200. (params.num_levels == 1 && !params.is_layered) ||
  201. view_params.target == SurfaceTarget::Texture3D) {
  202. return {};
  203. }
  204. const auto layer_mipmap{GetLayerMipmap(view_addr)};
  205. if (!layer_mipmap) {
  206. return {};
  207. }
  208. const auto [layer, mipmap] = *layer_mipmap;
  209. if (GetMipmapSize(mipmap) != candidate_size) {
  210. return EmplaceIrregularView(view_params, view_addr, candidate_size, mipmap, layer);
  211. }
  212. return GetView(ViewParams(view_params.target, layer, 1, mipmap, 1));
  213. }
  214. TView GetMainView() const {
  215. return main_view;
  216. }
  217. protected:
  218. explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params,
  219. bool is_astc_supported)
  220. : SurfaceBaseImpl(gpu_addr, params, is_astc_supported) {}
  221. ~SurfaceBase() = default;
  222. virtual TView CreateView(const ViewParams& view_key) = 0;
  223. TView main_view;
  224. std::unordered_map<ViewParams, TView> views;
  225. private:
  226. TView GetView(const ViewParams& key) {
  227. const auto [entry, is_cache_miss] = views.try_emplace(key);
  228. auto& view{entry->second};
  229. if (is_cache_miss) {
  230. view = CreateView(key);
  231. }
  232. return view;
  233. }
  234. static constexpr u32 NO_RT = 0xFFFFFFFF;
  235. bool is_modified{};
  236. bool is_target{};
  237. bool is_registered{};
  238. bool is_picked{};
  239. u32 index{NO_RT};
  240. u64 modification_tick{};
  241. };
  242. } // namespace VideoCommon