diff options
| author | 2019-05-07 10:57:16 -0400 | |
|---|---|---|
| committer | 2019-06-20 21:36:12 -0300 | |
| commit | bc930754cc9437ddd86e7d246b3eb4302540896a (patch) | |
| tree | 75e56e5e041db7b327a13c25ab13bc524458dc29 | |
| parent | Correct Surface Base and Views for new Texture Cache (diff) | |
| download | yuzu-bc930754cc9437ddd86e7d246b3eb4302540896a.tar.gz yuzu-bc930754cc9437ddd86e7d246b3eb4302540896a.tar.xz yuzu-bc930754cc9437ddd86e7d246b3eb4302540896a.zip | |
Implement Texture Cache V2
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 69 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.cpp | 286 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.h | 111 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/utils.cpp | 23 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/utils.h | 6 | ||||
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 454 |
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 | ||
| 116 | RasterizerOpenGL::~RasterizerOpenGL() {} | 116 | RasterizerOpenGL::~RasterizerOpenGL() {} |
| 117 | 117 | ||
| 118 | void RasterizerOpenGL::InitMemoryMananger(Tegra::MemoryManager& memory_manager) { | ||
| 119 | texture_cache.InitMemoryMananger(memory_manager); | ||
| 120 | } | ||
| 121 | |||
| 118 | void RasterizerOpenGL::CheckExtensions() { | 122 | void 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 | ||
| 740 | void 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 | |||
| 731 | void RasterizerOpenGL::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { | 751 | void 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 | ||
| 756 | void RasterizerOpenGL::FlushAndInvalidateRegionEx(GPUVAddr gpu_addr, CacheAddr addr, u64 size) { | ||
| 757 | FlushRegion(addr, size); | ||
| 758 | InvalidateRegionEx(gpu_addr, addr, size); | ||
| 759 | } | ||
| 760 | |||
| 736 | bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, | 761 | bool 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; | |||
| 22 | using VideoCore::Surface::PixelFormat; | 24 | using VideoCore::Surface::PixelFormat; |
| 23 | using VideoCore::Surface::SurfaceTarget; | 25 | using VideoCore::Surface::SurfaceTarget; |
| 24 | 26 | ||
| 27 | MICROPROFILE_DEFINE(OpenGL_Texture_Upload, "OpenGL", "Texture Upload", MP_RGB(128, 192, 128)); | ||
| 28 | MICROPROFILE_DEFINE(OpenGL_Texture_Download, "OpenGL", "Texture Download", MP_RGB(128, 192, 128)); | ||
| 29 | |||
| 25 | namespace { | 30 | namespace { |
| 26 | 31 | ||
| 27 | struct FormatTuple { | 32 | struct FormatTuple { |
| @@ -129,8 +134,8 @@ const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType compon | |||
| 129 | return format; | 134 | return format; |
| 130 | } | 135 | } |
| 131 | 136 | ||
| 132 | GLenum GetTextureTarget(const SurfaceParams& params) { | 137 | GLenum 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 | ||
| 215 | CachedSurface::CachedSurface(TextureCacheOpenGL& texture_cache, const SurfaceParams& params) | 219 | CachedSurface::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 | |||
| 239 | CachedSurface::~CachedSurface() { | ||
| 240 | views.clear(); | ||
| 241 | main_view = nullptr; | ||
| 224 | } | 242 | } |
| 225 | 243 | ||
| 226 | CachedSurface::~CachedSurface() = default; | 244 | void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { |
| 245 | LOG_CRITICAL(Render_OpenGL, "Flushing"); | ||
| 246 | MICROPROFILE_SCOPE(OpenGL_Texture_Download); | ||
| 227 | 247 | ||
| 228 | void 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 | ||
| 247 | void CachedSurface::UploadTexture() { | 267 | void 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 | ||
| 254 | void CachedSurface::UploadTextureMipmap(u32 level) { | 275 | void 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 | ||
| 326 | void CachedSurface::DecorateSurfaceName() { | 348 | void 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 | |||
| 352 | void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, std::string prefix) { | ||
| 353 | LabelGLObject(GL_TEXTURE, texture_view.texture.handle, gpu_addr, prefix); | ||
| 329 | } | 354 | } |
| 330 | 355 | ||
| 331 | std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) { | 356 | View 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 | ||
| 335 | CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, ViewKey key) | 363 | CachedSurfaceView::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 | ||
| 338 | CachedSurfaceView::~CachedSurfaceView() = default; | 369 | CachedSurfaceView::~CachedSurfaceView() = default; |
| 339 | 370 | ||
| 340 | void CachedSurfaceView::Attach(GLenum attachment) const { | 371 | void 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 | ||
| 364 | GLuint CachedSurfaceView::GetTexture(Tegra::Shader::TextureType texture_type, bool is_array, | 395 | void 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 | |||
| 375 | void 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 | ||
| 389 | CachedSurfaceView::TextureView CachedSurfaceView::CreateTextureView(GLenum target) const { | 407 | CachedSurfaceView::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 | ||
| 403 | std::pair<std::reference_wrapper<CachedSurfaceView::TextureView>, GLenum> | 421 | u32 swizzle = |
| 404 | CachedSurfaceView::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 | ||
| 423 | TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, | 428 | TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, |
| @@ -426,106 +431,21 @@ TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, | |||
| 426 | 431 | ||
| 427 | TextureCacheOpenGL::~TextureCacheOpenGL() = default; | 432 | TextureCacheOpenGL::~TextureCacheOpenGL() = default; |
| 428 | 433 | ||
| 429 | CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, | 434 | Surface 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 | |||
| 450 | CachedSurfaceView* 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 | |||
| 479 | CachedSurfaceView* 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 | ||
| 527 | Surface TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) { | 438 | void 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 @@ | |||
| 19 | namespace OpenGL { | 19 | namespace OpenGL { |
| 20 | 20 | ||
| 21 | using VideoCommon::SurfaceParams; | 21 | using VideoCommon::SurfaceParams; |
| 22 | using VideoCommon::ViewKey; | 22 | using VideoCommon::ViewParams; |
| 23 | 23 | ||
| 24 | class CachedSurfaceView; | 24 | class CachedSurfaceView; |
| 25 | class CachedSurface; | 25 | class CachedSurface; |
| 26 | class TextureCacheOpenGL; | 26 | class TextureCacheOpenGL; |
| 27 | 27 | ||
| 28 | using Surface = std::shared_ptr<CachedSurface>; | 28 | using Surface = std::shared_ptr<CachedSurface>; |
| 29 | using TextureCacheBase = VideoCommon::TextureCache<CachedSurface, CachedSurfaceView>; | 29 | using View = std::shared_ptr<CachedSurfaceView>; |
| 30 | using TextureCacheBase = VideoCommon::TextureCache<Surface, View>; | ||
| 30 | 31 | ||
| 31 | class CachedSurface final : public VideoCommon::SurfaceBase<TextureCacheOpenGL, CachedSurfaceView> { | 32 | class CachedSurface final : public VideoCommon::SurfaceBase<View> { |
| 32 | friend CachedSurfaceView; | 33 | friend CachedSurfaceView; |
| 33 | 34 | ||
| 34 | public: | 35 | public: |
| 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: | |||
| 49 | protected: | 50 | protected: |
| 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 | ||
| 54 | private: | 55 | private: |
| 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 | ||
| 66 | class CachedSurfaceView final { | 68 | class CachedSurfaceView final : public VideoCommon::ViewBase { |
| 67 | public: | 69 | public: |
| 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 | ||
| 116 | private: | 106 | private: |
| 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 | ||
| 147 | class TextureCacheOpenGL final : public TextureCacheBase { | 128 | class TextureCacheOpenGL final : public TextureCacheBase { |
| @@ -150,21 +131,9 @@ public: | |||
| 150 | ~TextureCacheOpenGL(); | 131 | ~TextureCacheOpenGL(); |
| 151 | 132 | ||
| 152 | protected: | 133 | protected: |
| 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 | |||
| 160 | private: | ||
| 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 | ||
| 57 | SurfaceBlitter::~SurfaceBlitter() = default; | 57 | SurfaceBlitter::~SurfaceBlitter() = default; |
| 58 | 58 | ||
| 59 | void SurfaceBlitter::Blit(CachedSurfaceView* src, CachedSurfaceView* dst, | 59 | void 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 | ||
| 45 | private: | 45 | private: |
| 46 | OGLFramebuffer src_framebuffer; | 46 | OGLFramebuffer src_framebuffer; |
| @@ -49,4 +49,4 @@ private: | |||
| 49 | 49 | ||
| 50 | void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string_view extra_info = {}); | 50 | void 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 | ||
| 41 | namespace VideoCommon { | 42 | namespace VideoCommon { |
| 42 | 43 | ||
| 44 | using VideoCore::Surface::SurfaceTarget; | ||
| 45 | using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig; | ||
| 46 | |||
| 43 | template <typename TSurface, typename TView> | 47 | template <typename TSurface, typename TView> |
| 44 | class TextureCache { | 48 | class 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 | ||
| 48 | public: | 52 | public: |
| 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 | ||
| 116 | protected: | 166 | protected: |
| 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 | ||
| 152 | private: | 226 | private: |
| 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 |