summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-04-24 02:45:03 -0300
committerGravatar ReinUsesLisp2019-06-20 21:36:11 -0300
commit5f3aacdc3760f0e9e0daeda3ee4c55e42fc9397e (patch)
tree6c95776e1de8c347544745df1784424cafaeb414 /src
parenttexture_cache: Flush 3D textures in the order they are drawn (diff)
downloadyuzu-5f3aacdc3760f0e9e0daeda3ee4c55e42fc9397e.tar.gz
yuzu-5f3aacdc3760f0e9e0daeda3ee4c55e42fc9397e.tar.xz
yuzu-5f3aacdc3760f0e9e0daeda3ee4c55e42fc9397e.zip
texture_cache: Move staging buffer into a generic implementation
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp114
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h7
-rw-r--r--src/video_core/texture_cache.cpp110
-rw-r--r--src/video_core/texture_cache.h161
4 files changed, 211 insertions, 181 deletions
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 362f4019c..3e2a1f53c 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -15,7 +15,6 @@
15 15
16namespace OpenGL { 16namespace OpenGL {
17 17
18using Tegra::Texture::ConvertFromGuestToHost;
19using Tegra::Texture::SwizzleSource; 18using Tegra::Texture::SwizzleSource;
20using VideoCore::MortonSwizzleMode; 19using VideoCore::MortonSwizzleMode;
21 20
@@ -207,32 +206,6 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte
207 return texture; 206 return texture;
208} 207}
209 208
210void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
211 u32 level) {
212 const u32 width{params.GetMipWidth(level)};
213 const u32 height{params.GetMipHeight(level)};
214 const u32 block_height{params.GetMipBlockHeight(level)};
215 const u32 block_depth{params.GetMipBlockDepth(level)};
216
217 std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
218 if (params.IsLayered()) {
219 std::size_t host_offset{0};
220 const std::size_t guest_stride = params.GetGuestLayerSize();
221 const std::size_t host_stride = params.GetHostLayerSize(level);
222 for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
223 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
224 1, params.GetTileWidthSpacing(), buffer + host_offset,
225 memory + guest_offset);
226 guest_offset += guest_stride;
227 host_offset += host_stride;
228 }
229 } else {
230 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
231 params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
232 memory + guest_offset);
233 }
234}
235
236} // Anonymous namespace 209} // Anonymous namespace
237 210
238CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params) 211CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params)
@@ -245,54 +218,11 @@ CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfacePar
245 is_compressed = tuple.compressed; 218 is_compressed = tuple.compressed;
246 target = GetTextureTarget(params); 219 target = GetTextureTarget(params);
247 texture = CreateTexture(params, target, internal_format); 220 texture = CreateTexture(params, target, internal_format);
248 staging_buffer.resize(params.GetHostSizeInBytes());
249} 221}
250 222
251CachedSurface::~CachedSurface() = default; 223CachedSurface::~CachedSurface() = default;
252 224
253void CachedSurface::LoadBuffer() { 225void CachedSurface::DownloadTextureImpl() {
254 if (params.IsTiled()) {
255 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
256 params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
257 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
258 u8* const buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)};
259 SwizzleFunc(MortonSwizzleMode::MortonToLinear, GetHostPtr(), params, buffer, level);
260 }
261 } else {
262 ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
263 const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
264 const u32 block_width{VideoCore::Surface::GetDefaultBlockWidth(params.GetPixelFormat())};
265 const u32 block_height{VideoCore::Surface::GetDefaultBlockHeight(params.GetPixelFormat())};
266 const u32 width{(params.GetWidth() + block_width - 1) / block_width};
267 const u32 height{(params.GetHeight() + block_height - 1) / block_height};
268 const u32 copy_size{width * bpp};
269 if (params.GetPitch() == copy_size) {
270 std::memcpy(staging_buffer.data(), GetHostPtr(), params.GetHostSizeInBytes());
271 } else {
272 const u8* start{GetHostPtr()};
273 u8* write_to{staging_buffer.data()};
274 for (u32 h = height; h > 0; --h) {
275 std::memcpy(write_to, start, copy_size);
276 start += params.GetPitch();
277 write_to += copy_size;
278 }
279 }
280 }
281
282 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
283 ConvertFromGuestToHost(staging_buffer.data() + params.GetHostMipmapLevelOffset(level),
284 params.GetPixelFormat(), params.GetMipWidth(level),
285 params.GetMipHeight(level), params.GetMipDepth(level), true, true);
286 }
287}
288
289void CachedSurface::FlushBufferImpl() {
290 LOG_CRITICAL(Render_OpenGL, "Flushing");
291
292 if (!IsModified()) {
293 return;
294 }
295
296 // TODO(Rodrigo): Optimize alignment 226 // TODO(Rodrigo): Optimize alignment
297 glPixelStorei(GL_PACK_ALIGNMENT, 1); 227 glPixelStorei(GL_PACK_ALIGNMENT, 1);
298 SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); 228 SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); });
@@ -300,60 +230,30 @@ void CachedSurface::FlushBufferImpl() {
300 for (u32 level = 0; level < params.GetNumLevels(); ++level) { 230 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
301 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); 231 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
302 if (is_compressed) { 232 if (is_compressed) {
303 glGetCompressedTextureImage( 233 glGetCompressedTextureImage(texture.handle, level,
304 texture.handle, level, static_cast<GLsizei>(params.GetHostMipmapSize(level)), 234 static_cast<GLsizei>(params.GetHostMipmapSize(level)),
305 staging_buffer.data() + params.GetHostMipmapLevelOffset(level)); 235 GetStagingBufferLevelData(level));
306 } else { 236 } else {
307 glGetTextureImage(texture.handle, level, format, type, 237 glGetTextureImage(texture.handle, level, format, type,
308 static_cast<GLsizei>(params.GetHostMipmapSize(level)), 238 static_cast<GLsizei>(params.GetHostMipmapSize(level)),
309 staging_buffer.data() + params.GetHostMipmapLevelOffset(level)); 239 GetStagingBufferLevelData(level));
310 } 240 }
311 } 241 }
312
313 if (params.IsTiled()) {
314 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
315 params.GetBlockWidth());
316 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
317 u8* const buffer = staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
318 SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level);
319 }
320 } else {
321 UNIMPLEMENTED();
322 /*
323 ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
324 ASSERT(params.GetNumLevels() == 1);
325
326 const u32 bpp{params.GetFormatBpp() / 8};
327 const u32 copy_size{params.GetWidth() * bpp};
328 if (params.GetPitch() == copy_size) {
329 std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
330 } else {
331 u8* start{host_ptr};
332 const u8* read_to{staging_buffer.data()};
333 for (u32 h = params.GetHeight(); h > 0; --h) {
334 std::memcpy(start, read_to, copy_size);
335 start += params.GetPitch();
336 read_to += copy_size;
337 }
338 }
339 */
340 }
341} 242}
342 243
343void CachedSurface::UploadTextureImpl() { 244void CachedSurface::UploadTextureImpl() {
245 SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
344 for (u32 level = 0; level < params.GetNumLevels(); ++level) { 246 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
345 UploadTextureMipmap(level); 247 UploadTextureMipmap(level);
346 } 248 }
347} 249}
348 250
349void CachedSurface::UploadTextureMipmap(u32 level) { 251void CachedSurface::UploadTextureMipmap(u32 level) {
350 u8* buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)};
351
352 // TODO(Rodrigo): Optimize alignment 252 // TODO(Rodrigo): Optimize alignment
353 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 253 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
354 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); 254 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
355 SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
356 255
256 u8* buffer{GetStagingBufferLevelData(level)};
357 if (is_compressed) { 257 if (is_compressed) {
358 const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))}; 258 const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))};
359 switch (params.GetTarget()) { 259 switch (params.GetTarget()) {
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index e6448c6f8..0a69be233 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -39,8 +39,6 @@ public:
39 explicit CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params); 39 explicit CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params);
40 ~CachedSurface(); 40 ~CachedSurface();
41 41
42 void LoadBuffer();
43
44 GLenum GetTarget() const { 42 GLenum GetTarget() const {
45 return target; 43 return target;
46 } 44 }
@@ -54,9 +52,8 @@ protected:
54 52
55 std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key); 53 std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key);
56 54
57 void FlushBufferImpl();
58
59 void UploadTextureImpl(); 55 void UploadTextureImpl();
56 void DownloadTextureImpl();
60 57
61private: 58private:
62 void UploadTextureMipmap(u32 level); 59 void UploadTextureMipmap(u32 level);
@@ -68,8 +65,6 @@ private:
68 GLenum target{}; 65 GLenum target{};
69 66
70 OGLTexture texture; 67 OGLTexture texture;
71
72 std::vector<u8> staging_buffer;
73}; 68};
74 69
75class CachedSurfaceView final { 70class CachedSurfaceView final {
diff --git a/src/video_core/texture_cache.cpp b/src/video_core/texture_cache.cpp
index b78a7d951..146e8ed9b 100644
--- a/src/video_core/texture_cache.cpp
+++ b/src/video_core/texture_cache.cpp
@@ -7,14 +7,16 @@
7#include "common/cityhash.h" 7#include "common/cityhash.h"
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "video_core/morton.h"
10#include "video_core/surface.h" 11#include "video_core/surface.h"
11#include "video_core/texture_cache.h" 12#include "video_core/texture_cache.h"
13#include "video_core/textures/convert.h"
12#include "video_core/textures/decoders.h" 14#include "video_core/textures/decoders.h"
13#include "video_core/textures/texture.h" 15#include "video_core/textures/texture.h"
14 16
15namespace VideoCommon { 17namespace VideoCommon {
16 18
17using VideoCore::Surface::SurfaceTarget; 19using VideoCore::MortonSwizzleMode;
18 20
19using VideoCore::Surface::ComponentTypeFromDepthFormat; 21using VideoCore::Surface::ComponentTypeFromDepthFormat;
20using VideoCore::Surface::ComponentTypeFromRenderTarget; 22using VideoCore::Surface::ComponentTypeFromRenderTarget;
@@ -22,12 +24,118 @@ using VideoCore::Surface::ComponentTypeFromTexture;
22using VideoCore::Surface::PixelFormatFromDepthFormat; 24using VideoCore::Surface::PixelFormatFromDepthFormat;
23using VideoCore::Surface::PixelFormatFromRenderTargetFormat; 25using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
24using VideoCore::Surface::PixelFormatFromTextureFormat; 26using VideoCore::Surface::PixelFormatFromTextureFormat;
27using VideoCore::Surface::SurfaceTarget;
25using VideoCore::Surface::SurfaceTargetFromTextureType; 28using VideoCore::Surface::SurfaceTargetFromTextureType;
26 29
30using Tegra::Texture::ConvertFromGuestToHost;
31
32namespace {
33
27constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { 34constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
28 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile); 35 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
29} 36}
30 37
38void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
39 u32 level) {
40 const u32 width{params.GetMipWidth(level)};
41 const u32 height{params.GetMipHeight(level)};
42 const u32 block_height{params.GetMipBlockHeight(level)};
43 const u32 block_depth{params.GetMipBlockDepth(level)};
44
45 std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
46 if (params.IsLayered()) {
47 std::size_t host_offset{0};
48 const std::size_t guest_stride = params.GetGuestLayerSize();
49 const std::size_t host_stride = params.GetHostLayerSize(level);
50 for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
51 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
52 1, params.GetTileWidthSpacing(), buffer + host_offset,
53 memory + guest_offset);
54 guest_offset += guest_stride;
55 host_offset += host_stride;
56 }
57 } else {
58 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
59 params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
60 memory + guest_offset);
61 }
62}
63
64} // Anonymous namespace
65
66SurfaceBaseImpl::SurfaceBaseImpl(const SurfaceParams& params) : params{params} {
67 staging_buffer.resize(params.GetHostSizeInBytes());
68}
69
70SurfaceBaseImpl::~SurfaceBaseImpl() = default;
71
72void SurfaceBaseImpl::LoadBuffer() {
73 if (params.IsTiled()) {
74 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
75 params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
76 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
77 u8* const buffer{GetStagingBufferLevelData(level)};
78 SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, buffer, level);
79 }
80 } else {
81 ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
82 const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
83 const u32 block_width{params.GetDefaultBlockWidth()};
84 const u32 block_height{params.GetDefaultBlockHeight()};
85 const u32 width{(params.GetWidth() + block_width - 1) / block_width};
86 const u32 height{(params.GetHeight() + block_height - 1) / block_height};
87 const u32 copy_size{width * bpp};
88 if (params.GetPitch() == copy_size) {
89 std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes());
90 } else {
91 const u8* start{host_ptr};
92 u8* write_to{staging_buffer.data()};
93 for (u32 h = height; h > 0; --h) {
94 std::memcpy(write_to, start, copy_size);
95 start += params.GetPitch();
96 write_to += copy_size;
97 }
98 }
99 }
100
101 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
102 ConvertFromGuestToHost(GetStagingBufferLevelData(level), params.GetPixelFormat(),
103 params.GetMipWidth(level), params.GetMipHeight(level),
104 params.GetMipDepth(level), true, true);
105 }
106}
107
108void SurfaceBaseImpl::FlushBuffer() {
109 if (params.IsTiled()) {
110 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
111 params.GetBlockWidth());
112 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
113 u8* const buffer = GetStagingBufferLevelData(level);
114 SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level);
115 }
116 } else {
117 UNIMPLEMENTED();
118 /*
119 ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
120 ASSERT(params.GetNumLevels() == 1);
121
122 const u32 bpp{params.GetFormatBpp() / 8};
123 const u32 copy_size{params.GetWidth() * bpp};
124 if (params.GetPitch() == copy_size) {
125 std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
126 } else {
127 u8* start{host_ptr};
128 const u8* read_to{staging_buffer.data()};
129 for (u32 h = params.GetHeight(); h > 0; --h) {
130 std::memcpy(start, read_to, copy_size);
131 start += params.GetPitch();
132 read_to += copy_size;
133 }
134 }
135 */
136 }
137}
138
31SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, 139SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
32 const Tegra::Texture::FullTextureInfo& config) { 140 const Tegra::Texture::FullTextureInfo& config) {
33 SurfaceParams params; 141 SurfaceParams params;
diff --git a/src/video_core/texture_cache.h b/src/video_core/texture_cache.h
index f22e8e776..90c72cb15 100644
--- a/src/video_core/texture_cache.h
+++ b/src/video_core/texture_cache.h
@@ -273,37 +273,11 @@ struct hash<VideoCommon::ViewKey> {
273 273
274namespace VideoCommon { 274namespace VideoCommon {
275 275
276template <typename TTextureCache, typename TView, typename TExecutionContext> 276class SurfaceBaseImpl {
277class SurfaceBase {
278 static_assert(std::is_trivially_copyable_v<TExecutionContext>);
279
280public: 277public:
281 virtual void LoadBuffer() = 0; 278 void LoadBuffer();
282
283 virtual TExecutionContext FlushBuffer(TExecutionContext exctx) = 0;
284
285 virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
286
287 TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
288 if (view_addr < gpu_addr || !params.IsFamiliar(view_params)) {
289 // It can't be a view if it's in a prior address.
290 return {};
291 }
292
293 const auto relative_offset{static_cast<u64>(view_addr - gpu_addr)};
294 const auto it{view_offset_map.find(relative_offset)};
295 if (it == view_offset_map.end()) {
296 // Couldn't find an aligned view.
297 return {};
298 }
299 const auto [layer, level] = it->second;
300
301 if (!params.IsViewValid(view_params, layer, level)) {
302 return {};
303 }
304 279
305 return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels()); 280 void FlushBuffer();
306 }
307 281
308 GPUVAddr GetGpuAddr() const { 282 GPUVAddr GetGpuAddr() const {
309 ASSERT(is_registered); 283 ASSERT(is_registered);
@@ -325,27 +299,10 @@ public:
325 return cache_addr; 299 return cache_addr;
326 } 300 }
327 301
328 std::size_t GetSizeInBytes() const {
329 return params.GetGuestSizeInBytes();
330 }
331
332 void MarkAsModified(bool is_modified_) {
333 is_modified = is_modified_;
334 if (is_modified_) {
335 modification_tick = texture_cache.Tick();
336 }
337 }
338
339 const SurfaceParams& GetSurfaceParams() const { 302 const SurfaceParams& GetSurfaceParams() const {
340 return params; 303 return params;
341 } 304 }
342 305
343 TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
344 TView* view{TryGetView(view_addr, view_params)};
345 ASSERT(view != nullptr);
346 return view;
347 }
348
349 void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) { 306 void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) {
350 ASSERT(!is_registered); 307 ASSERT(!is_registered);
351 is_registered = true; 308 is_registered = true;
@@ -361,30 +318,95 @@ public:
361 is_registered = false; 318 is_registered = false;
362 } 319 }
363 320
364 u64 GetModificationTick() const {
365 return modification_tick;
366 }
367
368 bool IsRegistered() const { 321 bool IsRegistered() const {
369 return is_registered; 322 return is_registered;
370 } 323 }
371 324
372protected: 325 std::size_t GetSizeInBytes() const {
373 explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params) 326 return params.GetGuestSizeInBytes();
374 : params{params}, texture_cache{texture_cache}, view_offset_map{ 327 }
375 params.CreateViewOffsetMap()} {}
376 328
377 ~SurfaceBase() = default; 329 u8* GetStagingBufferLevelData(u32 level) {
330 return staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
331 }
332
333protected:
334 explicit SurfaceBaseImpl(const SurfaceParams& params);
335 ~SurfaceBaseImpl(); // non-virtual is intended
378 336
379 virtual void DecorateSurfaceName() = 0; 337 virtual void DecorateSurfaceName() = 0;
380 338
381 virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0; 339 const SurfaceParams params;
340
341private:
342 GPUVAddr gpu_addr{};
343 VAddr cpu_addr{};
344 u8* host_ptr{};
345 CacheAddr cache_addr{};
346 bool is_registered{};
347
348 std::vector<u8> staging_buffer;
349};
350
351template <typename TTextureCache, typename TView, typename TExecutionContext>
352class SurfaceBase : public SurfaceBaseImpl {
353 static_assert(std::is_trivially_copyable_v<TExecutionContext>);
354
355public:
356 virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
357
358 virtual TExecutionContext DownloadTexture(TExecutionContext exctx) = 0;
359
360 TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
361 if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) {
362 // It can't be a view if it's in a prior address.
363 return {};
364 }
365
366 const auto relative_offset{static_cast<u64>(view_addr - GetGpuAddr())};
367 const auto it{view_offset_map.find(relative_offset)};
368 if (it == view_offset_map.end()) {
369 // Couldn't find an aligned view.
370 return {};
371 }
372 const auto [layer, level] = it->second;
373
374 if (!params.IsViewValid(view_params, layer, level)) {
375 return {};
376 }
377
378 return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
379 }
380
381 void MarkAsModified(bool is_modified_) {
382 is_modified = is_modified_;
383 if (is_modified_) {
384 modification_tick = texture_cache.Tick();
385 }
386 }
387
388 TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
389 TView* view{TryGetView(view_addr, view_params)};
390 ASSERT(view != nullptr);
391 return view;
392 }
382 393
383 bool IsModified() const { 394 bool IsModified() const {
384 return is_modified; 395 return is_modified;
385 } 396 }
386 397
387 const SurfaceParams params; 398 u64 GetModificationTick() const {
399 return modification_tick;
400 }
401
402protected:
403 explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params)
404 : SurfaceBaseImpl{params}, texture_cache{texture_cache},
405 view_offset_map{params.CreateViewOffsetMap()} {}
406
407 ~SurfaceBase() = default;
408
409 virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
388 410
389private: 411private:
390 TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) { 412 TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) {
@@ -400,13 +422,8 @@ private:
400 TTextureCache& texture_cache; 422 TTextureCache& texture_cache;
401 const std::map<u64, std::pair<u32, u32>> view_offset_map; 423 const std::map<u64, std::pair<u32, u32>> view_offset_map;
402 424
403 GPUVAddr gpu_addr{};
404 VAddr cpu_addr{};
405 u8* host_ptr{};
406 CacheAddr cache_addr{};
407 u64 modification_tick{};
408 bool is_modified{}; 425 bool is_modified{};
409 bool is_registered{}; 426 u64 modification_tick{};
410 std::unordered_map<ViewKey, std::unique_ptr<TView>> views; 427 std::unordered_map<ViewKey, std::unique_ptr<TView>> views;
411}; 428};
412 429
@@ -560,7 +577,7 @@ private:
560 if (!fast_view) { 577 if (!fast_view) {
561 // Flush even when we don't care about the contents, to preserve memory not 578 // Flush even when we don't care about the contents, to preserve memory not
562 // written by the new surface. 579 // written by the new surface.
563 exctx = surface->FlushBuffer(exctx); 580 exctx = FlushSurface(exctx, surface);
564 } 581 }
565 Unregister(surface); 582 Unregister(surface);
566 } 583 }
@@ -590,6 +607,16 @@ private:
590 return exctx; 607 return exctx;
591 } 608 }
592 609
610 TExecutionContext FlushSurface(TExecutionContext exctx,
611 const std::shared_ptr<TSurface>& surface) {
612 if (!surface->IsModified()) {
613 return exctx;
614 }
615 exctx = surface->DownloadTexture(exctx);
616 surface->FlushBuffer();
617 return exctx;
618 }
619
593 std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr, 620 std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr,
594 std::size_t size) const { 621 std::size_t size) const {
595 if (size == 0) { 622 if (size == 0) {
@@ -701,8 +728,8 @@ private:
701template <typename TTextureCache, typename TView> 728template <typename TTextureCache, typename TView>
702class SurfaceBaseContextless : public SurfaceBase<TTextureCache, TView, DummyExecutionContext> { 729class SurfaceBaseContextless : public SurfaceBase<TTextureCache, TView, DummyExecutionContext> {
703public: 730public:
704 DummyExecutionContext FlushBuffer(DummyExecutionContext) { 731 DummyExecutionContext DownloadTexture(DummyExecutionContext) {
705 FlushBufferImpl(); 732 DownloadTextureImpl();
706 return {}; 733 return {};
707 } 734 }
708 735
@@ -715,7 +742,7 @@ protected:
715 explicit SurfaceBaseContextless(TTextureCache& texture_cache, const SurfaceParams& params) 742 explicit SurfaceBaseContextless(TTextureCache& texture_cache, const SurfaceParams& params)
716 : SurfaceBase<TTextureCache, TView, DummyExecutionContext>{texture_cache, params} {} 743 : SurfaceBase<TTextureCache, TView, DummyExecutionContext>{texture_cache, params} {}
717 744
718 virtual void FlushBufferImpl() = 0; 745 virtual void DownloadTextureImpl() = 0;
719 746
720 virtual void UploadTextureImpl() = 0; 747 virtual void UploadTextureImpl() = 0;
721}; 748};