summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-05-07 10:57:16 -0400
committerGravatar ReinUsesLisp2019-06-20 21:36:12 -0300
commitbc930754cc9437ddd86e7d246b3eb4302540896a (patch)
tree75e56e5e041db7b327a13c25ab13bc524458dc29 /src
parentCorrect Surface Base and Views for new Texture Cache (diff)
downloadyuzu-bc930754cc9437ddd86e7d246b3eb4302540896a.tar.gz
yuzu-bc930754cc9437ddd86e7d246b3eb4302540896a.tar.xz
yuzu-bc930754cc9437ddd86e7d246b3eb4302540896a.zip
Implement Texture Cache V2
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp69
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp286
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h111
-rw-r--r--src/video_core/renderer_opengl/utils.cpp23
-rw-r--r--src/video_core/renderer_opengl/utils.h6
-rw-r--r--src/video_core/texture_cache/texture_cache.h454
6 files changed, 568 insertions, 381 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 027e9d293..482d0428c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -83,10 +83,10 @@ struct FramebufferCacheKey {
83 bool stencil_enable = false; 83 bool stencil_enable = false;
84 84
85 std::array<GLenum, Maxwell::NumRenderTargets> color_attachments{}; 85 std::array<GLenum, Maxwell::NumRenderTargets> color_attachments{};
86 std::array<CachedSurfaceView*, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors{}; 86 std::array<View, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors{};
87 u32 colors_count = 0; 87 u32 colors_count = 0;
88 88
89 CachedSurfaceView* zeta = nullptr; 89 View zeta = nullptr;
90 90
91 auto Tie() const { 91 auto Tie() const {
92 return std::tie(is_single_buffer, stencil_enable, color_attachments, colors, colors_count, 92 return std::tie(is_single_buffer, stencil_enable, color_attachments, colors, colors_count,
@@ -115,6 +115,10 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
115 115
116RasterizerOpenGL::~RasterizerOpenGL() {} 116RasterizerOpenGL::~RasterizerOpenGL() {}
117 117
118void RasterizerOpenGL::InitMemoryMananger(Tegra::MemoryManager& memory_manager) {
119 texture_cache.InitMemoryMananger(memory_manager);
120}
121
118void RasterizerOpenGL::CheckExtensions() { 122void RasterizerOpenGL::CheckExtensions() {
119 if (!GLAD_GL_ARB_texture_filter_anisotropic && !GLAD_GL_EXT_texture_filter_anisotropic) { 123 if (!GLAD_GL_ARB_texture_filter_anisotropic && !GLAD_GL_EXT_texture_filter_anisotropic) {
120 LOG_WARNING( 124 LOG_WARNING(
@@ -474,9 +478,11 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
474 } 478 }
475 current_framebuffer_config_state = fb_config_state; 479 current_framebuffer_config_state = fb_config_state;
476 480
477 CachedSurfaceView* depth_surface{}; 481 View depth_surface{};
478 if (using_depth_fb) { 482 if (using_depth_fb) {
479 depth_surface = texture_cache.GetDepthBufferSurface(preserve_contents); 483 depth_surface = texture_cache.GetDepthBufferSurface(preserve_contents);
484 } else {
485 texture_cache.SetEmptyDepthBuffer();
480 } 486 }
481 487
482 UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0); 488 UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0);
@@ -489,38 +495,41 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
489 if (using_color_fb) { 495 if (using_color_fb) {
490 if (single_color_target) { 496 if (single_color_target) {
491 // Used when just a single color attachment is enabled, e.g. for clearing a color buffer 497 // Used when just a single color attachment is enabled, e.g. for clearing a color buffer
492 CachedSurfaceView* color_surface{ 498 View color_surface{
493 texture_cache.GetColorBufferSurface(*single_color_target, preserve_contents)}; 499 texture_cache.GetColorBufferSurface(*single_color_target, preserve_contents)};
494 500
495 if (color_surface) { 501 if (color_surface) {
496 // Assume that a surface will be written to if it is used as a framebuffer, even if 502 // Assume that a surface will be written to if it is used as a framebuffer, even if
497 // the shader doesn't actually write to it. 503 // the shader doesn't actually write to it.
498 color_surface->MarkAsModified(true); 504 texture_cache.MarkColorBufferInUse(*single_color_target);
499 // Workaround for and issue in nvidia drivers 505 // Workaround for and issue in nvidia drivers
500 // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ 506 // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
501 state.framebuffer_srgb.enabled |= 507 state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion;
502 color_surface->GetSurfaceParams().GetSrgbConversion();
503 } 508 }
504 509
505 fbkey.is_single_buffer = true; 510 fbkey.is_single_buffer = true;
506 fbkey.color_attachments[0] = 511 fbkey.color_attachments[0] =
507 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target); 512 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target);
508 fbkey.colors[0] = color_surface; 513 fbkey.colors[0] = color_surface;
514 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
515 if (index != *single_color_target) {
516 texture_cache.SetEmptyColorBuffer(index);
517 }
518 }
509 } else { 519 } else {
510 // Multiple color attachments are enabled 520 // Multiple color attachments are enabled
511 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { 521 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
512 CachedSurfaceView* color_surface{ 522 View color_surface{texture_cache.GetColorBufferSurface(index, preserve_contents)};
513 texture_cache.GetColorBufferSurface(index, preserve_contents)};
514 523
515 if (color_surface) { 524 if (color_surface) {
516 // Assume that a surface will be written to if it is used as a framebuffer, even 525 // Assume that a surface will be written to if it is used as a framebuffer, even
517 // if the shader doesn't actually write to it. 526 // if the shader doesn't actually write to it.
518 color_surface->MarkAsModified(true); 527 texture_cache.MarkColorBufferInUse(index);
519 // Enable sRGB only for supported formats 528 // Enable sRGB only for supported formats
520 // Workaround for and issue in nvidia drivers 529 // Workaround for and issue in nvidia drivers
521 // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ 530 // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
522 state.framebuffer_srgb.enabled |= 531 state.framebuffer_srgb.enabled |=
523 color_surface->GetSurfaceParams().GetSrgbConversion(); 532 color_surface->GetSurfaceParams().srgb_conversion;
524 } 533 }
525 534
526 fbkey.color_attachments[index] = 535 fbkey.color_attachments[index] =
@@ -538,11 +547,11 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
538 if (depth_surface) { 547 if (depth_surface) {
539 // Assume that a surface will be written to if it is used as a framebuffer, even if 548 // Assume that a surface will be written to if it is used as a framebuffer, even if
540 // the shader doesn't actually write to it. 549 // the shader doesn't actually write to it.
541 depth_surface->MarkAsModified(true); 550 texture_cache.MarkDepthBufferInUse();
542 551
543 fbkey.zeta = depth_surface; 552 fbkey.zeta = depth_surface;
544 fbkey.stencil_enable = regs.stencil_enable && depth_surface->GetSurfaceParams().GetType() == 553 fbkey.stencil_enable = regs.stencil_enable &&
545 SurfaceType::DepthStencil; 554 depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil;
546 } 555 }
547 556
548 SetupCachedFramebuffer(fbkey, current_state); 557 SetupCachedFramebuffer(fbkey, current_state);
@@ -728,11 +737,27 @@ void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) {
728 buffer_cache.InvalidateRegion(addr, size); 737 buffer_cache.InvalidateRegion(addr, size);
729} 738}
730 739
740void RasterizerOpenGL::InvalidateRegionEx(GPUVAddr gpu_addr, CacheAddr addr, u64 size) {
741 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
742 if (!addr || !size) {
743 return;
744 }
745 texture_cache.InvalidateRegionEx(gpu_addr, size);
746 shader_cache.InvalidateRegion(addr, size);
747 global_cache.InvalidateRegion(addr, size);
748 buffer_cache.InvalidateRegion(addr, size);
749}
750
731void RasterizerOpenGL::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { 751void RasterizerOpenGL::FlushAndInvalidateRegion(CacheAddr addr, u64 size) {
732 FlushRegion(addr, size); 752 FlushRegion(addr, size);
733 InvalidateRegion(addr, size); 753 InvalidateRegion(addr, size);
734} 754}
735 755
756void RasterizerOpenGL::FlushAndInvalidateRegionEx(GPUVAddr gpu_addr, CacheAddr addr, u64 size) {
757 FlushRegion(addr, size);
758 InvalidateRegionEx(gpu_addr, addr, size);
759}
760
736bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 761bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
737 const Tegra::Engines::Fermi2D::Regs::Surface& dst, 762 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
738 const Common::Rectangle<u32>& src_rect, 763 const Common::Rectangle<u32>& src_rect,
@@ -740,7 +765,7 @@ bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs
740 MICROPROFILE_SCOPE(OpenGL_Blits); 765 MICROPROFILE_SCOPE(OpenGL_Blits);
741 const auto src_surface{texture_cache.GetFermiSurface(src)}; 766 const auto src_surface{texture_cache.GetFermiSurface(src)};
742 const auto dst_surface{texture_cache.GetFermiSurface(dst)}; 767 const auto dst_surface{texture_cache.GetFermiSurface(dst)};
743 blitter.Blit(src_surface, dst_surface, src_rect, dst_rect); 768 // blitter.Blit(src_surface, dst_surface, src_rect, dst_rect);
744 return true; 769 return true;
745} 770}
746 771
@@ -762,10 +787,10 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
762 const auto& params{surface->GetSurfaceParams()}; 787 const auto& params{surface->GetSurfaceParams()};
763 const auto& pixel_format{ 788 const auto& pixel_format{
764 VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)}; 789 VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
765 ASSERT_MSG(params.GetWidth() == config.width, "Framebuffer width is different"); 790 ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
766 ASSERT_MSG(params.GetHeight() == config.height, "Framebuffer height is different"); 791 ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
767 792
768 if (params.GetPixelFormat() != pixel_format) { 793 if (params.pixel_format != pixel_format) {
769 LOG_WARNING(Render_OpenGL, "Framebuffer pixel_format is different"); 794 LOG_WARNING(Render_OpenGL, "Framebuffer pixel_format is different");
770 } 795 }
771 796
@@ -860,10 +885,10 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
860 885
861 state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc); 886 state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc);
862 887
863 if (const auto surface{texture_cache.GetTextureSurface(texture)}; surface) { 888 if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) {
864 state.texture_units[current_bindpoint].texture = surface->GetTexture( 889 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
865 entry.GetType(), entry.IsArray(), texture.tic.x_source, texture.tic.y_source, 890 texture.tic.w_source);
866 texture.tic.z_source, texture.tic.w_source); 891 state.texture_units[current_bindpoint].texture = view->GetTexture();
867 } else { 892 } else {
868 // Can occur when texture addr is null or its memory is unmapped/invalid 893 // Can occur when texture addr is null or its memory is unmapped/invalid
869 state.texture_units[current_bindpoint].texture = 0; 894 state.texture_units[current_bindpoint].texture = 0;
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index f7c2f46aa..871608f6d 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -4,7 +4,9 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "common/microprofile.h"
7#include "common/scope_exit.h" 8#include "common/scope_exit.h"
9#include "core/core.h"
8#include "video_core/morton.h" 10#include "video_core/morton.h"
9#include "video_core/renderer_opengl/gl_resource_manager.h" 11#include "video_core/renderer_opengl/gl_resource_manager.h"
10#include "video_core/renderer_opengl/gl_texture_cache.h" 12#include "video_core/renderer_opengl/gl_texture_cache.h"
@@ -22,6 +24,9 @@ using VideoCore::Surface::ComponentType;
22using VideoCore::Surface::PixelFormat; 24using VideoCore::Surface::PixelFormat;
23using VideoCore::Surface::SurfaceTarget; 25using VideoCore::Surface::SurfaceTarget;
24 26
27MICROPROFILE_DEFINE(OpenGL_Texture_Upload, "OpenGL", "Texture Upload", MP_RGB(128, 192, 128));
28MICROPROFILE_DEFINE(OpenGL_Texture_Download, "OpenGL", "Texture Download", MP_RGB(128, 192, 128));
29
25namespace { 30namespace {
26 31
27struct FormatTuple { 32struct FormatTuple {
@@ -129,8 +134,8 @@ const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType compon
129 return format; 134 return format;
130} 135}
131 136
132GLenum GetTextureTarget(const SurfaceParams& params) { 137GLenum GetTextureTarget(const SurfaceTarget& target) {
133 switch (params.GetTarget()) { 138 switch (target) {
134 case SurfaceTarget::Texture1D: 139 case SurfaceTarget::Texture1D:
135 return GL_TEXTURE_1D; 140 return GL_TEXTURE_1D;
136 case SurfaceTarget::Texture2D: 141 case SurfaceTarget::Texture2D:
@@ -175,8 +180,8 @@ void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) {
175 glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 180 glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
176 glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 181 glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
177 glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 182 glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
178 glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, params.GetNumLevels() - 1); 183 glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, params.num_levels - 1);
179 if (params.GetNumLevels() == 1) { 184 if (params.num_levels == 1) {
180 glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f); 185 glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f);
181 } 186 }
182} 187}
@@ -185,21 +190,20 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte
185 OGLTexture texture; 190 OGLTexture texture;
186 texture.Create(target); 191 texture.Create(target);
187 192
188 switch (params.GetTarget()) { 193 switch (params.target) {
189 case SurfaceTarget::Texture1D: 194 case SurfaceTarget::Texture1D:
190 glTextureStorage1D(texture.handle, params.GetNumLevels(), internal_format, 195 glTextureStorage1D(texture.handle, params.num_levels, internal_format, params.width);
191 params.GetWidth());
192 break; 196 break;
193 case SurfaceTarget::Texture2D: 197 case SurfaceTarget::Texture2D:
194 case SurfaceTarget::TextureCubemap: 198 case SurfaceTarget::TextureCubemap:
195 glTextureStorage2D(texture.handle, params.GetNumLevels(), internal_format, 199 glTextureStorage2D(texture.handle, params.num_levels, internal_format, params.width,
196 params.GetWidth(), params.GetHeight()); 200 params.height);
197 break; 201 break;
198 case SurfaceTarget::Texture3D: 202 case SurfaceTarget::Texture3D:
199 case SurfaceTarget::Texture2DArray: 203 case SurfaceTarget::Texture2DArray:
200 case SurfaceTarget::TextureCubeArray: 204 case SurfaceTarget::TextureCubeArray:
201 glTextureStorage3D(texture.handle, params.GetNumLevels(), internal_format, 205 glTextureStorage3D(texture.handle, params.num_levels, internal_format, params.width,
202 params.GetWidth(), params.GetHeight(), params.GetDepth()); 206 params.height, params.depth);
203 break; 207 break;
204 default: 208 default:
205 UNREACHABLE(); 209 UNREACHABLE();
@@ -212,54 +216,72 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte
212 216
213} // Anonymous namespace 217} // Anonymous namespace
214 218
215CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params) 219CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params)
216 : VideoCommon::SurfaceBase<TextureCacheOpenGL, CachedSurfaceView>{texture_cache, params} { 220 : VideoCommon::SurfaceBase<View>(gpu_addr, params) {
217 const auto& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())}; 221 const auto& tuple{GetFormatTuple(params.pixel_format, params.component_type)};
218 internal_format = tuple.internal_format; 222 internal_format = tuple.internal_format;
219 format = tuple.format; 223 format = tuple.format;
220 type = tuple.type; 224 type = tuple.type;
221 is_compressed = tuple.compressed; 225 is_compressed = tuple.compressed;
222 target = GetTextureTarget(params); 226 target = GetTextureTarget(params.target);
223 texture = CreateTexture(params, target, internal_format); 227 texture = CreateTexture(params, target, internal_format);
228 DecorateSurfaceName();
229 ViewParams main{};
230 main.num_levels = params.num_levels;
231 main.base_level = 0;
232 main.base_layer = 0;
233 main.num_layers = params.is_layered ? params.depth : 1;
234 main.target = params.target;
235 main_view = CreateView(main);
236 main_view->DecorateViewName(gpu_addr, params.TargetName() + "V:" + std::to_string(view_count++));
237}
238
239CachedSurface::~CachedSurface() {
240 views.clear();
241 main_view = nullptr;
224} 242}
225 243
226CachedSurface::~CachedSurface() = default; 244void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
245 LOG_CRITICAL(Render_OpenGL, "Flushing");
246 MICROPROFILE_SCOPE(OpenGL_Texture_Download);
227 247
228void CachedSurface::DownloadTexture() {
229 // TODO(Rodrigo): Optimize alignment 248 // TODO(Rodrigo): Optimize alignment
230 glPixelStorei(GL_PACK_ALIGNMENT, 1); 249 glPixelStorei(GL_PACK_ALIGNMENT, 1);
231 SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); 250 SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); });
232 251
233 for (u32 level = 0; level < params.GetNumLevels(); ++level) { 252 for (u32 level = 0; level < params.num_levels; ++level) {
234 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); 253 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
254 const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level);
235 if (is_compressed) { 255 if (is_compressed) {
236 glGetCompressedTextureImage(texture.handle, level, 256 glGetCompressedTextureImage(texture.handle, level,
237 static_cast<GLsizei>(params.GetHostMipmapSize(level)), 257 static_cast<GLsizei>(params.GetHostMipmapSize(level)),
238 GetStagingBufferLevelData(level)); 258 staging_buffer.data() + mip_offset);
239 } else { 259 } else {
240 glGetTextureImage(texture.handle, level, format, type, 260 glGetTextureImage(texture.handle, level, format, type,
241 static_cast<GLsizei>(params.GetHostMipmapSize(level)), 261 static_cast<GLsizei>(params.GetHostMipmapSize(level)),
242 GetStagingBufferLevelData(level)); 262 staging_buffer.data() + mip_offset);
243 } 263 }
244 } 264 }
245} 265}
246 266
247void CachedSurface::UploadTexture() { 267void CachedSurface::UploadTexture(std::vector<u8>& staging_buffer) {
268 MICROPROFILE_SCOPE(OpenGL_Texture_Upload);
248 SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); }); 269 SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
249 for (u32 level = 0; level < params.GetNumLevels(); ++level) { 270 for (u32 level = 0; level < params.num_levels; ++level) {
250 UploadTextureMipmap(level); 271 UploadTextureMipmap(level, staging_buffer);
251 } 272 }
252} 273}
253 274
254void CachedSurface::UploadTextureMipmap(u32 level) { 275void CachedSurface::UploadTextureMipmap(u32 level, std::vector<u8>& staging_buffer) {
255 // TODO(Rodrigo): Optimize alignment 276 // TODO(Rodrigo): Optimize alignment
256 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 277 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
257 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); 278 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
258 279
259 u8* buffer{GetStagingBufferLevelData(level)}; 280 const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level);
281 u8* buffer{staging_buffer.data() + mip_offset};
260 if (is_compressed) { 282 if (is_compressed) {
261 const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))}; 283 const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))};
262 switch (params.GetTarget()) { 284 switch (params.target) {
263 case SurfaceTarget::Texture2D: 285 case SurfaceTarget::Texture2D:
264 glCompressedTextureSubImage2D(texture.handle, level, 0, 0, 286 glCompressedTextureSubImage2D(texture.handle, level, 0, 0,
265 static_cast<GLsizei>(params.GetMipWidth(level)), 287 static_cast<GLsizei>(params.GetMipWidth(level)),
@@ -277,7 +299,7 @@ void CachedSurface::UploadTextureMipmap(u32 level) {
277 break; 299 break;
278 case SurfaceTarget::TextureCubemap: { 300 case SurfaceTarget::TextureCubemap: {
279 const std::size_t layer_size{params.GetHostLayerSize(level)}; 301 const std::size_t layer_size{params.GetHostLayerSize(level)};
280 for (std::size_t face = 0; face < params.GetDepth(); ++face) { 302 for (std::size_t face = 0; face < params.depth; ++face) {
281 glCompressedTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face), 303 glCompressedTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face),
282 static_cast<GLsizei>(params.GetMipWidth(level)), 304 static_cast<GLsizei>(params.GetMipWidth(level)),
283 static_cast<GLsizei>(params.GetMipHeight(level)), 1, 305 static_cast<GLsizei>(params.GetMipHeight(level)), 1,
@@ -291,7 +313,7 @@ void CachedSurface::UploadTextureMipmap(u32 level) {
291 UNREACHABLE(); 313 UNREACHABLE();
292 } 314 }
293 } else { 315 } else {
294 switch (params.GetTarget()) { 316 switch (params.target) {
295 case SurfaceTarget::Texture1D: 317 case SurfaceTarget::Texture1D:
296 glTextureSubImage1D(texture.handle, level, 0, params.GetMipWidth(level), format, type, 318 glTextureSubImage1D(texture.handle, level, 0, params.GetMipWidth(level), format, type,
297 buffer); 319 buffer);
@@ -310,7 +332,7 @@ void CachedSurface::UploadTextureMipmap(u32 level) {
310 static_cast<GLsizei>(params.GetMipDepth(level)), format, type, buffer); 332 static_cast<GLsizei>(params.GetMipDepth(level)), format, type, buffer);
311 break; 333 break;
312 case SurfaceTarget::TextureCubemap: 334 case SurfaceTarget::TextureCubemap:
313 for (std::size_t face = 0; face < params.GetDepth(); ++face) { 335 for (std::size_t face = 0; face < params.depth; ++face) {
314 glTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face), 336 glTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face),
315 params.GetMipWidth(level), params.GetMipHeight(level), 1, 337 params.GetMipWidth(level), params.GetMipHeight(level), 1,
316 format, type, buffer); 338 format, type, buffer);
@@ -324,61 +346,57 @@ void CachedSurface::UploadTextureMipmap(u32 level) {
324} 346}
325 347
326void CachedSurface::DecorateSurfaceName() { 348void CachedSurface::DecorateSurfaceName() {
327 LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr(), 349 LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr(), params.TargetName());
328 params.GetTarget() == SurfaceTarget::Texture3D ? "3D" : ""); 350}
351
352void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, std::string prefix) {
353 LabelGLObject(GL_TEXTURE, texture_view.texture.handle, gpu_addr, prefix);
329} 354}
330 355
331std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) { 356View CachedSurface::CreateView(const ViewParams& view_key) {
332 return std::make_unique<CachedSurfaceView>(*this, view_key); 357 auto view = std::make_shared<CachedSurfaceView>(*this, view_key);
358 views[view_key] = view;
359 view->DecorateViewName(gpu_addr, params.TargetName() + "V:" + std::to_string(view_count++));
360 return view;
333} 361}
334 362
335CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, ViewKey key) 363CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, const ViewParams& params)
336 : surface{surface}, key{key}, params{surface.GetSurfaceParams()} {} 364 : VideoCommon::ViewBase(params), surface{surface} {
365 target = GetTextureTarget(params.target);
366 texture_view = CreateTextureView();
367}
337 368
338CachedSurfaceView::~CachedSurfaceView() = default; 369CachedSurfaceView::~CachedSurfaceView() = default;
339 370
340void CachedSurfaceView::Attach(GLenum attachment) const { 371void CachedSurfaceView::Attach(GLenum attachment) const {
341 ASSERT(key.num_layers == 1 && key.num_levels == 1); 372 ASSERT(params.num_layers == 1 && params.num_levels == 1);
342 373
343 switch (params.GetTarget()) { 374 switch (params.target) {
344 case SurfaceTarget::Texture1D: 375 case SurfaceTarget::Texture1D:
345 glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, attachment, surface.GetTarget(), 376 glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, attachment, target,
346 surface.GetTexture(), key.base_level); 377 surface.GetTexture(), params.base_level);
347 break; 378 break;
348 case SurfaceTarget::Texture2D: 379 case SurfaceTarget::Texture2D:
349 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, surface.GetTarget(), 380 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target,
350 surface.GetTexture(), key.base_level); 381 surface.GetTexture(), params.base_level);
351 break; 382 break;
352 case SurfaceTarget::Texture1DArray: 383 case SurfaceTarget::Texture1DArray:
353 case SurfaceTarget::Texture2DArray: 384 case SurfaceTarget::Texture2DArray:
354 case SurfaceTarget::TextureCubemap: 385 case SurfaceTarget::TextureCubemap:
355 case SurfaceTarget::TextureCubeArray: 386 case SurfaceTarget::TextureCubeArray:
356 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attachment, surface.GetTexture(), 387 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attachment, target,
357 key.base_level, key.base_layer); 388 params.base_level, params.base_layer);
358 break; 389 break;
359 default: 390 default:
360 UNIMPLEMENTED(); 391 UNIMPLEMENTED();
361 } 392 }
362} 393}
363 394
364GLuint CachedSurfaceView::GetTexture(Tegra::Shader::TextureType texture_type, bool is_array, 395void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_source,
365 SwizzleSource x_source, SwizzleSource y_source,
366 SwizzleSource z_source, SwizzleSource w_source) { 396 SwizzleSource z_source, SwizzleSource w_source) {
367 const auto [texture_view, target] = GetTextureView(texture_type, is_array); 397 u32 swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source);
368 if (texture_view.get().texture.handle == 0) { 398 if (swizzle == texture_view.swizzle)
369 texture_view.get() = std::move(CreateTextureView(target));
370 }
371 ApplySwizzle(texture_view, x_source, y_source, z_source, w_source);
372 return texture_view.get().texture.handle;
373}
374
375void CachedSurfaceView::ApplySwizzle(TextureView& texture_view, SwizzleSource x_source,
376 SwizzleSource y_source, SwizzleSource z_source,
377 SwizzleSource w_source) {
378 const std::array<SwizzleSource, 4> swizzle = {x_source, y_source, z_source, w_source};
379 if (swizzle == texture_view.swizzle) {
380 return; 399 return;
381 }
382 const std::array<GLint, 4> gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source), 400 const std::array<GLint, 4> gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source),
383 GetSwizzleSource(z_source), 401 GetSwizzleSource(z_source),
384 GetSwizzleSource(w_source)}; 402 GetSwizzleSource(w_source)};
@@ -386,38 +404,25 @@ void CachedSurfaceView::ApplySwizzle(TextureView& texture_view, SwizzleSource x_
386 texture_view.swizzle = swizzle; 404 texture_view.swizzle = swizzle;
387} 405}
388 406
389CachedSurfaceView::TextureView CachedSurfaceView::CreateTextureView(GLenum target) const { 407CachedSurfaceView::TextureView CachedSurfaceView::CreateTextureView() const {
408 const auto& owner_params = surface.GetSurfaceParams();
390 TextureView texture_view; 409 TextureView texture_view;
391 glGenTextures(1, &texture_view.texture.handle); 410 texture_view.texture.Create();
392 411
393 const GLuint handle{texture_view.texture.handle}; 412 const GLuint handle{texture_view.texture.handle};
394 const FormatTuple& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())}; 413 const FormatTuple& tuple{
414 GetFormatTuple(owner_params.pixel_format, owner_params.component_type)};
395 415
396 glTextureView(handle, target, surface.texture.handle, tuple.internal_format, key.base_level, 416 glTextureView(handle, target, surface.texture.handle, tuple.internal_format, params.base_level,
397 key.num_levels, key.base_layer, key.num_layers); 417 params.num_levels, params.base_layer, params.num_layers);
398 ApplyTextureDefaults(params, handle);
399 418
400 return texture_view; 419 ApplyTextureDefaults(owner_params, handle);
401}
402 420
403std::pair<std::reference_wrapper<CachedSurfaceView::TextureView>, GLenum> 421 u32 swizzle =
404CachedSurfaceView::GetTextureView(Tegra::Shader::TextureType texture_type, bool is_array) { 422 EncodeSwizzle(SwizzleSource::R, SwizzleSource::G, SwizzleSource::B, SwizzleSource::A);
405 using Pair = std::pair<std::reference_wrapper<TextureView>, GLenum>; 423 texture_view.swizzle = swizzle;
406 switch (texture_type) { 424
407 case Tegra::Shader::TextureType::Texture1D: 425 return texture_view;
408 return is_array ? Pair{texture_view_1d_array, GL_TEXTURE_1D_ARRAY}
409 : Pair{texture_view_1d, GL_TEXTURE_1D};
410 case Tegra::Shader::TextureType::Texture2D:
411 return is_array ? Pair{texture_view_2d_array, GL_TEXTURE_2D_ARRAY}
412 : Pair{texture_view_2d, GL_TEXTURE_2D};
413 case Tegra::Shader::TextureType::Texture3D:
414 ASSERT(!is_array);
415 return {texture_view_3d, GL_TEXTURE_3D};
416 case Tegra::Shader::TextureType::TextureCube:
417 return is_array ? Pair{texture_view_cube_array, GL_TEXTURE_CUBE_MAP_ARRAY}
418 : Pair{texture_view_cube, GL_TEXTURE_CUBE_MAP};
419 }
420 UNREACHABLE();
421} 426}
422 427
423TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, 428TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
@@ -426,106 +431,21 @@ TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
426 431
427TextureCacheOpenGL::~TextureCacheOpenGL() = default; 432TextureCacheOpenGL::~TextureCacheOpenGL() = default;
428 433
429CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, 434Surface TextureCacheOpenGL::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) {
430 u8* host_ptr, 435 return std::make_shared<CachedSurface>(gpu_addr, params);
431 const SurfaceParams& new_params,
432 bool preserve_contents,
433 const std::vector<Surface>& overlaps) {
434 if (overlaps.size() > 1) {
435 return TryCopyAsViews(gpu_addr, cpu_addr, host_ptr, new_params, overlaps);
436 }
437
438 const auto& old_surface{overlaps[0]};
439 const auto& old_params{old_surface->GetSurfaceParams()};
440 if (old_params.GetTarget() == new_params.GetTarget() &&
441 old_params.GetDepth() == new_params.GetDepth() && old_params.GetDepth() == 1 &&
442 old_params.GetNumLevels() == new_params.GetNumLevels() &&
443 old_params.GetPixelFormat() == new_params.GetPixelFormat()) {
444 return SurfaceCopy(gpu_addr, cpu_addr, host_ptr, new_params, old_surface, old_params);
445 }
446
447 return nullptr;
448}
449
450CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
451 const SurfaceParams& new_params,
452 const Surface& old_surface,
453 const SurfaceParams& old_params) {
454 const auto new_surface{GetUncachedSurface(new_params)};
455 Register(new_surface, gpu_addr, cpu_addr, host_ptr);
456
457 const u32 min_width{
458 std::max(old_params.GetDefaultBlockWidth(), new_params.GetDefaultBlockWidth())};
459 const u32 min_height{
460 std::max(old_params.GetDefaultBlockHeight(), new_params.GetDefaultBlockHeight())};
461 for (u32 level = 0; level < old_params.GetNumLevels(); ++level) {
462 const u32 width{std::min(old_params.GetMipWidth(level), new_params.GetMipWidth(level))};
463 const u32 height{std::min(old_params.GetMipHeight(level), new_params.GetMipHeight(level))};
464 if (width < min_width || height < min_height) {
465 // Avoid copies that are too small to be handled in OpenGL
466 break;
467 }
468 glCopyImageSubData(old_surface->GetTexture(), old_surface->GetTarget(), level, 0, 0, 0,
469 new_surface->GetTexture(), new_surface->GetTarget(), level, 0, 0, 0,
470 width, height, 1);
471 }
472
473 new_surface->MarkAsModified(true);
474
475 // TODO(Rodrigo): Add an entry to directly get the superview
476 return new_surface->GetView(gpu_addr, new_params);
477}
478
479CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(GPUVAddr gpu_addr, VAddr cpu_addr,
480 u8* host_ptr, const SurfaceParams& new_params,
481 const std::vector<Surface>& overlaps) {
482 if (new_params.GetTarget() == SurfaceTarget::Texture1D ||
483 new_params.GetTarget() == SurfaceTarget::Texture1DArray ||
484 new_params.GetTarget() == SurfaceTarget::Texture3D) {
485 // Non-2D textures are not handled at the moment in this fast path.
486 return nullptr;
487 }
488
489 const auto new_surface{GetUncachedSurface(new_params)};
490 // TODO(Rodrigo): Move this down
491 Register(new_surface, gpu_addr, cpu_addr, host_ptr);
492
493 // TODO(Rodrigo): Find a way to avoid heap allocations here.
494 std::vector<CachedSurfaceView*> views;
495 views.reserve(overlaps.size());
496 for (const auto& overlap : overlaps) {
497 const auto view{
498 new_surface->TryGetView(overlap->GetGpuAddr(), overlap->GetSurfaceParams())};
499 if (!view) {
500 // TODO(Rodrigo): Remove this
501 Unregister(new_surface);
502 return nullptr;
503 }
504 views.push_back(view);
505 }
506
507 // TODO(Rodrigo): It's possible that these method leaves some unloaded textures if the data has
508 // been uploaded to guest memory but not used as a surface previously.
509 for (std::size_t i = 0; i < overlaps.size(); ++i) {
510 const auto& overlap{overlaps[i]};
511 const auto& view{views[i]};
512 for (u32 overlap_level = 0; overlap_level < view->GetNumLevels(); ++overlap_level) {
513 const u32 super_level{view->GetBaseLevel() + overlap_level};
514 glCopyImageSubData(overlap->GetTexture(), overlap->GetTarget(), overlap_level, 0, 0, 0,
515 new_surface->GetTexture(), new_surface->GetTarget(), super_level, 0,
516 0, view->GetBaseLayer(), view->GetWidth(), view->GetHeight(),
517 view->GetNumLayers());
518 }
519 }
520
521 new_surface->MarkAsModified(true);
522
523 // TODO(Rodrigo): Add an entry to directly get the superview
524 return new_surface->GetView(gpu_addr, new_params);
525} 436}
526 437
527Surface TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) { 438void TextureCacheOpenGL::ImageCopy(Surface src_surface, Surface dst_surface,
528 return std::make_unique<CachedSurface>(*this, params); 439 const VideoCommon::CopyParams& copy_params) {
440 const auto src_handle = src_surface->GetTexture();
441 const auto src_target = src_surface->GetTarget();
442 const auto dst_handle = dst_surface->GetTexture();
443 const auto dst_target = dst_surface->GetTarget();
444 glCopyImageSubData(src_handle, src_target, copy_params.source_level, copy_params.source_x,
445 copy_params.source_y, copy_params.source_z, dst_handle, dst_target,
446 copy_params.dest_level, copy_params.dest_x, copy_params.dest_y,
447 copy_params.dest_z, copy_params.width, copy_params.height,
448 copy_params.depth);
529} 449}
530 450
531} // namespace OpenGL 451} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index c65e37153..1722c1bbc 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -19,24 +19,25 @@
19namespace OpenGL { 19namespace OpenGL {
20 20
21using VideoCommon::SurfaceParams; 21using VideoCommon::SurfaceParams;
22using VideoCommon::ViewKey; 22using VideoCommon::ViewParams;
23 23
24class CachedSurfaceView; 24class CachedSurfaceView;
25class CachedSurface; 25class CachedSurface;
26class TextureCacheOpenGL; 26class TextureCacheOpenGL;
27 27
28using Surface = std::shared_ptr<CachedSurface>; 28using Surface = std::shared_ptr<CachedSurface>;
29using TextureCacheBase = VideoCommon::TextureCache<CachedSurface, CachedSurfaceView>; 29using View = std::shared_ptr<CachedSurfaceView>;
30using TextureCacheBase = VideoCommon::TextureCache<Surface, View>;
30 31
31class CachedSurface final : public VideoCommon::SurfaceBase<TextureCacheOpenGL, CachedSurfaceView> { 32class CachedSurface final : public VideoCommon::SurfaceBase<View> {
32 friend CachedSurfaceView; 33 friend CachedSurfaceView;
33 34
34public: 35public:
35 explicit CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params); 36 explicit CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params);
36 ~CachedSurface(); 37 ~CachedSurface();
37 38
38 void UploadTexture(); 39 void UploadTexture(std::vector<u8>& staging_buffer) override;
39 void DownloadTexture(); 40 void DownloadTexture(std::vector<u8>& staging_buffer) override;
40 41
41 GLenum GetTarget() const { 42 GLenum GetTarget() const {
42 return target; 43 return target;
@@ -49,99 +50,79 @@ public:
49protected: 50protected:
50 void DecorateSurfaceName(); 51 void DecorateSurfaceName();
51 52
52 std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key); 53 View CreateView(const ViewParams& view_key) override;
53 54
54private: 55private:
55 void UploadTextureMipmap(u32 level); 56 void UploadTextureMipmap(u32 level, std::vector<u8>& staging_buffer);
56 57
57 GLenum internal_format{}; 58 GLenum internal_format{};
58 GLenum format{}; 59 GLenum format{};
59 GLenum type{}; 60 GLenum type{};
60 bool is_compressed{}; 61 bool is_compressed{};
61 GLenum target{}; 62 GLenum target{};
63 u32 view_count{};
62 64
63 OGLTexture texture; 65 OGLTexture texture;
64}; 66};
65 67
66class CachedSurfaceView final { 68class CachedSurfaceView final : public VideoCommon::ViewBase {
67public: 69public:
68 explicit CachedSurfaceView(CachedSurface& surface, ViewKey key); 70 explicit CachedSurfaceView(CachedSurface& surface, const ViewParams& params);
69 ~CachedSurfaceView(); 71 ~CachedSurfaceView();
70 72
71 /// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER 73 /// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER
72 void Attach(GLenum attachment) const; 74 void Attach(GLenum attachment) const;
73 75
74 GLuint GetTexture(Tegra::Shader::TextureType texture_type, bool is_array, 76 GLuint GetTexture() {
75 Tegra::Texture::SwizzleSource x_source, 77 return texture_view.texture.handle;
76 Tegra::Texture::SwizzleSource y_source,
77 Tegra::Texture::SwizzleSource z_source,
78 Tegra::Texture::SwizzleSource w_source);
79
80 void MarkAsModified(bool is_modified) {
81 surface.MarkAsModified(is_modified);
82 } 78 }
83 79
84 const SurfaceParams& GetSurfaceParams() const { 80 const SurfaceParams& GetSurfaceParams() const {
85 return params; 81 return surface.GetSurfaceParams();
86 } 82 }
87 83
88 u32 GetWidth() const { 84 u32 GetWidth() const {
89 return params.GetMipWidth(GetBaseLevel()); 85 const auto owner_params = GetSurfaceParams();
86 return owner_params.GetMipWidth(params.base_level);
90 } 87 }
91 88
92 u32 GetHeight() const { 89 u32 GetHeight() const {
93 return params.GetMipHeight(GetBaseLevel()); 90 const auto owner_params = GetSurfaceParams();
91 return owner_params.GetMipHeight(params.base_level);
94 } 92 }
95 93
96 u32 GetDepth() const { 94 u32 GetDepth() const {
97 return params.GetMipDepth(GetBaseLevel()); 95 const auto owner_params = GetSurfaceParams();
98 } 96 return owner_params.GetMipDepth(params.base_level);
99
100 u32 GetBaseLayer() const {
101 return key.base_layer;
102 } 97 }
103 98
104 u32 GetNumLayers() const { 99 void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
105 return key.num_layers; 100 Tegra::Texture::SwizzleSource y_source,
106 } 101 Tegra::Texture::SwizzleSource z_source,
107 102 Tegra::Texture::SwizzleSource w_source);
108 u32 GetBaseLevel() const {
109 return key.base_level;
110 }
111 103
112 u32 GetNumLevels() const { 104 void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
113 return key.num_levels;
114 }
115 105
116private: 106private:
117 struct TextureView { 107 struct TextureView {
118 OGLTexture texture; 108 OGLTextureView texture;
119 std::array<Tegra::Texture::SwizzleSource, 4> swizzle{ 109 u32 swizzle;
120 Tegra::Texture::SwizzleSource::R, Tegra::Texture::SwizzleSource::G,
121 Tegra::Texture::SwizzleSource::B, Tegra::Texture::SwizzleSource::A};
122 }; 110 };
123 111
124 void ApplySwizzle(TextureView& texture_view, Tegra::Texture::SwizzleSource x_source, 112 u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source,
125 Tegra::Texture::SwizzleSource y_source, 113 Tegra::Texture::SwizzleSource y_source,
126 Tegra::Texture::SwizzleSource z_source, 114 Tegra::Texture::SwizzleSource z_source,
127 Tegra::Texture::SwizzleSource w_source); 115 Tegra::Texture::SwizzleSource w_source) const {
128 116 return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) |
129 TextureView CreateTextureView(GLenum target) const; 117 (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source);
118 }
130 119
131 std::pair<std::reference_wrapper<TextureView>, GLenum> GetTextureView( 120 TextureView CreateTextureView() const;
132 Tegra::Shader::TextureType texture_type, bool is_array);
133 121
134 CachedSurface& surface; 122 CachedSurface& surface;
135 const ViewKey key; 123 GLenum target{};
136 const SurfaceParams params; 124
137 125 TextureView texture_view;
138 TextureView texture_view_1d;
139 TextureView texture_view_1d_array;
140 TextureView texture_view_2d;
141 TextureView texture_view_2d_array;
142 TextureView texture_view_3d;
143 TextureView texture_view_cube;
144 TextureView texture_view_cube_array;
145}; 126};
146 127
147class TextureCacheOpenGL final : public TextureCacheBase { 128class TextureCacheOpenGL final : public TextureCacheBase {
@@ -150,21 +131,9 @@ public:
150 ~TextureCacheOpenGL(); 131 ~TextureCacheOpenGL();
151 132
152protected: 133protected:
153 CachedSurfaceView* TryFastGetSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, 134 Surface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) override;
154 const SurfaceParams& new_params, 135 void ImageCopy(Surface src_surface, Surface dst_surface,
155 bool preserve_contents, 136 const VideoCommon::CopyParams& copy_params) override;
156 const std::vector<Surface>& overlaps);
157
158 Surface CreateSurface(const SurfaceParams& params);
159
160private:
161 CachedSurfaceView* SurfaceCopy(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
162 const SurfaceParams& new_params, const Surface& old_surface,
163 const SurfaceParams& old_params);
164
165 CachedSurfaceView* TryCopyAsViews(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
166 const SurfaceParams& new_params,
167 const std::vector<Surface>& overlaps);
168}; 137};
169 138
170} // namespace OpenGL 139} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/utils.cpp b/src/video_core/renderer_opengl/utils.cpp
index 5994c0c61..a9fa539a5 100644
--- a/src/video_core/renderer_opengl/utils.cpp
+++ b/src/video_core/renderer_opengl/utils.cpp
@@ -56,8 +56,7 @@ SurfaceBlitter::SurfaceBlitter() {
56 56
57SurfaceBlitter::~SurfaceBlitter() = default; 57SurfaceBlitter::~SurfaceBlitter() = default;
58 58
59void SurfaceBlitter::Blit(CachedSurfaceView* src, CachedSurfaceView* dst, 59void SurfaceBlitter::Blit(View src, View dst, const Common::Rectangle<u32>& src_rect,
60 const Common::Rectangle<u32>& src_rect,
61 const Common::Rectangle<u32>& dst_rect) const { 60 const Common::Rectangle<u32>& dst_rect) const {
62 const auto& src_params{src->GetSurfaceParams()}; 61 const auto& src_params{src->GetSurfaceParams()};
63 const auto& dst_params{dst->GetSurfaceParams()}; 62 const auto& dst_params{dst->GetSurfaceParams()};
@@ -72,17 +71,13 @@ void SurfaceBlitter::Blit(CachedSurfaceView* src, CachedSurfaceView* dst,
72 71
73 u32 buffers{}; 72 u32 buffers{};
74 73
75 UNIMPLEMENTED_IF(src_params.GetTarget() != SurfaceTarget::Texture2D); 74 UNIMPLEMENTED_IF(src_params.target != SurfaceTarget::Texture2D);
76 UNIMPLEMENTED_IF(dst_params.GetTarget() != SurfaceTarget::Texture2D); 75 UNIMPLEMENTED_IF(dst_params.target != SurfaceTarget::Texture2D);
77 76
78 const auto GetTexture = [](CachedSurfaceView* view) { 77 const GLuint src_texture{src->GetTexture()};
79 return view->GetTexture(TextureType::Texture2D, false, SwizzleSource::R, SwizzleSource::G, 78 const GLuint dst_texture{dst->GetTexture()};
80 SwizzleSource::B, SwizzleSource::A);
81 };
82 const GLuint src_texture{GetTexture(src)};
83 const GLuint dst_texture{GetTexture(dst)};
84 79
85 if (src_params.GetType() == SurfaceType::ColorTexture) { 80 if (src_params.type == SurfaceType::ColorTexture) {
86 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 81 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
87 src_texture, 0); 82 src_texture, 0);
88 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 83 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
@@ -94,7 +89,7 @@ void SurfaceBlitter::Blit(CachedSurfaceView* src, CachedSurfaceView* dst,
94 0); 89 0);
95 90
96 buffers = GL_COLOR_BUFFER_BIT; 91 buffers = GL_COLOR_BUFFER_BIT;
97 } else if (src_params.GetType() == SurfaceType::Depth) { 92 } else if (src_params.type == SurfaceType::Depth) {
98 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 93 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
99 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, src_texture, 94 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, src_texture,
100 0); 95 0);
@@ -106,7 +101,7 @@ void SurfaceBlitter::Blit(CachedSurfaceView* src, CachedSurfaceView* dst,
106 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 101 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
107 102
108 buffers = GL_DEPTH_BUFFER_BIT; 103 buffers = GL_DEPTH_BUFFER_BIT;
109 } else if (src_params.GetType() == SurfaceType::DepthStencil) { 104 } else if (src_params.type == SurfaceType::DepthStencil) {
110 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 105 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
111 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 106 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
112 src_texture, 0); 107 src_texture, 0);
@@ -148,4 +143,4 @@ void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string_vie
148 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str())); 143 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
149} 144}
150 145
151} // namespace OpenGL \ No newline at end of file 146} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/utils.h b/src/video_core/renderer_opengl/utils.h
index e7726d14e..8977d2383 100644
--- a/src/video_core/renderer_opengl/utils.h
+++ b/src/video_core/renderer_opengl/utils.h
@@ -39,8 +39,8 @@ public:
39 explicit SurfaceBlitter(); 39 explicit SurfaceBlitter();
40 ~SurfaceBlitter(); 40 ~SurfaceBlitter();
41 41
42 void Blit(CachedSurfaceView* src, CachedSurfaceView* dst, 42 void Blit(View src, View dst, const Common::Rectangle<u32>& src_rect,
43 const Common::Rectangle<u32>& src_rect, const Common::Rectangle<u32>& dst_rect) const; 43 const Common::Rectangle<u32>& dst_rect) const;
44 44
45private: 45private:
46 OGLFramebuffer src_framebuffer; 46 OGLFramebuffer src_framebuffer;
@@ -49,4 +49,4 @@ private:
49 49
50void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string_view extra_info = {}); 50void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string_view extra_info = {});
51 51
52} // namespace OpenGL \ No newline at end of file 52} // namespace OpenGL
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index c5c01957a..eb0d9bc10 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -22,6 +22,7 @@
22#include "video_core/memory_manager.h" 22#include "video_core/memory_manager.h"
23#include "video_core/rasterizer_interface.h" 23#include "video_core/rasterizer_interface.h"
24#include "video_core/surface.h" 24#include "video_core/surface.h"
25#include "video_core/texture_cache/copy_params.h"
25#include "video_core/texture_cache/surface_base.h" 26#include "video_core/texture_cache/surface_base.h"
26#include "video_core/texture_cache/surface_params.h" 27#include "video_core/texture_cache/surface_params.h"
27#include "video_core/texture_cache/surface_view.h" 28#include "video_core/texture_cache/surface_view.h"
@@ -40,32 +41,42 @@ class RasterizerInterface;
40 41
41namespace VideoCommon { 42namespace VideoCommon {
42 43
44using VideoCore::Surface::SurfaceTarget;
45using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig;
46
43template <typename TSurface, typename TView> 47template <typename TSurface, typename TView>
44class TextureCache { 48class TextureCache {
45 using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>; 49 using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<TSurface>>;
46 using IntervalType = typename IntervalMap::interval_type; 50 using IntervalType = typename IntervalMap::interval_type;
47 51
48public: 52public:
53 void InitMemoryMananger(Tegra::MemoryManager& memory_manager) {
54 this->memory_manager = &memory_manager;
55 }
56
49 void InvalidateRegion(CacheAddr addr, std::size_t size) { 57 void InvalidateRegion(CacheAddr addr, std::size_t size) {
50 for (const auto& surface : GetSurfacesInRegion(addr, size)) { 58 for (const auto& surface : GetSurfacesInRegion(addr, size)) {
51 if (!surface->IsRegistered()) {
52 // Skip duplicates
53 continue;
54 }
55 Unregister(surface); 59 Unregister(surface);
56 } 60 }
57 } 61 }
58 62
59 TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { 63 void InvalidateRegionEx(GPUVAddr addr, std::size_t size) {
64 for (const auto& surface : GetSurfacesInRegionInner(addr, size)) {
65 Unregister(surface);
66 }
67 }
68
69 TView GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
70 const VideoCommon::Shader::Sampler& entry) {
60 const auto gpu_addr{config.tic.Address()}; 71 const auto gpu_addr{config.tic.Address()};
61 if (!gpu_addr) { 72 if (!gpu_addr) {
62 return {}; 73 return {};
63 } 74 }
64 const auto params{SurfaceParams::CreateForTexture(system, config)}; 75 const auto params{SurfaceParams::CreateForTexture(system, config, entry)};
65 return GetSurfaceView(gpu_addr, params, true); 76 return GetSurface(gpu_addr, params, true).second;
66 } 77 }
67 78
68 TView* GetDepthBufferSurface(bool preserve_contents) { 79 TView GetDepthBufferSurface(bool preserve_contents) {
69 const auto& regs{system.GPU().Maxwell3D().regs}; 80 const auto& regs{system.GPU().Maxwell3D().regs};
70 const auto gpu_addr{regs.zeta.Address()}; 81 const auto gpu_addr{regs.zeta.Address()};
71 if (!gpu_addr || !regs.zeta_enable) { 82 if (!gpu_addr || !regs.zeta_enable) {
@@ -75,36 +86,75 @@ public:
75 system, regs.zeta_width, regs.zeta_height, regs.zeta.format, 86 system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
76 regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, 87 regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
77 regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; 88 regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
78 return GetSurfaceView(gpu_addr, depth_params, preserve_contents); 89 auto surface_view = GetSurface(gpu_addr, depth_params, preserve_contents);
90 if (depth_buffer.target)
91 depth_buffer.target->MarkAsProtected(false);
92 if (depth_buffer.target)
93 depth_buffer.target->MarkAsProtected(true);
94 return surface_view.second;
79 } 95 }
80 96
81 TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) { 97 TView GetColorBufferSurface(std::size_t index, bool preserve_contents) {
82 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); 98 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
83 99
84 const auto& regs{system.GPU().Maxwell3D().regs}; 100 const auto& regs{system.GPU().Maxwell3D().regs};
85 if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 || 101 if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
86 regs.rt[index].format == Tegra::RenderTargetFormat::NONE) { 102 regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
103 SetEmptyColorBuffer(index);
87 return {}; 104 return {};
88 } 105 }
89 106
90 auto& memory_manager{system.GPU().MemoryManager()}; 107 const auto& config{regs.rt[index]};
91 const auto& config{system.GPU().Maxwell3D().regs.rt[index]}; 108 const auto gpu_addr{config.Address()};
92 const auto gpu_addr{config.Address() +
93 config.base_layer * config.layer_stride * sizeof(u32)};
94 if (!gpu_addr) { 109 if (!gpu_addr) {
110 SetEmptyColorBuffer(index);
95 return {}; 111 return {};
96 } 112 }
97 113
98 return GetSurfaceView(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), 114 auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
99 preserve_contents); 115 preserve_contents);
116 if (render_targets[index].target)
117 render_targets[index].target->MarkAsProtected(false);
118 render_targets[index].target = surface_view.first;
119 if (render_targets[index].target)
120 render_targets[index].target->MarkAsProtected(true);
121 return surface_view.second;
122 }
123
124 void MarkColorBufferInUse(std::size_t index) {
125 if (render_targets[index].target)
126 render_targets[index].target->MarkAsModified(true, Tick());
100 } 127 }
101 128
102 TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) { 129 void MarkDepthBufferInUse() {
103 return GetSurfaceView(config.Address(), SurfaceParams::CreateForFermiCopySurface(config), 130 if (depth_buffer.target)
104 true); 131 depth_buffer.target->MarkAsModified(true, Tick());
105 } 132 }
106 133
107 std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const { 134 void SetEmptyDepthBuffer() {
135 if (depth_buffer.target != nullptr) {
136 depth_buffer.target->MarkAsProtected(false);
137 depth_buffer.target = nullptr;
138 depth_buffer.view = nullptr;
139 }
140 }
141
142 void SetEmptyColorBuffer(std::size_t index) {
143 if (render_targets[index].target != nullptr) {
144 render_targets[index].target->MarkAsProtected(false);
145 std::memset(&render_targets[index].config, sizeof(RenderTargetConfig), 0);
146 render_targets[index].target = nullptr;
147 render_targets[index].view = nullptr;
148 }
149 }
150
151 TView GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
152 SurfaceParams params = SurfaceParams::CreateForFermiCopySurface(config);
153 const GPUVAddr gpu_addr = config.Address();
154 return GetSurface(gpu_addr, params, true).second;
155 }
156
157 TSurface TryFindFramebufferSurface(const u8* host_ptr) const {
108 const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))}; 158 const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
109 return it != registered_surfaces.end() ? *it->second.begin() : nullptr; 159 return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
110 } 160 }
@@ -115,126 +165,334 @@ public:
115 165
116protected: 166protected:
117 TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer) 167 TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
118 : system{system}, rasterizer{rasterizer} {} 168 : system{system}, rasterizer{rasterizer} {
169 for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
170 SetEmptyColorBuffer(i);
171 }
172 SetEmptyDepthBuffer();
173 }
119 174
120 ~TextureCache() = default; 175 ~TextureCache() = default;
121 176
122 virtual TView* TryFastGetSurfaceView( 177 virtual TSurface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) = 0;
123 GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
124 bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
125 178
126 virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0; 179 virtual void ImageCopy(TSurface src_surface, TSurface dst_surface,
180 const CopyParams& copy_params) = 0;
127 181
128 void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr, 182 void Register(TSurface surface) {
129 u8* host_ptr) { 183 const GPUVAddr gpu_addr = surface->GetGpuAddr();
130 surface->Register(gpu_addr, cpu_addr, host_ptr); 184 u8* host_ptr = memory_manager->GetPointer(gpu_addr);
131 registered_surfaces.add({GetSurfaceInterval(surface), {surface}}); 185 const std::size_t size = surface->GetSizeInBytes();
132 rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1); 186 const std::optional<VAddr> cpu_addr = memory_manager->GpuToCpuAddress(gpu_addr);
187 if (!host_ptr || !cpu_addr) {
188 LOG_CRITICAL(HW_GPU, "Failed to register surface with unmapped gpu_address 0x{:016x}",
189 gpu_addr);
190 return;
191 }
192 surface->SetHostPtr(host_ptr);
193 surface->SetCpuAddr(*cpu_addr);
194 registered_surfaces.add({GetInterval(host_ptr, size), {surface}});
195 rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
196 RegisterInnerCache(surface);
197 surface->MarkAsRegistered(true);
133 } 198 }
134 199
135 void Unregister(std::shared_ptr<TSurface> surface) { 200 void Unregister(TSurface surface) {
136 registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}}); 201 if (surface->IsProtected())
137 rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1); 202 return;
138 surface->Unregister(); 203 const GPUVAddr gpu_addr = surface->GetGpuAddr();
204 const void* host_ptr = surface->GetHostPtr();
205 const std::size_t size = surface->GetSizeInBytes();
206 const VAddr cpu_addr = surface->GetCpuAddr();
207 registered_surfaces.erase(GetInterval(host_ptr, size));
208 rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1);
209 UnregisterInnerCache(surface);
210 surface->MarkAsRegistered(false);
211 ReserveSurface(surface->GetSurfaceParams(), surface);
139 } 212 }
140 213
141 std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) { 214 TSurface GetUncachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) {
142 if (const auto surface = TryGetReservedSurface(params); surface) 215 if (const auto surface = TryGetReservedSurface(params); surface) {
216 surface->SetGpuAddr(gpu_addr);
143 return surface; 217 return surface;
218 }
144 // No reserved surface available, create a new one and reserve it 219 // No reserved surface available, create a new one and reserve it
145 auto new_surface{CreateSurface(params)}; 220 auto new_surface{CreateSurface(gpu_addr, params)};
146 ReserveSurface(params, new_surface);
147 return new_surface; 221 return new_surface;
148 } 222 }
149 223
150 Core::System& system; 224 Core::System& system;
151 225
152private: 226private:
153 TView* GetSurfaceView(GPUVAddr gpu_addr, const SurfaceParams& params, bool preserve_contents) { 227 enum class RecycleStrategy : u32 {
154 auto& memory_manager{system.GPU().MemoryManager()}; 228 Ignore = 0,
155 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; 229 Flush = 1,
156 DEBUG_ASSERT(cpu_addr); 230 BufferCopy = 3,
157 231 };
158 const auto host_ptr{memory_manager.GetPointer(gpu_addr)}; 232
159 const auto cache_addr{ToCacheAddr(host_ptr)}; 233 RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params,
160 auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())}; 234 const GPUVAddr gpu_addr, const bool untopological) {
161 if (overlaps.empty()) { 235 // Untopological decision
162 return LoadSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); 236 if (untopological) {
237 return RecycleStrategy::Ignore;
238 }
239 // 3D Textures decision
240 if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) {
241 return RecycleStrategy::Flush;
163 } 242 }
243 for (auto s : overlaps) {
244 const auto& s_params = s->GetSurfaceParams();
245 if (s_params.block_depth > 1 || s_params.target == SurfaceTarget::Texture3D) {
246 return RecycleStrategy::Flush;
247 }
248 }
249 return RecycleStrategy::Ignore;
250 }
164 251
165 if (overlaps.size() == 1) { 252 std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
166 if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) { 253 const SurfaceParams& params, const GPUVAddr gpu_addr,
167 return view; 254 const u8* host_ptr, const bool preserve_contents,
255 const bool untopological) {
256 for (auto surface : overlaps) {
257 Unregister(surface);
258 }
259 RecycleStrategy strategy = !Settings::values.use_accurate_gpu_emulation
260 ? PickStrategy(overlaps, params, gpu_addr, untopological)
261 : RecycleStrategy::Flush;
262 switch (strategy) {
263 case RecycleStrategy::Ignore: {
264 return InitializeSurface(gpu_addr, params, preserve_contents);
265 }
266 case RecycleStrategy::Flush: {
267 std::sort(overlaps.begin(), overlaps.end(),
268 [](const TSurface& a, const TSurface& b) -> bool {
269 return a->GetModificationTick() < b->GetModificationTick();
270 });
271 for (auto surface : overlaps) {
272 FlushSurface(surface);
168 } 273 }
274 return InitializeSurface(gpu_addr, params, preserve_contents);
169 } 275 }
276 default: {
277 UNIMPLEMENTED_MSG("Unimplemented Texture Cache Recycling Strategy!");
278 return InitializeSurface(gpu_addr, params, preserve_contents);
279 }
280 }
281 }
170 282
171 const auto fast_view{TryFastGetSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, 283 std::pair<TSurface, TView> RebuildMirage(TSurface current_surface,
172 preserve_contents, overlaps)}; 284 const SurfaceParams& params) {
285 const auto gpu_addr = current_surface->GetGpuAddr();
286 TSurface new_surface = GetUncachedSurface(gpu_addr, params);
287 std::vector<CopyParams> bricks = current_surface->BreakDown();
288 for (auto& brick : bricks) {
289 ImageCopy(current_surface, new_surface, brick);
290 }
291 Unregister(current_surface);
292 Register(new_surface);
293 return {new_surface, new_surface->GetMainView()};
294 }
173 295
174 if (!fast_view) { 296 std::pair<TSurface, TView> ManageStructuralMatch(TSurface current_surface,
175 std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) { 297 const SurfaceParams& params) {
176 return lhs->GetModificationTick() < rhs->GetModificationTick(); 298 const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
177 }); 299 if (is_mirage) {
300 return RebuildMirage(current_surface, params);
178 } 301 }
302 const bool matches_target = current_surface->MatchTarget(params.target);
303 if (matches_target) {
304 return {current_surface, current_surface->GetMainView()};
305 }
306 return {current_surface, current_surface->EmplaceOverview(params)};
307 }
179 308
180 for (const auto& surface : overlaps) { 309 std::optional<std::pair<TSurface, TView>> ReconstructSurface(std::vector<TSurface>& overlaps,
181 if (!fast_view) { 310 const SurfaceParams& params,
182 // Flush even when we don't care about the contents, to preserve memory not 311 const GPUVAddr gpu_addr,
183 // written by the new surface. 312 const u8* host_ptr) {
184 FlushSurface(surface); 313 if (!params.is_layered || params.target == SurfaceTarget::Texture3D) {
314 return {};
315 }
316 TSurface new_surface = GetUncachedSurface(gpu_addr, params);
317 for (auto surface : overlaps) {
318 const SurfaceParams& src_params = surface->GetSurfaceParams();
319 if (src_params.is_layered || src_params.num_levels > 1) {
320 // We send this cases to recycle as they are more complex to handle
321 return {};
322 }
323 const std::size_t candidate_size = src_params.GetGuestSizeInBytes();
324 auto mipmap_layer = new_surface->GetLayerMipmap(surface->GetGpuAddr());
325 if (!mipmap_layer) {
326 return {};
185 } 327 }
328 const u32 layer = (*mipmap_layer).first;
329 const u32 mipmap = (*mipmap_layer).second;
330 if (new_surface->GetMipmapSize(mipmap) != candidate_size) {
331 return {};
332 }
333 // Now we got all the data set up
334 CopyParams copy_params{};
335 const u32 dst_width = params.GetMipWidth(mipmap);
336 const u32 dst_height = params.GetMipHeight(mipmap);
337 copy_params.width = std::min(src_params.width, dst_width);
338 copy_params.height = std::min(src_params.height, dst_height);
339 copy_params.depth = 1;
340 copy_params.source_level = 0;
341 copy_params.dest_level = mipmap;
342 copy_params.source_z = 0;
343 copy_params.dest_z = layer;
344 ImageCopy(surface, new_surface, copy_params);
345 }
346 for (auto surface : overlaps) {
186 Unregister(surface); 347 Unregister(surface);
187 } 348 }
188 if (fast_view) { 349 Register(new_surface);
189 return fast_view; 350 return {{new_surface, new_surface->GetMainView()}};
351 }
352
353 std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params,
354 bool preserve_contents) {
355
356 const auto host_ptr{memory_manager->GetPointer(gpu_addr)};
357 const auto cache_addr{ToCacheAddr(host_ptr)};
358 const std::size_t candidate_size = params.GetGuestSizeInBytes();
359 auto overlaps{GetSurfacesInRegionInner(gpu_addr, candidate_size)};
360 if (overlaps.empty()) {
361 return InitializeSurface(gpu_addr, params, preserve_contents);
362 }
363
364 for (auto surface : overlaps) {
365 if (!surface->MatchesTopology(params)) {
366 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
367 true);
368 }
190 } 369 }
191 370
192 return LoadSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); 371 if (overlaps.size() == 1) {
372 TSurface current_surface = overlaps[0];
373 if (current_surface->MatchesStructure(params) &&
374 current_surface->GetGpuAddr() == gpu_addr &&
375 (params.target != SurfaceTarget::Texture3D ||
376 current_surface->MatchTarget(params.target))) {
377 return ManageStructuralMatch(current_surface, params);
378 }
379 if (current_surface->GetSizeInBytes() <= candidate_size) {
380 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
381 false);
382 }
383 std::optional<TView> view = current_surface->EmplaceView(params, gpu_addr);
384 if (view.has_value()) {
385 const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
386 if (is_mirage) {
387 LOG_CRITICAL(HW_GPU, "Mirage View Unsupported");
388 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
389 false);
390 }
391 return {current_surface, *view};
392 }
393 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false);
394 } else {
395 std::optional<std::pair<TSurface, TView>> view =
396 ReconstructSurface(overlaps, params, gpu_addr, host_ptr);
397 if (view.has_value()) {
398 return *view;
399 }
400 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false);
401 }
193 } 402 }
194 403
195 TView* LoadSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, 404 std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params,
196 const SurfaceParams& params, bool preserve_contents) { 405 bool preserve_contents) {
197 const auto new_surface{GetUncachedSurface(params)}; 406 auto new_surface{GetUncachedSurface(gpu_addr, params)};
198 Register(new_surface, gpu_addr, cpu_addr, host_ptr); 407 Register(new_surface);
199 if (preserve_contents) { 408 if (preserve_contents) {
200 LoadSurface(new_surface); 409 LoadSurface(new_surface);
201 } 410 }
202 return new_surface->GetView(gpu_addr, params); 411 return {new_surface, new_surface->GetMainView()};
203 } 412 }
204 413
205 void LoadSurface(const std::shared_ptr<TSurface>& surface) { 414 void LoadSurface(const TSurface& surface) {
206 surface->LoadBuffer(); 415 staging_buffer.resize(surface->GetHostSizeInBytes());
207 surface->UploadTexture(); 416 surface->LoadBuffer(*memory_manager, staging_buffer);
208 surface->MarkAsModified(false); 417 surface->UploadTexture(staging_buffer);
418 surface->MarkAsModified(false, Tick());
209 } 419 }
210 420
211 void FlushSurface(const std::shared_ptr<TSurface>& surface) { 421 void FlushSurface(const TSurface& surface) {
212 if (!surface->IsModified()) { 422 if (!surface->IsModified()) {
213 return; 423 return;
214 } 424 }
215 surface->DownloadTexture(); 425 staging_buffer.resize(surface->GetHostSizeInBytes());
216 surface->FlushBuffer(); 426 surface->DownloadTexture(staging_buffer);
427 surface->FlushBuffer(staging_buffer);
428 surface->MarkAsModified(false, Tick());
217 } 429 }
218 430
219 std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr, 431 std::vector<TSurface> GetSurfacesInRegion(CacheAddr cache_addr, std::size_t size) const {
220 std::size_t size) const {
221 if (size == 0) { 432 if (size == 0) {
222 return {}; 433 return {};
223 } 434 }
224 const IntervalType interval{cache_addr, cache_addr + size}; 435 const IntervalType interval{cache_addr, cache_addr + size};
225 436
226 std::vector<std::shared_ptr<TSurface>> surfaces; 437 std::vector<TSurface> surfaces;
227 for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) { 438 for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
228 surfaces.push_back(*pair.second.begin()); 439 for (auto& s : pair.second) {
440 if (!s || !s->IsRegistered()) {
441 continue;
442 }
443 surfaces.push_back(s);
444 }
229 } 445 }
230 return surfaces; 446 return surfaces;
231 } 447 }
232 448
233 void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) { 449 void RegisterInnerCache(TSurface& surface) {
450 GPUVAddr start = surface->GetGpuAddr() >> inner_cache_page_bits;
451 const GPUVAddr end = (surface->GetGpuAddrEnd() - 1) >> inner_cache_page_bits;
452 while (start <= end) {
453 inner_cache[start].push_back(surface);
454 start++;
455 }
456 }
457
458 void UnregisterInnerCache(TSurface& surface) {
459 GPUVAddr start = surface->GetGpuAddr() >> inner_cache_page_bits;
460 const GPUVAddr end = (surface->GetGpuAddrEnd() - 1) >> inner_cache_page_bits;
461 while (start <= end) {
462 inner_cache[start].remove(surface);
463 start++;
464 }
465 }
466
467 std::vector<TSurface> GetSurfacesInRegionInner(const GPUVAddr gpu_addr, const std::size_t size) {
468 if (size == 0) {
469 return {};
470 }
471 const GPUVAddr gpu_addr_end = gpu_addr + size;
472 GPUVAddr start = gpu_addr >> inner_cache_page_bits;
473 const GPUVAddr end = (gpu_addr_end - 1) >> inner_cache_page_bits;
474 std::vector<TSurface> surfaces;
475 while (start <= end) {
476 std::list<TSurface>& list = inner_cache[start];
477 for (auto& s : list) {
478 if (!s->IsPicked() && s->Overlaps(gpu_addr, gpu_addr_end)) {
479 s->MarkAsPicked(true);
480 surfaces.push_back(s);
481 }
482 }
483 start++;
484 }
485 for (auto& s : surfaces) {
486 s->MarkAsPicked(false);
487 }
488 return surfaces;
489 }
490
491 void ReserveSurface(const SurfaceParams& params, TSurface surface) {
234 surface_reserve[params].push_back(std::move(surface)); 492 surface_reserve[params].push_back(std::move(surface));
235 } 493 }
236 494
237 std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) { 495 TSurface TryGetReservedSurface(const SurfaceParams& params) {
238 auto search{surface_reserve.find(params)}; 496 auto search{surface_reserve.find(params)};
239 if (search == surface_reserve.end()) { 497 if (search == surface_reserve.end()) {
240 return {}; 498 return {};
@@ -247,21 +505,41 @@ private:
247 return {}; 505 return {};
248 } 506 }
249 507
250 IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const { 508 IntervalType GetInterval(const void* host_ptr, const std::size_t size) const {
251 return IntervalType::right_open(surface->GetCacheAddr(), 509 const CacheAddr addr = ToCacheAddr(host_ptr);
252 surface->GetCacheAddr() + surface->GetSizeInBytes()); 510 return IntervalType::right_open(addr, addr + size);
253 } 511 }
254 512
513 struct RenderInfo {
514 RenderTargetConfig config;
515 TSurface target;
516 TView view;
517 };
518
519 struct DepthBufferInfo {
520 TSurface target;
521 TView view;
522 };
523
255 VideoCore::RasterizerInterface& rasterizer; 524 VideoCore::RasterizerInterface& rasterizer;
525 Tegra::MemoryManager* memory_manager;
256 526
257 u64 ticks{}; 527 u64 ticks{};
258 528
259 IntervalMap registered_surfaces; 529 IntervalMap registered_surfaces;
260 530
531 static constexpr u64 inner_cache_page_bits{20};
532 static constexpr u64 inner_cache_page_size{1 << inner_cache_page_bits};
533 std::unordered_map<GPUVAddr, std::list<TSurface>> inner_cache;
534
261 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have 535 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
262 /// previously been used. This is to prevent surfaces from being constantly created and 536 /// previously been used. This is to prevent surfaces from being constantly created and
263 /// destroyed when used with different surface parameters. 537 /// destroyed when used with different surface parameters.
264 std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve; 538 std::unordered_map<SurfaceParams, std::list<TSurface>> surface_reserve;
539 std::array<RenderInfo, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> render_targets;
540 DepthBufferInfo depth_buffer;
541
542 std::vector<u8> staging_buffer;
265}; 543};
266 544
267} // namespace VideoCommon 545} // namespace VideoCommon