diff options
| author | 2019-04-16 20:01:07 -0300 | |
|---|---|---|
| committer | 2019-06-20 21:36:11 -0300 | |
| commit | 4b396f375c0d32b60595f224d06b1b63d6df6b0a (patch) | |
| tree | d61b116481b20802deee2472735e83c053901454 /src | |
| parent | gl_texture_cache: Add copy from multiple overlaps into a single surface (diff) | |
| download | yuzu-4b396f375c0d32b60595f224d06b1b63d6df6b0a.tar.gz yuzu-4b396f375c0d32b60595f224d06b1b63d6df6b0a.tar.xz yuzu-4b396f375c0d32b60595f224d06b1b63d6df6b0a.zip | |
gl_texture_cache: Minor changes
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.cpp | 50 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.h | 20 | ||||
| -rw-r--r-- | src/video_core/texture_cache.cpp | 72 | ||||
| -rw-r--r-- | src/video_core/texture_cache.h | 175 |
5 files changed, 185 insertions, 140 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 07c28357e..af63365a4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -498,8 +498,8 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | |||
| 498 | color_surface->MarkAsModified(true); | 498 | color_surface->MarkAsModified(true); |
| 499 | // Workaround for and issue in nvidia drivers | 499 | // Workaround for and issue in nvidia drivers |
| 500 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ | 500 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ |
| 501 | // state.framebuffer_srgb.enabled |= | 501 | state.framebuffer_srgb.enabled |= |
| 502 | // color_surface->GetSurfaceParams().srgb_conversion; | 502 | color_surface->GetSurfaceParams().GetSrgbConversion(); |
| 503 | } | 503 | } |
| 504 | 504 | ||
| 505 | fbkey.is_single_buffer = true; | 505 | fbkey.is_single_buffer = true; |
| @@ -519,8 +519,8 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | |||
| 519 | // Enable sRGB only for supported formats | 519 | // Enable sRGB only for supported formats |
| 520 | // Workaround for and issue in nvidia drivers | 520 | // Workaround for and issue in nvidia drivers |
| 521 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ | 521 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ |
| 522 | // state.framebuffer_srgb.enabled |= | 522 | state.framebuffer_srgb.enabled |= |
| 523 | // color_surface->GetSurfaceParams().srgb_conversion; | 523 | color_surface->GetSurfaceParams().GetSrgbConversion(); |
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | fbkey.color_attachments[index] = | 526 | fbkey.color_attachments[index] = |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 6a6fe7cc4..da2d1e63a 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "video_core/morton.h" | 8 | #include "video_core/morton.h" |
| 9 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 9 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 10 | #include "video_core/renderer_opengl/gl_texture_cache.h" | 10 | #include "video_core/renderer_opengl/gl_texture_cache.h" |
| 11 | #include "video_core/renderer_opengl/utils.h" | ||
| 11 | #include "video_core/texture_cache.h" | 12 | #include "video_core/texture_cache.h" |
| 12 | #include "video_core/textures/convert.h" | 13 | #include "video_core/textures/convert.h" |
| 13 | #include "video_core/textures/texture.h" | 14 | #include "video_core/textures/texture.h" |
| @@ -285,6 +286,8 @@ void CachedSurface::LoadBuffer() { | |||
| 285 | } | 286 | } |
| 286 | 287 | ||
| 287 | void CachedSurface::FlushBufferImpl() { | 288 | void CachedSurface::FlushBufferImpl() { |
| 289 | LOG_CRITICAL(Render_OpenGL, "Flushing"); | ||
| 290 | |||
| 288 | if (!IsModified()) { | 291 | if (!IsModified()) { |
| 289 | return; | 292 | return; |
| 290 | } | 293 | } |
| @@ -352,9 +355,6 @@ void CachedSurface::UploadTextureMipmap(u32 level) { | |||
| 352 | 355 | ||
| 353 | if (is_compressed) { | 356 | if (is_compressed) { |
| 354 | const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))}; | 357 | const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))}; |
| 355 | GLint expected_size; | ||
| 356 | glGetTextureLevelParameteriv(texture.handle, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, | ||
| 357 | &expected_size); | ||
| 358 | switch (params.GetTarget()) { | 358 | switch (params.GetTarget()) { |
| 359 | case SurfaceTarget::Texture2D: | 359 | case SurfaceTarget::Texture2D: |
| 360 | glCompressedTextureSubImage2D(texture.handle, level, 0, 0, | 360 | glCompressedTextureSubImage2D(texture.handle, level, 0, 0, |
| @@ -419,6 +419,10 @@ void CachedSurface::UploadTextureMipmap(u32 level) { | |||
| 419 | } | 419 | } |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | void CachedSurface::DecorateSurfaceName() { | ||
| 423 | LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr()); | ||
| 424 | } | ||
| 425 | |||
| 422 | std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) { | 426 | std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) { |
| 423 | return std::make_unique<CachedSurfaceView>(*this, view_key); | 427 | return std::make_unique<CachedSurfaceView>(*this, view_key); |
| 424 | } | 428 | } |
| @@ -517,11 +521,13 @@ TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, | |||
| 517 | 521 | ||
| 518 | TextureCacheOpenGL::~TextureCacheOpenGL() = default; | 522 | TextureCacheOpenGL::~TextureCacheOpenGL() = default; |
| 519 | 523 | ||
| 520 | CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView( | 524 | CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, |
| 521 | VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params, bool preserve_contents, | 525 | u8* host_ptr, |
| 522 | const std::vector<CachedSurface*>& overlaps) { | 526 | const SurfaceParams& new_params, |
| 527 | bool preserve_contents, | ||
| 528 | const std::vector<Surface>& overlaps) { | ||
| 523 | if (overlaps.size() > 1) { | 529 | if (overlaps.size() > 1) { |
| 524 | return TryCopyAsViews(cpu_addr, host_ptr, new_params, overlaps); | 530 | return TryCopyAsViews(gpu_addr, cpu_addr, host_ptr, new_params, overlaps); |
| 525 | } | 531 | } |
| 526 | 532 | ||
| 527 | const auto& old_surface{overlaps[0]}; | 533 | const auto& old_surface{overlaps[0]}; |
| @@ -530,18 +536,18 @@ CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView( | |||
| 530 | old_params.GetDepth() == new_params.GetDepth() && old_params.GetDepth() == 1 && | 536 | old_params.GetDepth() == new_params.GetDepth() && old_params.GetDepth() == 1 && |
| 531 | old_params.GetNumLevels() == new_params.GetNumLevels() && | 537 | old_params.GetNumLevels() == new_params.GetNumLevels() && |
| 532 | old_params.GetPixelFormat() == new_params.GetPixelFormat()) { | 538 | old_params.GetPixelFormat() == new_params.GetPixelFormat()) { |
| 533 | return SurfaceCopy(cpu_addr, host_ptr, new_params, old_surface, old_params); | 539 | return SurfaceCopy(gpu_addr, cpu_addr, host_ptr, new_params, old_surface, old_params); |
| 534 | } | 540 | } |
| 535 | 541 | ||
| 536 | return nullptr; | 542 | return nullptr; |
| 537 | } | 543 | } |
| 538 | 544 | ||
| 539 | CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(VAddr cpu_addr, u8* host_ptr, | 545 | CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, |
| 540 | const SurfaceParams& new_params, | 546 | const SurfaceParams& new_params, |
| 541 | CachedSurface* old_surface, | 547 | const Surface& old_surface, |
| 542 | const SurfaceParams& old_params) { | 548 | const SurfaceParams& old_params) { |
| 543 | CachedSurface* const new_surface{GetUncachedSurface(new_params)}; | 549 | const auto new_surface{GetUncachedSurface(new_params)}; |
| 544 | Register(new_surface, cpu_addr, host_ptr); | 550 | Register(new_surface, gpu_addr, cpu_addr, host_ptr); |
| 545 | 551 | ||
| 546 | const u32 min_width{ | 552 | const u32 min_width{ |
| 547 | std::max(old_params.GetDefaultBlockWidth(), new_params.GetDefaultBlockWidth())}; | 553 | std::max(old_params.GetDefaultBlockWidth(), new_params.GetDefaultBlockWidth())}; |
| @@ -562,12 +568,12 @@ CachedSurfaceView* TextureCacheOpenGL::SurfaceCopy(VAddr cpu_addr, u8* host_ptr, | |||
| 562 | new_surface->MarkAsModified(true); | 568 | new_surface->MarkAsModified(true); |
| 563 | 569 | ||
| 564 | // TODO(Rodrigo): Add an entry to directly get the superview | 570 | // TODO(Rodrigo): Add an entry to directly get the superview |
| 565 | return new_surface->GetView(cpu_addr, new_params); | 571 | return new_surface->GetView(gpu_addr, new_params); |
| 566 | } | 572 | } |
| 567 | 573 | ||
| 568 | CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(VAddr cpu_addr, u8* host_ptr, | 574 | CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(GPUVAddr gpu_addr, VAddr cpu_addr, |
| 569 | const SurfaceParams& new_params, | 575 | u8* host_ptr, const SurfaceParams& new_params, |
| 570 | const std::vector<CachedSurface*>& overlaps) { | 576 | const std::vector<Surface>& overlaps) { |
| 571 | if (new_params.GetTarget() == SurfaceTarget::Texture1D || | 577 | if (new_params.GetTarget() == SurfaceTarget::Texture1D || |
| 572 | new_params.GetTarget() == SurfaceTarget::Texture1DArray || | 578 | new_params.GetTarget() == SurfaceTarget::Texture1DArray || |
| 573 | new_params.GetTarget() == SurfaceTarget::Texture3D) { | 579 | new_params.GetTarget() == SurfaceTarget::Texture3D) { |
| @@ -575,16 +581,16 @@ CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(VAddr cpu_addr, u8* host_p | |||
| 575 | return nullptr; | 581 | return nullptr; |
| 576 | } | 582 | } |
| 577 | 583 | ||
| 578 | CachedSurface* const new_surface{GetUncachedSurface(new_params)}; | 584 | const auto new_surface{GetUncachedSurface(new_params)}; |
| 579 | // TODO(Rodrigo): Move this down | 585 | // TODO(Rodrigo): Move this down |
| 580 | Register(new_surface, cpu_addr, host_ptr); | 586 | Register(new_surface, gpu_addr, cpu_addr, host_ptr); |
| 581 | 587 | ||
| 582 | // TODO(Rodrigo): Find a way to avoid heap allocations here. | 588 | // TODO(Rodrigo): Find a way to avoid heap allocations here. |
| 583 | std::vector<CachedSurfaceView*> views; | 589 | std::vector<CachedSurfaceView*> views; |
| 584 | views.reserve(overlaps.size()); | 590 | views.reserve(overlaps.size()); |
| 585 | for (const auto& overlap : overlaps) { | 591 | for (const auto& overlap : overlaps) { |
| 586 | const auto view{ | 592 | const auto view{ |
| 587 | new_surface->TryGetView(overlap->GetCpuAddr(), overlap->GetSurfaceParams())}; | 593 | new_surface->TryGetView(overlap->GetGpuAddr(), overlap->GetSurfaceParams())}; |
| 588 | if (!view) { | 594 | if (!view) { |
| 589 | // TODO(Rodrigo): Remove this | 595 | // TODO(Rodrigo): Remove this |
| 590 | Unregister(new_surface); | 596 | Unregister(new_surface); |
| @@ -610,11 +616,11 @@ CachedSurfaceView* TextureCacheOpenGL::TryCopyAsViews(VAddr cpu_addr, u8* host_p | |||
| 610 | new_surface->MarkAsModified(true); | 616 | new_surface->MarkAsModified(true); |
| 611 | 617 | ||
| 612 | // TODO(Rodrigo): Add an entry to directly get the superview | 618 | // TODO(Rodrigo): Add an entry to directly get the superview |
| 613 | return new_surface->GetView(cpu_addr, new_params); | 619 | return new_surface->GetView(gpu_addr, new_params); |
| 614 | } | 620 | } |
| 615 | 621 | ||
| 616 | std::unique_ptr<CachedSurface> TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) { | 622 | Surface TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) { |
| 617 | return std::make_unique<CachedSurface>(params); | 623 | return std::make_unique<CachedSurface>(*this, params); |
| 618 | } | 624 | } |
| 619 | 625 | ||
| 620 | } // namespace OpenGL | 626 | } // 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 86ad91dab..8705db74c 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -27,6 +27,7 @@ using VideoCore::Surface::SurfaceType; | |||
| 27 | class CachedSurfaceView; | 27 | class CachedSurfaceView; |
| 28 | class CachedSurface; | 28 | class CachedSurface; |
| 29 | 29 | ||
| 30 | using Surface = std::shared_ptr<CachedSurface>; | ||
| 30 | using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>; | 31 | using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>; |
| 31 | 32 | ||
| 32 | class CachedSurface final : public VideoCommon::SurfaceBaseContextless<CachedSurfaceView> { | 33 | class CachedSurface final : public VideoCommon::SurfaceBaseContextless<CachedSurfaceView> { |
| @@ -47,6 +48,8 @@ public: | |||
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | protected: | 50 | protected: |
| 51 | void DecorateSurfaceName(); | ||
| 52 | |||
| 50 | std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key); | 53 | std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key); |
| 51 | 54 | ||
| 52 | void FlushBufferImpl(); | 55 | void FlushBufferImpl(); |
| @@ -65,7 +68,6 @@ private: | |||
| 65 | OGLTexture texture; | 68 | OGLTexture texture; |
| 66 | 69 | ||
| 67 | std::vector<u8> staging_buffer; | 70 | std::vector<u8> staging_buffer; |
| 68 | u8* host_ptr{}; | ||
| 69 | }; | 71 | }; |
| 70 | 72 | ||
| 71 | class CachedSurfaceView final { | 73 | class CachedSurfaceView final { |
| @@ -155,19 +157,21 @@ public: | |||
| 155 | ~TextureCacheOpenGL(); | 157 | ~TextureCacheOpenGL(); |
| 156 | 158 | ||
| 157 | protected: | 159 | protected: |
| 158 | CachedSurfaceView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, | 160 | CachedSurfaceView* TryFastGetSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, |
| 159 | const SurfaceParams& new_params, | 161 | const SurfaceParams& new_params, |
| 160 | bool preserve_contents, | 162 | bool preserve_contents, |
| 161 | const std::vector<CachedSurface*>& overlaps); | 163 | const std::vector<Surface>& overlaps); |
| 162 | 164 | ||
| 163 | std::unique_ptr<CachedSurface> CreateSurface(const SurfaceParams& params); | 165 | Surface CreateSurface(const SurfaceParams& params); |
| 164 | 166 | ||
| 165 | private: | 167 | private: |
| 166 | CachedSurfaceView* SurfaceCopy(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params, | 168 | CachedSurfaceView* SurfaceCopy(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, |
| 167 | CachedSurface* old_surface, const SurfaceParams& old_params); | 169 | const SurfaceParams& new_params, const Surface& old_surface, |
| 170 | const SurfaceParams& old_params); | ||
| 168 | 171 | ||
| 169 | CachedSurfaceView* TryCopyAsViews(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& new_params, | 172 | CachedSurfaceView* TryCopyAsViews(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, |
| 170 | const std::vector<CachedSurface*>& overlaps); | 173 | const SurfaceParams& new_params, |
| 174 | const std::vector<Surface>& overlaps); | ||
| 171 | }; | 175 | }; |
| 172 | 176 | ||
| 173 | } // namespace OpenGL | 177 | } // namespace OpenGL |
diff --git a/src/video_core/texture_cache.cpp b/src/video_core/texture_cache.cpp index 2994312f4..b47ce6b98 100644 --- a/src/video_core/texture_cache.cpp +++ b/src/video_core/texture_cache.cpp | |||
| @@ -32,12 +32,13 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, | |||
| 32 | const Tegra::Texture::FullTextureInfo& config) { | 32 | const Tegra::Texture::FullTextureInfo& config) { |
| 33 | SurfaceParams params; | 33 | SurfaceParams params; |
| 34 | params.is_tiled = config.tic.IsTiled(); | 34 | params.is_tiled = config.tic.IsTiled(); |
| 35 | params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); | ||
| 35 | params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, | 36 | params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, |
| 36 | params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, | 37 | params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, |
| 37 | params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, | 38 | params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, |
| 38 | params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1; | 39 | params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1; |
| 39 | params.pixel_format = | 40 | params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), |
| 40 | PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), false); | 41 | params.srgb_conversion); |
| 41 | params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); | 42 | params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); |
| 42 | params.type = GetFormatType(params.pixel_format); | 43 | params.type = GetFormatType(params.pixel_format); |
| 43 | params.target = SurfaceTargetFromTextureType(config.tic.texture_type); | 44 | params.target = SurfaceTargetFromTextureType(config.tic.texture_type); |
| @@ -62,6 +63,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer( | |||
| 62 | Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) { | 63 | Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) { |
| 63 | SurfaceParams params; | 64 | SurfaceParams params; |
| 64 | params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; | 65 | params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; |
| 66 | params.srgb_conversion = false; | ||
| 65 | params.block_width = 1 << std::min(block_width, 5U); | 67 | params.block_width = 1 << std::min(block_width, 5U); |
| 66 | params.block_height = 1 << std::min(block_height, 5U); | 68 | params.block_height = 1 << std::min(block_height, 5U); |
| 67 | params.block_depth = 1 << std::min(block_depth, 5U); | 69 | params.block_depth = 1 << std::min(block_depth, 5U); |
| @@ -85,6 +87,8 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz | |||
| 85 | SurfaceParams params; | 87 | SurfaceParams params; |
| 86 | params.is_tiled = | 88 | params.is_tiled = |
| 87 | config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; | 89 | config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; |
| 90 | params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || | ||
| 91 | config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; | ||
| 88 | params.block_width = 1 << config.memory_layout.block_width; | 92 | params.block_width = 1 << config.memory_layout.block_width; |
| 89 | params.block_height = 1 << config.memory_layout.block_height; | 93 | params.block_height = 1 << config.memory_layout.block_height; |
| 90 | params.block_depth = 1 << config.memory_layout.block_depth; | 94 | params.block_depth = 1 << config.memory_layout.block_depth; |
| @@ -113,6 +117,8 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( | |||
| 113 | const Tegra::Engines::Fermi2D::Regs::Surface& config) { | 117 | const Tegra::Engines::Fermi2D::Regs::Surface& config) { |
| 114 | SurfaceParams params{}; | 118 | SurfaceParams params{}; |
| 115 | params.is_tiled = !config.linear; | 119 | params.is_tiled = !config.linear; |
| 120 | params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || | ||
| 121 | config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; | ||
| 116 | params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0, | 122 | params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0, |
| 117 | params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, | 123 | params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, |
| 118 | params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, | 124 | params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, |
| @@ -162,6 +168,7 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const { | |||
| 162 | if (level == 0) { | 168 | if (level == 0) { |
| 163 | return this->block_height; | 169 | return this->block_height; |
| 164 | } | 170 | } |
| 171 | |||
| 165 | const u32 height{GetMipHeight(level)}; | 172 | const u32 height{GetMipHeight(level)}; |
| 166 | const u32 default_block_height{GetDefaultBlockHeight()}; | 173 | const u32 default_block_height{GetDefaultBlockHeight()}; |
| 167 | const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; | 174 | const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; |
| @@ -173,10 +180,12 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const { | |||
| 173 | } | 180 | } |
| 174 | 181 | ||
| 175 | u32 SurfaceParams::GetMipBlockDepth(u32 level) const { | 182 | u32 SurfaceParams::GetMipBlockDepth(u32 level) const { |
| 176 | if (level == 0) | 183 | if (level == 0) { |
| 177 | return block_depth; | 184 | return this->block_depth; |
| 178 | if (target != SurfaceTarget::Texture3D) | 185 | } |
| 186 | if (IsLayered()) { | ||
| 179 | return 1; | 187 | return 1; |
| 188 | } | ||
| 180 | 189 | ||
| 181 | const u32 depth{GetMipDepth(level)}; | 190 | const u32 depth{GetMipDepth(level)}; |
| 182 | u32 block_depth = 32; | 191 | u32 block_depth = 32; |
| @@ -192,7 +201,7 @@ u32 SurfaceParams::GetMipBlockDepth(u32 level) const { | |||
| 192 | std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const { | 201 | std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const { |
| 193 | std::size_t offset = 0; | 202 | std::size_t offset = 0; |
| 194 | for (u32 i = 0; i < level; i++) { | 203 | for (u32 i = 0; i < level; i++) { |
| 195 | offset += GetInnerMipmapMemorySize(i, false, IsLayered(), false); | 204 | offset += GetInnerMipmapMemorySize(i, false, false); |
| 196 | } | 205 | } |
| 197 | return offset; | 206 | return offset; |
| 198 | } | 207 | } |
| @@ -200,21 +209,33 @@ std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const { | |||
| 200 | std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { | 209 | std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { |
| 201 | std::size_t offset = 0; | 210 | std::size_t offset = 0; |
| 202 | for (u32 i = 0; i < level; i++) { | 211 | for (u32 i = 0; i < level; i++) { |
| 203 | offset += GetInnerMipmapMemorySize(i, true, false, false); | 212 | offset += GetInnerMipmapMemorySize(i, true, false) * GetNumLayers(); |
| 204 | } | 213 | } |
| 205 | return offset; | 214 | return offset; |
| 206 | } | 215 | } |
| 207 | 216 | ||
| 208 | std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { | 217 | std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { |
| 209 | return GetInnerMipmapMemorySize(level, true, true, false) * GetNumLayers(); | 218 | return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers(); |
| 210 | } | 219 | } |
| 211 | 220 | ||
| 212 | std::size_t SurfaceParams::GetGuestLayerSize() const { | 221 | std::size_t SurfaceParams::GetGuestLayerSize() const { |
| 213 | return GetInnerMemorySize(false, true, false); | 222 | return GetLayerSize(false, false); |
| 223 | } | ||
| 224 | |||
| 225 | std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const { | ||
| 226 | std::size_t size = 0; | ||
| 227 | for (u32 level = 0; level < num_levels; ++level) { | ||
| 228 | size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed); | ||
| 229 | } | ||
| 230 | if (is_tiled && IsLayered()) { | ||
| 231 | return Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); | ||
| 232 | } | ||
| 233 | return size; | ||
| 214 | } | 234 | } |
| 215 | 235 | ||
| 216 | std::size_t SurfaceParams::GetHostLayerSize(u32 level) const { | 236 | std::size_t SurfaceParams::GetHostLayerSize(u32 level) const { |
| 217 | return GetInnerMipmapMemorySize(level, true, IsLayered(), false); | 237 | ASSERT(target != SurfaceTarget::Texture3D); |
| 238 | return GetInnerMipmapMemorySize(level, true, false); | ||
| 218 | } | 239 | } |
| 219 | 240 | ||
| 220 | u32 SurfaceParams::GetDefaultBlockWidth() const { | 241 | u32 SurfaceParams::GetDefaultBlockWidth() const { |
| @@ -273,15 +294,6 @@ bool SurfaceParams::IsPixelFormatZeta() const { | |||
| 273 | } | 294 | } |
| 274 | 295 | ||
| 275 | void SurfaceParams::CalculateCachedValues() { | 296 | void SurfaceParams::CalculateCachedValues() { |
| 276 | guest_size_in_bytes = GetInnerMemorySize(false, false, false); | ||
| 277 | |||
| 278 | // ASTC is uncompressed in software, in emulated as RGBA8 | ||
| 279 | if (IsPixelFormatASTC(pixel_format)) { | ||
| 280 | host_size_in_bytes = static_cast<std::size_t>(width * height * depth) * 4ULL; | ||
| 281 | } else { | ||
| 282 | host_size_in_bytes = GetInnerMemorySize(true, false, false); | ||
| 283 | } | ||
| 284 | |||
| 285 | switch (target) { | 297 | switch (target) { |
| 286 | case SurfaceTarget::Texture1D: | 298 | case SurfaceTarget::Texture1D: |
| 287 | case SurfaceTarget::Texture2D: | 299 | case SurfaceTarget::Texture2D: |
| @@ -297,28 +309,30 @@ void SurfaceParams::CalculateCachedValues() { | |||
| 297 | default: | 309 | default: |
| 298 | UNREACHABLE(); | 310 | UNREACHABLE(); |
| 299 | } | 311 | } |
| 312 | |||
| 313 | guest_size_in_bytes = GetInnerMemorySize(false, false, false); | ||
| 314 | |||
| 315 | // ASTC is uncompressed in software, in emulated as RGBA8 | ||
| 316 | if (IsPixelFormatASTC(pixel_format)) { | ||
| 317 | host_size_in_bytes = static_cast<std::size_t>(width * height * depth * 4U); | ||
| 318 | } else { | ||
| 319 | host_size_in_bytes = GetInnerMemorySize(true, false, false); | ||
| 320 | } | ||
| 300 | } | 321 | } |
| 301 | 322 | ||
| 302 | std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only, | 323 | std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, |
| 303 | bool uncompressed) const { | 324 | bool uncompressed) const { |
| 304 | const bool tiled{as_host_size ? false : is_tiled}; | 325 | const bool tiled{as_host_size ? false : is_tiled}; |
| 305 | const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())}; | 326 | const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())}; |
| 306 | const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())}; | 327 | const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())}; |
| 307 | const u32 depth{layer_only ? 1U : GetMipDepth(level)}; | 328 | const u32 depth{target == SurfaceTarget::Texture3D ? GetMipDepth(level) : 1U}; |
| 308 | return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth, | 329 | return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth, |
| 309 | GetMipBlockHeight(level), GetMipBlockDepth(level)); | 330 | GetMipBlockHeight(level), GetMipBlockDepth(level)); |
| 310 | } | 331 | } |
| 311 | 332 | ||
| 312 | std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, | 333 | std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, |
| 313 | bool uncompressed) const { | 334 | bool uncompressed) const { |
| 314 | std::size_t size = 0; | 335 | return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : num_layers); |
| 315 | for (u32 level = 0; level < num_levels; ++level) { | ||
| 316 | size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed); | ||
| 317 | } | ||
| 318 | if (is_tiled && !as_host_size) { | ||
| 319 | size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); | ||
| 320 | } | ||
| 321 | return size; | ||
| 322 | } | 336 | } |
| 323 | 337 | ||
| 324 | std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const { | 338 | std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const { |
diff --git a/src/video_core/texture_cache.h b/src/video_core/texture_cache.h index 9fd5f074e..0e289d378 100644 --- a/src/video_core/texture_cache.h +++ b/src/video_core/texture_cache.h | |||
| @@ -53,6 +53,7 @@ protected: | |||
| 53 | HasheableSurfaceParams() = default; | 53 | HasheableSurfaceParams() = default; |
| 54 | 54 | ||
| 55 | bool is_tiled; | 55 | bool is_tiled; |
| 56 | bool srgb_conversion; | ||
| 56 | u32 block_width; | 57 | u32 block_width; |
| 57 | u32 block_height; | 58 | u32 block_height; |
| 58 | u32 block_depth; | 59 | u32 block_depth; |
| @@ -92,6 +93,10 @@ public: | |||
| 92 | return is_tiled; | 93 | return is_tiled; |
| 93 | } | 94 | } |
| 94 | 95 | ||
| 96 | bool GetSrgbConversion() const { | ||
| 97 | return srgb_conversion; | ||
| 98 | } | ||
| 99 | |||
| 95 | u32 GetBlockWidth() const { | 100 | u32 GetBlockWidth() const { |
| 96 | return block_width; | 101 | return block_width; |
| 97 | } | 102 | } |
| @@ -211,13 +216,15 @@ private: | |||
| 211 | /// Calculates values that can be deduced from HasheableSurfaceParams. | 216 | /// Calculates values that can be deduced from HasheableSurfaceParams. |
| 212 | void CalculateCachedValues(); | 217 | void CalculateCachedValues(); |
| 213 | 218 | ||
| 214 | /// Returns the size of a given mipmap level. | 219 | /// Returns the size of a given mipmap level inside a layer. |
| 215 | std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only, | 220 | std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const; |
| 216 | bool uncompressed) const; | ||
| 217 | 221 | ||
| 218 | /// Returns the size of all mipmap levels and aligns as needed. | 222 | /// Returns the size of all mipmap levels and aligns as needed. |
| 219 | std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const; | 223 | std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const; |
| 220 | 224 | ||
| 225 | /// Returns the size of a layer | ||
| 226 | std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const; | ||
| 227 | |||
| 221 | /// Returns true if the passed view width and height match the size of this params in a given | 228 | /// Returns true if the passed view width and height match the size of this params in a given |
| 222 | /// mipmap level. | 229 | /// mipmap level. |
| 223 | bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const; | 230 | bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const; |
| @@ -277,13 +284,13 @@ public: | |||
| 277 | 284 | ||
| 278 | virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0; | 285 | virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0; |
| 279 | 286 | ||
| 280 | TView* TryGetView(VAddr view_addr, const SurfaceParams& view_params) { | 287 | TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) { |
| 281 | if (view_addr < cpu_addr || !params.IsFamiliar(view_params)) { | 288 | if (view_addr < gpu_addr || !params.IsFamiliar(view_params)) { |
| 282 | // It can't be a view if it's in a prior address. | 289 | // It can't be a view if it's in a prior address. |
| 283 | return {}; | 290 | return {}; |
| 284 | } | 291 | } |
| 285 | 292 | ||
| 286 | const auto relative_offset{static_cast<u64>(view_addr - cpu_addr)}; | 293 | const auto relative_offset{static_cast<u64>(view_addr - gpu_addr)}; |
| 287 | const auto it{view_offset_map.find(relative_offset)}; | 294 | const auto it{view_offset_map.find(relative_offset)}; |
| 288 | if (it == view_offset_map.end()) { | 295 | if (it == view_offset_map.end()) { |
| 289 | // Couldn't find an aligned view. | 296 | // Couldn't find an aligned view. |
| @@ -298,6 +305,11 @@ public: | |||
| 298 | return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels()); | 305 | return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels()); |
| 299 | } | 306 | } |
| 300 | 307 | ||
| 308 | GPUVAddr GetGpuAddr() const { | ||
| 309 | ASSERT(is_registered); | ||
| 310 | return gpu_addr; | ||
| 311 | } | ||
| 312 | |||
| 301 | VAddr GetCpuAddr() const { | 313 | VAddr GetCpuAddr() const { |
| 302 | ASSERT(is_registered); | 314 | ASSERT(is_registered); |
| 303 | return cpu_addr; | 315 | return cpu_addr; |
| @@ -325,22 +337,20 @@ public: | |||
| 325 | return params; | 337 | return params; |
| 326 | } | 338 | } |
| 327 | 339 | ||
| 328 | TView* GetView(VAddr view_addr, const SurfaceParams& view_params) { | 340 | TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) { |
| 329 | TView* view{TryGetView(view_addr, view_params)}; | 341 | TView* view{TryGetView(view_addr, view_params)}; |
| 330 | ASSERT(view != nullptr); | 342 | ASSERT(view != nullptr); |
| 331 | return view; | 343 | return view; |
| 332 | } | 344 | } |
| 333 | 345 | ||
| 334 | void Register(VAddr cpu_addr_, u8* host_ptr_) { | 346 | void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) { |
| 335 | ASSERT(!is_registered); | 347 | ASSERT(!is_registered); |
| 336 | is_registered = true; | 348 | is_registered = true; |
| 349 | gpu_addr = gpu_addr_; | ||
| 337 | cpu_addr = cpu_addr_; | 350 | cpu_addr = cpu_addr_; |
| 338 | host_ptr = host_ptr_; | 351 | host_ptr = host_ptr_; |
| 339 | cache_addr = ToCacheAddr(host_ptr_); | 352 | cache_addr = ToCacheAddr(host_ptr_); |
| 340 | } | 353 | DecorateSurfaceName(); |
| 341 | |||
| 342 | void Register(VAddr cpu_addr_) { | ||
| 343 | Register(cpu_addr_, Memory::GetPointer(cpu_addr_)); | ||
| 344 | } | 354 | } |
| 345 | 355 | ||
| 346 | void Unregister() { | 356 | void Unregister() { |
| @@ -358,6 +368,8 @@ protected: | |||
| 358 | 368 | ||
| 359 | ~SurfaceBase() = default; | 369 | ~SurfaceBase() = default; |
| 360 | 370 | ||
| 371 | virtual void DecorateSurfaceName() = 0; | ||
| 372 | |||
| 361 | virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0; | 373 | virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0; |
| 362 | 374 | ||
| 363 | bool IsModified() const { | 375 | bool IsModified() const { |
| @@ -379,6 +391,7 @@ private: | |||
| 379 | 391 | ||
| 380 | const std::map<u64, std::pair<u32, u32>> view_offset_map; | 392 | const std::map<u64, std::pair<u32, u32>> view_offset_map; |
| 381 | 393 | ||
| 394 | GPUVAddr gpu_addr{}; | ||
| 382 | VAddr cpu_addr{}; | 395 | VAddr cpu_addr{}; |
| 383 | u8* host_ptr{}; | 396 | u8* host_ptr{}; |
| 384 | CacheAddr cache_addr{}; | 397 | CacheAddr cache_addr{}; |
| @@ -392,12 +405,12 @@ class TextureCache { | |||
| 392 | static_assert(std::is_trivially_copyable_v<TExecutionContext>); | 405 | static_assert(std::is_trivially_copyable_v<TExecutionContext>); |
| 393 | 406 | ||
| 394 | using ResultType = std::tuple<TView*, TExecutionContext>; | 407 | using ResultType = std::tuple<TView*, TExecutionContext>; |
| 395 | using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<TSurface*>>; | 408 | using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>; |
| 396 | using IntervalType = typename IntervalMap::interval_type; | 409 | using IntervalType = typename IntervalMap::interval_type; |
| 397 | 410 | ||
| 398 | public: | 411 | public: |
| 399 | void InvalidateRegion(CacheAddr addr, std::size_t size) { | 412 | void InvalidateRegion(CacheAddr addr, std::size_t size) { |
| 400 | for (TSurface* surface : GetSurfacesInRegion(addr, size)) { | 413 | for (const auto& surface : GetSurfacesInRegion(addr, size)) { |
| 401 | if (!surface->IsRegistered()) { | 414 | if (!surface->IsRegistered()) { |
| 402 | // Skip duplicates | 415 | // Skip duplicates |
| 403 | continue; | 416 | continue; |
| @@ -408,32 +421,25 @@ public: | |||
| 408 | 421 | ||
| 409 | ResultType GetTextureSurface(TExecutionContext exctx, | 422 | ResultType GetTextureSurface(TExecutionContext exctx, |
| 410 | const Tegra::Texture::FullTextureInfo& config) { | 423 | const Tegra::Texture::FullTextureInfo& config) { |
| 411 | auto& memory_manager{system.GPU().MemoryManager()}; | 424 | const auto gpu_addr{config.tic.Address()}; |
| 412 | const auto cpu_addr{memory_manager.GpuToCpuAddress(config.tic.Address())}; | 425 | if (!gpu_addr) { |
| 413 | if (!cpu_addr) { | ||
| 414 | return {{}, exctx}; | 426 | return {{}, exctx}; |
| 415 | } | 427 | } |
| 416 | const auto params{SurfaceParams::CreateForTexture(system, config)}; | 428 | const auto params{SurfaceParams::CreateForTexture(system, config)}; |
| 417 | return GetSurfaceView(exctx, *cpu_addr, params, true); | 429 | return GetSurfaceView(exctx, gpu_addr, params, true); |
| 418 | } | 430 | } |
| 419 | 431 | ||
| 420 | ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) { | 432 | ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) { |
| 421 | const auto& regs{system.GPU().Maxwell3D().regs}; | 433 | const auto& regs{system.GPU().Maxwell3D().regs}; |
| 422 | if (!regs.zeta.Address() || !regs.zeta_enable) { | 434 | const auto gpu_addr{regs.zeta.Address()}; |
| 435 | if (!gpu_addr || !regs.zeta_enable) { | ||
| 423 | return {{}, exctx}; | 436 | return {{}, exctx}; |
| 424 | } | 437 | } |
| 425 | |||
| 426 | auto& memory_manager{system.GPU().MemoryManager()}; | ||
| 427 | const auto cpu_addr{memory_manager.GpuToCpuAddress(regs.zeta.Address())}; | ||
| 428 | if (!cpu_addr) { | ||
| 429 | return {{}, exctx}; | ||
| 430 | } | ||
| 431 | |||
| 432 | const auto depth_params{SurfaceParams::CreateForDepthBuffer( | 438 | const auto depth_params{SurfaceParams::CreateForDepthBuffer( |
| 433 | system, regs.zeta_width, regs.zeta_height, regs.zeta.format, | 439 | system, regs.zeta_width, regs.zeta_height, regs.zeta.format, |
| 434 | regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, | 440 | regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, |
| 435 | regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; | 441 | regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; |
| 436 | return GetSurfaceView(exctx, *cpu_addr, depth_params, preserve_contents); | 442 | return GetSurfaceView(exctx, gpu_addr, depth_params, preserve_contents); |
| 437 | } | 443 | } |
| 438 | 444 | ||
| 439 | ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index, | 445 | ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index, |
| @@ -448,25 +454,23 @@ public: | |||
| 448 | 454 | ||
| 449 | auto& memory_manager{system.GPU().MemoryManager()}; | 455 | auto& memory_manager{system.GPU().MemoryManager()}; |
| 450 | const auto& config{system.GPU().Maxwell3D().regs.rt[index]}; | 456 | const auto& config{system.GPU().Maxwell3D().regs.rt[index]}; |
| 451 | const auto cpu_addr{memory_manager.GpuToCpuAddress( | 457 | const auto gpu_addr{config.Address() + |
| 452 | config.Address() + config.base_layer * config.layer_stride * sizeof(u32))}; | 458 | config.base_layer * config.layer_stride * sizeof(u32)}; |
| 453 | if (!cpu_addr) { | 459 | if (!gpu_addr) { |
| 454 | return {{}, exctx}; | 460 | return {{}, exctx}; |
| 455 | } | 461 | } |
| 456 | 462 | ||
| 457 | return GetSurfaceView(exctx, *cpu_addr, SurfaceParams::CreateForFramebuffer(system, index), | 463 | return GetSurfaceView(exctx, gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), |
| 458 | preserve_contents); | 464 | preserve_contents); |
| 459 | } | 465 | } |
| 460 | 466 | ||
| 461 | ResultType GetFermiSurface(TExecutionContext exctx, | 467 | ResultType GetFermiSurface(TExecutionContext exctx, |
| 462 | const Tegra::Engines::Fermi2D::Regs::Surface& config) { | 468 | const Tegra::Engines::Fermi2D::Regs::Surface& config) { |
| 463 | const auto cpu_addr{system.GPU().MemoryManager().GpuToCpuAddress(config.Address())}; | 469 | return GetSurfaceView(exctx, config.Address(), |
| 464 | ASSERT(cpu_addr); | 470 | SurfaceParams::CreateForFermiCopySurface(config), true); |
| 465 | return GetSurfaceView(exctx, *cpu_addr, SurfaceParams::CreateForFermiCopySurface(config), | ||
| 466 | true); | ||
| 467 | } | 471 | } |
| 468 | 472 | ||
| 469 | TSurface* TryFindFramebufferSurface(const u8* host_ptr) const { | 473 | std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const { |
| 470 | const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))}; | 474 | const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))}; |
| 471 | return it != registered_surfaces.end() ? *it->second.begin() : nullptr; | 475 | return it != registered_surfaces.end() ? *it->second.begin() : nullptr; |
| 472 | } | 476 | } |
| @@ -477,56 +481,68 @@ protected: | |||
| 477 | 481 | ||
| 478 | ~TextureCache() = default; | 482 | ~TextureCache() = default; |
| 479 | 483 | ||
| 480 | virtual ResultType TryFastGetSurfaceView(TExecutionContext exctx, VAddr cpu_addr, u8* host_ptr, | 484 | virtual ResultType TryFastGetSurfaceView( |
| 481 | const SurfaceParams& params, bool preserve_contents, | 485 | TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, |
| 482 | const std::vector<TSurface*>& overlaps) = 0; | 486 | const SurfaceParams& params, bool preserve_contents, |
| 487 | const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0; | ||
| 483 | 488 | ||
| 484 | virtual std::unique_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0; | 489 | virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0; |
| 485 | 490 | ||
| 486 | void Register(TSurface* surface, VAddr cpu_addr, u8* host_ptr) { | 491 | void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr, |
| 487 | surface->Register(cpu_addr, host_ptr); | 492 | u8* host_ptr) { |
| 493 | surface->Register(gpu_addr, cpu_addr, host_ptr); | ||
| 488 | registered_surfaces.add({GetSurfaceInterval(surface), {surface}}); | 494 | registered_surfaces.add({GetSurfaceInterval(surface), {surface}}); |
| 489 | rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1); | 495 | rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1); |
| 490 | } | 496 | } |
| 491 | 497 | ||
| 492 | void Unregister(TSurface* surface) { | 498 | void Unregister(std::shared_ptr<TSurface> surface) { |
| 493 | registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}}); | 499 | registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}}); |
| 494 | rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1); | 500 | rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1); |
| 495 | surface->Unregister(); | 501 | surface->Unregister(); |
| 496 | } | 502 | } |
| 497 | 503 | ||
| 498 | TSurface* GetUncachedSurface(const SurfaceParams& params) { | 504 | std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) { |
| 499 | if (TSurface* surface = TryGetReservedSurface(params); surface) | 505 | if (const auto surface = TryGetReservedSurface(params); surface) |
| 500 | return surface; | 506 | return surface; |
| 501 | // No reserved surface available, create a new one and reserve it | 507 | // No reserved surface available, create a new one and reserve it |
| 502 | auto new_surface{CreateSurface(params)}; | 508 | auto new_surface{CreateSurface(params)}; |
| 503 | TSurface* surface{new_surface.get()}; | 509 | ReserveSurface(params, new_surface); |
| 504 | ReserveSurface(params, std::move(new_surface)); | 510 | return new_surface; |
| 505 | return surface; | ||
| 506 | } | 511 | } |
| 507 | 512 | ||
| 508 | Core::System& system; | 513 | Core::System& system; |
| 509 | 514 | ||
| 510 | private: | 515 | private: |
| 511 | ResultType GetSurfaceView(TExecutionContext exctx, VAddr cpu_addr, const SurfaceParams& params, | 516 | ResultType GetSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, |
| 512 | bool preserve_contents) { | 517 | const SurfaceParams& params, bool preserve_contents) { |
| 513 | const auto host_ptr{Memory::GetPointer(cpu_addr)}; | 518 | auto& memory_manager{system.GPU().MemoryManager()}; |
| 519 | const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; | ||
| 520 | DEBUG_ASSERT(cpu_addr); | ||
| 521 | |||
| 522 | const auto host_ptr{memory_manager.GetPointer(gpu_addr)}; | ||
| 514 | const auto cache_addr{ToCacheAddr(host_ptr)}; | 523 | const auto cache_addr{ToCacheAddr(host_ptr)}; |
| 515 | const auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())}; | 524 | const auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())}; |
| 516 | if (overlaps.empty()) { | 525 | if (overlaps.empty()) { |
| 517 | return LoadSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents); | 526 | return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); |
| 518 | } | 527 | } |
| 519 | 528 | ||
| 520 | if (overlaps.size() == 1) { | 529 | if (overlaps.size() == 1) { |
| 521 | if (TView* view = overlaps[0]->TryGetView(cpu_addr, params); view) | 530 | if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) { |
| 522 | return {view, exctx}; | 531 | return {view, exctx}; |
| 532 | } | ||
| 523 | } | 533 | } |
| 524 | 534 | ||
| 525 | TView* fast_view; | 535 | TView* fast_view; |
| 526 | std::tie(fast_view, exctx) = | 536 | std::tie(fast_view, exctx) = TryFastGetSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, |
| 527 | TryFastGetSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents, overlaps); | 537 | params, preserve_contents, overlaps); |
| 538 | |||
| 539 | if (!fast_view) { | ||
| 540 | std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) { | ||
| 541 | return lhs->GetModificationTick() < rhs->GetModificationTick(); | ||
| 542 | }); | ||
| 543 | } | ||
| 528 | 544 | ||
| 529 | for (TSurface* surface : overlaps) { | 545 | for (const auto& surface : overlaps) { |
| 530 | if (!fast_view) { | 546 | if (!fast_view) { |
| 531 | // Flush even when we don't care about the contents, to preserve memory not written | 547 | // Flush even when we don't care about the contents, to preserve memory not written |
| 532 | // by the new surface. | 548 | // by the new surface. |
| @@ -539,57 +555,59 @@ private: | |||
| 539 | return {fast_view, exctx}; | 555 | return {fast_view, exctx}; |
| 540 | } | 556 | } |
| 541 | 557 | ||
| 542 | return LoadSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents); | 558 | return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); |
| 543 | } | 559 | } |
| 544 | 560 | ||
| 545 | ResultType LoadSurfaceView(TExecutionContext exctx, VAddr cpu_addr, u8* host_ptr, | 561 | ResultType LoadSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, |
| 546 | const SurfaceParams& params, bool preserve_contents) { | 562 | u8* host_ptr, const SurfaceParams& params, bool preserve_contents) { |
| 547 | TSurface* new_surface{GetUncachedSurface(params)}; | 563 | const auto new_surface{GetUncachedSurface(params)}; |
| 548 | Register(new_surface, cpu_addr, host_ptr); | 564 | Register(new_surface, gpu_addr, cpu_addr, host_ptr); |
| 549 | if (preserve_contents) { | 565 | if (preserve_contents) { |
| 550 | exctx = LoadSurface(exctx, new_surface); | 566 | exctx = LoadSurface(exctx, new_surface); |
| 551 | } | 567 | } |
| 552 | return {new_surface->GetView(cpu_addr, params), exctx}; | 568 | return {new_surface->GetView(gpu_addr, params), exctx}; |
| 553 | } | 569 | } |
| 554 | 570 | ||
| 555 | TExecutionContext LoadSurface(TExecutionContext exctx, TSurface* surface) { | 571 | TExecutionContext LoadSurface(TExecutionContext exctx, |
| 572 | const std::shared_ptr<TSurface>& surface) { | ||
| 556 | surface->LoadBuffer(); | 573 | surface->LoadBuffer(); |
| 557 | exctx = surface->UploadTexture(exctx); | 574 | exctx = surface->UploadTexture(exctx); |
| 558 | surface->MarkAsModified(false); | 575 | surface->MarkAsModified(false); |
| 559 | return exctx; | 576 | return exctx; |
| 560 | } | 577 | } |
| 561 | 578 | ||
| 562 | std::vector<TSurface*> GetSurfacesInRegion(CacheAddr cache_addr, std::size_t size) const { | 579 | std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr, |
| 580 | std::size_t size) const { | ||
| 563 | if (size == 0) { | 581 | if (size == 0) { |
| 564 | return {}; | 582 | return {}; |
| 565 | } | 583 | } |
| 566 | const IntervalType interval{cache_addr, cache_addr + size}; | 584 | const IntervalType interval{cache_addr, cache_addr + size}; |
| 567 | 585 | ||
| 568 | std::vector<TSurface*> surfaces; | 586 | std::vector<std::shared_ptr<TSurface>> surfaces; |
| 569 | for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) { | 587 | for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) { |
| 570 | surfaces.push_back(*pair.second.begin()); | 588 | surfaces.push_back(*pair.second.begin()); |
| 571 | } | 589 | } |
| 572 | return surfaces; | 590 | return surfaces; |
| 573 | } | 591 | } |
| 574 | 592 | ||
| 575 | void ReserveSurface(const SurfaceParams& params, std::unique_ptr<TSurface> surface) { | 593 | void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) { |
| 576 | surface_reserve[params].push_back(std::move(surface)); | 594 | surface_reserve[params].push_back(std::move(surface)); |
| 577 | } | 595 | } |
| 578 | 596 | ||
| 579 | TSurface* TryGetReservedSurface(const SurfaceParams& params) { | 597 | std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) { |
| 580 | auto search{surface_reserve.find(params)}; | 598 | auto search{surface_reserve.find(params)}; |
| 581 | if (search == surface_reserve.end()) { | 599 | if (search == surface_reserve.end()) { |
| 582 | return {}; | 600 | return {}; |
| 583 | } | 601 | } |
| 584 | for (auto& surface : search->second) { | 602 | for (auto& surface : search->second) { |
| 585 | if (!surface->IsRegistered()) { | 603 | if (!surface->IsRegistered()) { |
| 586 | return surface.get(); | 604 | return surface; |
| 587 | } | 605 | } |
| 588 | } | 606 | } |
| 589 | return {}; | 607 | return {}; |
| 590 | } | 608 | } |
| 591 | 609 | ||
| 592 | IntervalType GetSurfaceInterval(TSurface* surface) const { | 610 | IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const { |
| 593 | return IntervalType::right_open(surface->GetCacheAddr(), | 611 | return IntervalType::right_open(surface->GetCacheAddr(), |
| 594 | surface->GetCacheAddr() + surface->GetSizeInBytes()); | 612 | surface->GetCacheAddr() + surface->GetSizeInBytes()); |
| 595 | } | 613 | } |
| @@ -601,7 +619,7 @@ private: | |||
| 601 | /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have | 619 | /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have |
| 602 | /// previously been used. This is to prevent surfaces from being constantly created and | 620 | /// previously been used. This is to prevent surfaces from being constantly created and |
| 603 | /// destroyed when used with different surface parameters. | 621 | /// destroyed when used with different surface parameters. |
| 604 | std::unordered_map<SurfaceParams, std::list<std::unique_ptr<TSurface>>> surface_reserve; | 622 | std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve; |
| 605 | }; | 623 | }; |
| 606 | 624 | ||
| 607 | struct DummyExecutionContext {}; | 625 | struct DummyExecutionContext {}; |
| @@ -631,7 +649,7 @@ public: | |||
| 631 | return RemoveContext(Base::GetFermiSurface({}, config)); | 649 | return RemoveContext(Base::GetFermiSurface({}, config)); |
| 632 | } | 650 | } |
| 633 | 651 | ||
| 634 | TSurface* TryFindFramebufferSurface(const u8* host_ptr) const { | 652 | std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const { |
| 635 | return Base::TryFindFramebufferSurface(host_ptr); | 653 | return Base::TryFindFramebufferSurface(host_ptr); |
| 636 | } | 654 | } |
| 637 | 655 | ||
| @@ -640,15 +658,18 @@ protected: | |||
| 640 | VideoCore::RasterizerInterface& rasterizer) | 658 | VideoCore::RasterizerInterface& rasterizer) |
| 641 | : TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {} | 659 | : TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {} |
| 642 | 660 | ||
| 643 | virtual TView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, | 661 | virtual TView* TryFastGetSurfaceView( |
| 644 | bool preserve_contents, | 662 | GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, |
| 645 | const std::vector<TSurface*>& overlaps) = 0; | 663 | bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0; |
| 646 | 664 | ||
| 647 | private: | 665 | private: |
| 648 | std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView( | 666 | std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView( |
| 649 | DummyExecutionContext, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, | 667 | DummyExecutionContext, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, |
| 650 | bool preserve_contents, const std::vector<TSurface*>& overlaps) { | 668 | const SurfaceParams& params, bool preserve_contents, |
| 651 | return {TryFastGetSurfaceView(cpu_addr, host_ptr, params, preserve_contents, overlaps), {}}; | 669 | const std::vector<std::shared_ptr<TSurface>>& overlaps) { |
| 670 | return {TryFastGetSurfaceView(gpu_addr, cpu_addr, host_ptr, params, preserve_contents, | ||
| 671 | overlaps), | ||
| 672 | {}}; | ||
| 652 | } | 673 | } |
| 653 | 674 | ||
| 654 | TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) { | 675 | TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) { |