diff options
| author | 2019-04-11 17:14:55 -0300 | |
|---|---|---|
| committer | 2019-06-20 21:36:11 -0300 | |
| commit | bab21e8cb3df9c06e3c0a37a8fc68fed676f5d6e (patch) | |
| tree | 860ce1a40373ff6002506bef72f78022de7d022c /src | |
| parent | Merge pull request #2596 from FernandoS27/revert-2590 (diff) | |
| download | yuzu-bab21e8cb3df9c06e3c0a37a8fc68fed676f5d6e.tar.gz yuzu-bab21e8cb3df9c06e3c0a37a8fc68fed676f5d6e.tar.xz yuzu-bab21e8cb3df9c06e3c0a37a8fc68fed676f5d6e.zip | |
gl_texture_cache: Initial implementation
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 66 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.cpp | 514 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.h | 131 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/texture_cache.cpp | 37 | ||||
| -rw-r--r-- | src/video_core/texture_cache.h | 96 | ||||
| -rw-r--r-- | src/video_core/textures/decoders.cpp | 3 |
9 files changed, 809 insertions, 47 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f8b67cbe1..64cff27a4 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -45,8 +45,6 @@ add_library(video_core STATIC | |||
| 45 | renderer_opengl/gl_global_cache.h | 45 | renderer_opengl/gl_global_cache.h |
| 46 | renderer_opengl/gl_rasterizer.cpp | 46 | renderer_opengl/gl_rasterizer.cpp |
| 47 | renderer_opengl/gl_rasterizer.h | 47 | renderer_opengl/gl_rasterizer.h |
| 48 | renderer_opengl/gl_rasterizer_cache.cpp | ||
| 49 | renderer_opengl/gl_rasterizer_cache.h | ||
| 50 | renderer_opengl/gl_resource_manager.cpp | 48 | renderer_opengl/gl_resource_manager.cpp |
| 51 | renderer_opengl/gl_resource_manager.h | 49 | renderer_opengl/gl_resource_manager.h |
| 52 | renderer_opengl/gl_sampler_cache.cpp | 50 | renderer_opengl/gl_sampler_cache.cpp |
| @@ -67,6 +65,8 @@ add_library(video_core STATIC | |||
| 67 | renderer_opengl/gl_state.h | 65 | renderer_opengl/gl_state.h |
| 68 | renderer_opengl/gl_stream_buffer.cpp | 66 | renderer_opengl/gl_stream_buffer.cpp |
| 69 | renderer_opengl/gl_stream_buffer.h | 67 | renderer_opengl/gl_stream_buffer.h |
| 68 | renderer_opengl/gl_texture_cache.cpp | ||
| 69 | renderer_opengl/gl_texture_cache.h | ||
| 70 | renderer_opengl/maxwell_to_gl.h | 70 | renderer_opengl/maxwell_to_gl.h |
| 71 | renderer_opengl/renderer_opengl.cpp | 71 | renderer_opengl/renderer_opengl.cpp |
| 72 | renderer_opengl/renderer_opengl.h | 72 | renderer_opengl/renderer_opengl.h |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d77426067..cea268f1e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -100,7 +100,7 @@ struct FramebufferCacheKey { | |||
| 100 | 100 | ||
| 101 | RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, | 101 | RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, |
| 102 | ScreenInfo& info) | 102 | ScreenInfo& info) |
| 103 | : res_cache{*this}, shader_cache{*this, system, emu_window, device}, | 103 | : texture_cache{system, *this}, shader_cache{*this, system, emu_window, device}, |
| 104 | global_cache{*this}, system{system}, screen_info{info}, | 104 | global_cache{*this}, system{system}, screen_info{info}, |
| 105 | buffer_cache(*this, STREAM_BUFFER_SIZE) { | 105 | buffer_cache(*this, STREAM_BUFFER_SIZE) { |
| 106 | OpenGLState::ApplyDefaultState(); | 106 | OpenGLState::ApplyDefaultState(); |
| @@ -478,9 +478,9 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | |||
| 478 | } | 478 | } |
| 479 | current_framebuffer_config_state = fb_config_state; | 479 | current_framebuffer_config_state = fb_config_state; |
| 480 | 480 | ||
| 481 | Surface depth_surface; | 481 | CachedSurfaceView* depth_surface{}; |
| 482 | if (using_depth_fb) { | 482 | if (using_depth_fb) { |
| 483 | depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); | 483 | depth_surface = texture_cache.GetDepthBufferSurface(preserve_contents); |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0); | 486 | UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0); |
| @@ -493,42 +493,43 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | |||
| 493 | if (using_color_fb) { | 493 | if (using_color_fb) { |
| 494 | if (single_color_target) { | 494 | if (single_color_target) { |
| 495 | // Used when just a single color attachment is enabled, e.g. for clearing a color buffer | 495 | // Used when just a single color attachment is enabled, e.g. for clearing a color buffer |
| 496 | Surface color_surface = | 496 | CachedSurfaceView* color_surface{ |
| 497 | res_cache.GetColorBufferSurface(*single_color_target, preserve_contents); | 497 | texture_cache.GetColorBufferSurface(*single_color_target, preserve_contents)}; |
| 498 | 498 | ||
| 499 | if (color_surface) { | 499 | if (color_surface) { |
| 500 | // Assume that a surface will be written to if it is used as a framebuffer, even if | 500 | // Assume that a surface will be written to if it is used as a framebuffer, even if |
| 501 | // the shader doesn't actually write to it. | 501 | // the shader doesn't actually write to it. |
| 502 | color_surface->MarkAsModified(true, res_cache); | 502 | color_surface->MarkAsModified(true); |
| 503 | // Workaround for and issue in nvidia drivers | 503 | // Workaround for and issue in nvidia drivers |
| 504 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ | 504 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ |
| 505 | state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion; | 505 | // state.framebuffer_srgb.enabled |= |
| 506 | // color_surface->GetSurfaceParams().srgb_conversion; | ||
| 506 | } | 507 | } |
| 507 | 508 | ||
| 508 | fbkey.is_single_buffer = true; | 509 | fbkey.is_single_buffer = true; |
| 509 | fbkey.color_attachments[0] = | 510 | fbkey.color_attachments[0] = |
| 510 | GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target); | 511 | GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target); |
| 511 | fbkey.colors[0] = color_surface != nullptr ? color_surface->Texture().handle : 0; | 512 | fbkey.colors[0] = color_surface != nullptr ? color_surface->GetTexture() : 0; |
| 512 | } else { | 513 | } else { |
| 513 | // Multiple color attachments are enabled | 514 | // Multiple color attachments are enabled |
| 514 | for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | 515 | for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { |
| 515 | Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); | 516 | CachedSurfaceView* color_surface{ |
| 517 | texture_cache.GetColorBufferSurface(index, preserve_contents)}; | ||
| 516 | 518 | ||
| 517 | if (color_surface) { | 519 | if (color_surface) { |
| 518 | // Assume that a surface will be written to if it is used as a framebuffer, even | 520 | // Assume that a surface will be written to if it is used as a framebuffer, even |
| 519 | // if the shader doesn't actually write to it. | 521 | // if the shader doesn't actually write to it. |
| 520 | color_surface->MarkAsModified(true, res_cache); | 522 | color_surface->MarkAsModified(true); |
| 521 | // Enable sRGB only for supported formats | 523 | // Enable sRGB only for supported formats |
| 522 | // Workaround for and issue in nvidia drivers | 524 | // Workaround for and issue in nvidia drivers |
| 523 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ | 525 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ |
| 524 | state.framebuffer_srgb.enabled |= | 526 | // state.framebuffer_srgb.enabled |= |
| 525 | color_surface->GetSurfaceParams().srgb_conversion; | 527 | // color_surface->GetSurfaceParams().srgb_conversion; |
| 526 | } | 528 | } |
| 527 | 529 | ||
| 528 | fbkey.color_attachments[index] = | 530 | fbkey.color_attachments[index] = |
| 529 | GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); | 531 | GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); |
| 530 | fbkey.colors[index] = | 532 | fbkey.colors[index] = color_surface != nullptr ? color_surface->GetTexture() : 0; |
| 531 | color_surface != nullptr ? color_surface->Texture().handle : 0; | ||
| 532 | } | 533 | } |
| 533 | fbkey.is_single_buffer = false; | 534 | fbkey.is_single_buffer = false; |
| 534 | fbkey.colors_count = regs.rt_control.count; | 535 | fbkey.colors_count = regs.rt_control.count; |
| @@ -541,11 +542,11 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | |||
| 541 | if (depth_surface) { | 542 | if (depth_surface) { |
| 542 | // Assume that a surface will be written to if it is used as a framebuffer, even if | 543 | // Assume that a surface will be written to if it is used as a framebuffer, even if |
| 543 | // the shader doesn't actually write to it. | 544 | // the shader doesn't actually write to it. |
| 544 | depth_surface->MarkAsModified(true, res_cache); | 545 | depth_surface->MarkAsModified(true); |
| 545 | 546 | ||
| 546 | fbkey.zeta = depth_surface->Texture().handle; | 547 | fbkey.zeta = depth_surface->GetTexture(); |
| 547 | fbkey.stencil_enable = regs.stencil_enable && | 548 | fbkey.stencil_enable = regs.stencil_enable && depth_surface->GetSurfaceParams().GetType() == |
| 548 | depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil; | 549 | SurfaceType::DepthStencil; |
| 549 | } | 550 | } |
| 550 | 551 | ||
| 551 | SetupCachedFramebuffer(fbkey, current_state); | 552 | SetupCachedFramebuffer(fbkey, current_state); |
| @@ -704,9 +705,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 704 | shader_program_manager->ApplyTo(state); | 705 | shader_program_manager->ApplyTo(state); |
| 705 | state.Apply(); | 706 | state.Apply(); |
| 706 | 707 | ||
| 707 | res_cache.SignalPreDrawCall(); | ||
| 708 | params.DispatchDraw(); | 708 | params.DispatchDraw(); |
| 709 | res_cache.SignalPostDrawCall(); | ||
| 710 | 709 | ||
| 711 | accelerate_draw = AccelDraw::Disabled; | 710 | accelerate_draw = AccelDraw::Disabled; |
| 712 | } | 711 | } |
| @@ -718,7 +717,7 @@ void RasterizerOpenGL::FlushRegion(CacheAddr addr, u64 size) { | |||
| 718 | if (!addr || !size) { | 717 | if (!addr || !size) { |
| 719 | return; | 718 | return; |
| 720 | } | 719 | } |
| 721 | res_cache.FlushRegion(addr, size); | 720 | // texture_cache.FlushRegion(addr, size); |
| 722 | global_cache.FlushRegion(addr, size); | 721 | global_cache.FlushRegion(addr, size); |
| 723 | } | 722 | } |
| 724 | 723 | ||
| @@ -727,7 +726,7 @@ void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) { | |||
| 727 | if (!addr || !size) { | 726 | if (!addr || !size) { |
| 728 | return; | 727 | return; |
| 729 | } | 728 | } |
| 730 | res_cache.InvalidateRegion(addr, size); | 729 | texture_cache.InvalidateRegion(addr, size); |
| 731 | shader_cache.InvalidateRegion(addr, size); | 730 | shader_cache.InvalidateRegion(addr, size); |
| 732 | global_cache.InvalidateRegion(addr, size); | 731 | global_cache.InvalidateRegion(addr, size); |
| 733 | buffer_cache.InvalidateRegion(addr, size); | 732 | buffer_cache.InvalidateRegion(addr, size); |
| @@ -743,7 +742,8 @@ bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs | |||
| 743 | const Common::Rectangle<u32>& src_rect, | 742 | const Common::Rectangle<u32>& src_rect, |
| 744 | const Common::Rectangle<u32>& dst_rect) { | 743 | const Common::Rectangle<u32>& dst_rect) { |
| 745 | MICROPROFILE_SCOPE(OpenGL_Blits); | 744 | MICROPROFILE_SCOPE(OpenGL_Blits); |
| 746 | res_cache.FermiCopySurface(src, dst, src_rect, dst_rect); | 745 | UNIMPLEMENTED(); |
| 746 | // texture_cache.FermiCopySurface(src, dst, src_rect, dst_rect); | ||
| 747 | return true; | 747 | return true; |
| 748 | } | 748 | } |
| 749 | 749 | ||
| @@ -755,7 +755,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 755 | 755 | ||
| 756 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); | 756 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); |
| 757 | 757 | ||
| 758 | const auto& surface{res_cache.TryFindFramebufferSurface(Memory::GetPointer(framebuffer_addr))}; | 758 | const auto surface{ |
| 759 | texture_cache.TryFindFramebufferSurface(Memory::GetPointer(framebuffer_addr))}; | ||
| 759 | if (!surface) { | 760 | if (!surface) { |
| 760 | return {}; | 761 | return {}; |
| 761 | } | 762 | } |
| @@ -764,14 +765,14 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 764 | const auto& params{surface->GetSurfaceParams()}; | 765 | const auto& params{surface->GetSurfaceParams()}; |
| 765 | const auto& pixel_format{ | 766 | const auto& pixel_format{ |
| 766 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)}; | 767 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)}; |
| 767 | ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); | 768 | ASSERT_MSG(params.GetWidth() == config.width, "Framebuffer width is different"); |
| 768 | ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); | 769 | ASSERT_MSG(params.GetHeight() == config.height, "Framebuffer height is different"); |
| 769 | 770 | ||
| 770 | if (params.pixel_format != pixel_format) { | 771 | if (params.GetPixelFormat() != pixel_format) { |
| 771 | LOG_WARNING(Render_OpenGL, "Framebuffer pixel_format is different"); | 772 | LOG_WARNING(Render_OpenGL, "Framebuffer pixel_format is different"); |
| 772 | } | 773 | } |
| 773 | 774 | ||
| 774 | screen_info.display_texture = surface->Texture().handle; | 775 | screen_info.display_texture = surface->GetTexture(); |
| 775 | 776 | ||
| 776 | return true; | 777 | return true; |
| 777 | } | 778 | } |
| @@ -862,11 +863,10 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s | |||
| 862 | 863 | ||
| 863 | state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc); | 864 | state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc); |
| 864 | 865 | ||
| 865 | if (Surface surface = res_cache.GetTextureSurface(texture, entry); surface) { | 866 | if (const auto surface{texture_cache.GetTextureSurface(texture)}; surface) { |
| 866 | state.texture_units[current_bindpoint].texture = | 867 | state.texture_units[current_bindpoint].texture = surface->GetTexture( |
| 867 | surface->Texture(entry.IsArray()).handle; | 868 | entry.GetType(), entry.IsArray(), texture.tic.x_source, texture.tic.y_source, |
| 868 | surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, | 869 | texture.tic.z_source, texture.tic.w_source); |
| 869 | texture.tic.w_source); | ||
| 870 | } else { | 870 | } else { |
| 871 | // Can occur when texture addr is null or its memory is unmapped/invalid | 871 | // Can occur when texture addr is null or its memory is unmapped/invalid |
| 872 | state.texture_units[current_bindpoint].texture = 0; | 872 | state.texture_units[current_bindpoint].texture = 0; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index f7671ff5d..921e9fc31 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -24,13 +24,13 @@ | |||
| 24 | #include "video_core/renderer_opengl/gl_buffer_cache.h" | 24 | #include "video_core/renderer_opengl/gl_buffer_cache.h" |
| 25 | #include "video_core/renderer_opengl/gl_device.h" | 25 | #include "video_core/renderer_opengl/gl_device.h" |
| 26 | #include "video_core/renderer_opengl/gl_global_cache.h" | 26 | #include "video_core/renderer_opengl/gl_global_cache.h" |
| 27 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | ||
| 28 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 27 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 29 | #include "video_core/renderer_opengl/gl_sampler_cache.h" | 28 | #include "video_core/renderer_opengl/gl_sampler_cache.h" |
| 30 | #include "video_core/renderer_opengl/gl_shader_cache.h" | 29 | #include "video_core/renderer_opengl/gl_shader_cache.h" |
| 31 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | 30 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" |
| 32 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 31 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| 33 | #include "video_core/renderer_opengl/gl_state.h" | 32 | #include "video_core/renderer_opengl/gl_state.h" |
| 33 | #include "video_core/renderer_opengl/gl_texture_cache.h" | ||
| 34 | #include "video_core/renderer_opengl/utils.h" | 34 | #include "video_core/renderer_opengl/utils.h" |
| 35 | 35 | ||
| 36 | namespace Core { | 36 | namespace Core { |
| @@ -181,7 +181,7 @@ private: | |||
| 181 | const Device device; | 181 | const Device device; |
| 182 | OpenGLState state; | 182 | OpenGLState state; |
| 183 | 183 | ||
| 184 | RasterizerCacheOpenGL res_cache; | 184 | TextureCacheOpenGL texture_cache; |
| 185 | ShaderCacheOpenGL shader_cache; | 185 | ShaderCacheOpenGL shader_cache; |
| 186 | GlobalRegionCacheOpenGL global_cache; | 186 | GlobalRegionCacheOpenGL global_cache; |
| 187 | SamplerCacheOpenGL sampler_cache; | 187 | SamplerCacheOpenGL sampler_cache; |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp new file mode 100644 index 000000000..3a456995e --- /dev/null +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -0,0 +1,514 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/scope_exit.h" | ||
| 8 | #include "video_core/morton.h" | ||
| 9 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 10 | #include "video_core/renderer_opengl/gl_texture_cache.h" | ||
| 11 | #include "video_core/texture_cache.h" | ||
| 12 | #include "video_core/textures/convert.h" | ||
| 13 | #include "video_core/textures/texture.h" | ||
| 14 | |||
| 15 | namespace OpenGL { | ||
| 16 | |||
| 17 | using Tegra::Texture::ConvertFromGuestToHost; | ||
| 18 | using Tegra::Texture::SwizzleSource; | ||
| 19 | using VideoCore::MortonSwizzleMode; | ||
| 20 | |||
| 21 | namespace { | ||
| 22 | |||
| 23 | struct FormatTuple { | ||
| 24 | GLint internal_format; | ||
| 25 | GLenum format; | ||
| 26 | GLenum type; | ||
| 27 | ComponentType component_type; | ||
| 28 | bool compressed; | ||
| 29 | }; | ||
| 30 | |||
| 31 | constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ | ||
| 32 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U | ||
| 33 | {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S | ||
| 34 | {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI | ||
| 35 | {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U | ||
| 36 | {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm, | ||
| 37 | false}, // A2B10G10R10U | ||
| 38 | {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U | ||
| 39 | {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8U | ||
| 40 | {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // R8UI | ||
| 41 | {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F | ||
| 42 | {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // RGBA16U | ||
| 43 | {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RGBA16UI | ||
| 44 | {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, | ||
| 45 | false}, // R11FG11FB10F | ||
| 46 | {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI | ||
| 47 | {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 48 | true}, // DXT1 | ||
| 49 | {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 50 | true}, // DXT23 | ||
| 51 | {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 52 | true}, // DXT45 | ||
| 53 | {GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXN1 | ||
| 54 | {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 55 | true}, // DXN2UNORM | ||
| 56 | {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM | ||
| 57 | {GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 58 | true}, // BC7U | ||
| 59 | {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, | ||
| 60 | true}, // BC6H_UF16 | ||
| 61 | {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, | ||
| 62 | true}, // BC6H_SF16 | ||
| 63 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 | ||
| 64 | {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 | ||
| 65 | {GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F | ||
| 66 | {GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false}, // RG32F | ||
| 67 | {GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false}, // R32F | ||
| 68 | {GL_R16F, GL_RED, GL_HALF_FLOAT, ComponentType::Float, false}, // R16F | ||
| 69 | {GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // R16U | ||
| 70 | {GL_R16_SNORM, GL_RED, GL_SHORT, ComponentType::SNorm, false}, // R16S | ||
| 71 | {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // R16UI | ||
| 72 | {GL_R16I, GL_RED_INTEGER, GL_SHORT, ComponentType::SInt, false}, // R16I | ||
| 73 | {GL_RG16, GL_RG, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // RG16 | ||
| 74 | {GL_RG16F, GL_RG, GL_HALF_FLOAT, ComponentType::Float, false}, // RG16F | ||
| 75 | {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RG16UI | ||
| 76 | {GL_RG16I, GL_RG_INTEGER, GL_SHORT, ComponentType::SInt, false}, // RG16I | ||
| 77 | {GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S | ||
| 78 | {GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F | ||
| 79 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, | ||
| 80 | false}, // RGBA8_SRGB | ||
| 81 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U | ||
| 82 | {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S | ||
| 83 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI | ||
| 84 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI | ||
| 85 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8 | ||
| 86 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5 | ||
| 87 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4 | ||
| 88 | {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 | ||
| 89 | // Compressed sRGB formats | ||
| 90 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 91 | true}, // DXT1_SRGB | ||
| 92 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 93 | true}, // DXT23_SRGB | ||
| 94 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 95 | true}, // DXT45_SRGB | ||
| 96 | {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 97 | true}, // BC7U_SRGB | ||
| 98 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB | ||
| 99 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB | ||
| 100 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB | ||
| 101 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB | ||
| 102 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5 | ||
| 103 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB | ||
| 104 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8 | ||
| 105 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB | ||
| 106 | |||
| 107 | // Depth formats | ||
| 108 | {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F | ||
| 109 | {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, ComponentType::UNorm, | ||
| 110 | false}, // Z16 | ||
| 111 | |||
| 112 | // DepthStencil formats | ||
| 113 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, | ||
| 114 | false}, // Z24S8 | ||
| 115 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, | ||
| 116 | false}, // S8Z24 | ||
| 117 | {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, | ||
| 118 | ComponentType::Float, false}, // Z32FS8 | ||
| 119 | }}; | ||
| 120 | |||
| 121 | const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { | ||
| 122 | ASSERT(static_cast<std::size_t>(pixel_format) < tex_format_tuples.size()); | ||
| 123 | const auto& format{tex_format_tuples[static_cast<std::size_t>(pixel_format)]}; | ||
| 124 | ASSERT(component_type == format.component_type); | ||
| 125 | return format; | ||
| 126 | } | ||
| 127 | |||
| 128 | GLenum GetTextureTarget(const SurfaceParams& params) { | ||
| 129 | switch (params.GetTarget()) { | ||
| 130 | case SurfaceTarget::Texture1D: | ||
| 131 | return GL_TEXTURE_1D; | ||
| 132 | case SurfaceTarget::Texture2D: | ||
| 133 | return GL_TEXTURE_2D; | ||
| 134 | case SurfaceTarget::Texture3D: | ||
| 135 | return GL_TEXTURE_3D; | ||
| 136 | case SurfaceTarget::Texture1DArray: | ||
| 137 | return GL_TEXTURE_1D_ARRAY; | ||
| 138 | case SurfaceTarget::Texture2DArray: | ||
| 139 | return GL_TEXTURE_2D_ARRAY; | ||
| 140 | case SurfaceTarget::TextureCubemap: | ||
| 141 | return GL_TEXTURE_CUBE_MAP; | ||
| 142 | case SurfaceTarget::TextureCubeArray: | ||
| 143 | return GL_TEXTURE_CUBE_MAP_ARRAY; | ||
| 144 | } | ||
| 145 | UNREACHABLE(); | ||
| 146 | return {}; | ||
| 147 | } | ||
| 148 | |||
| 149 | GLint GetSwizzleSource(SwizzleSource source) { | ||
| 150 | switch (source) { | ||
| 151 | case SwizzleSource::Zero: | ||
| 152 | return GL_ZERO; | ||
| 153 | case SwizzleSource::R: | ||
| 154 | return GL_RED; | ||
| 155 | case SwizzleSource::G: | ||
| 156 | return GL_GREEN; | ||
| 157 | case SwizzleSource::B: | ||
| 158 | return GL_BLUE; | ||
| 159 | case SwizzleSource::A: | ||
| 160 | return GL_ALPHA; | ||
| 161 | case SwizzleSource::OneInt: | ||
| 162 | case SwizzleSource::OneFloat: | ||
| 163 | return GL_ONE; | ||
| 164 | } | ||
| 165 | UNREACHABLE(); | ||
| 166 | return GL_NONE; | ||
| 167 | } | ||
| 168 | |||
| 169 | void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { | ||
| 170 | glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
| 171 | glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
| 172 | glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 173 | glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 174 | glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, params.GetNumLevels() - 1); | ||
| 175 | if (params.GetNumLevels() == 1) { | ||
| 176 | glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | OGLTexture CreateTexture(const SurfaceParams& params, GLenum internal_format) { | ||
| 181 | OGLTexture texture; | ||
| 182 | texture.Create(GetTextureTarget(params)); | ||
| 183 | |||
| 184 | switch (params.GetTarget()) { | ||
| 185 | case SurfaceTarget::Texture1D: | ||
| 186 | glTextureStorage1D(texture.handle, params.GetNumLevels(), internal_format, | ||
| 187 | params.GetWidth()); | ||
| 188 | break; | ||
| 189 | case SurfaceTarget::Texture2D: | ||
| 190 | case SurfaceTarget::TextureCubemap: | ||
| 191 | glTextureStorage2D(texture.handle, params.GetNumLevels(), internal_format, | ||
| 192 | params.GetWidth(), params.GetHeight()); | ||
| 193 | break; | ||
| 194 | case SurfaceTarget::Texture3D: | ||
| 195 | case SurfaceTarget::Texture2DArray: | ||
| 196 | case SurfaceTarget::TextureCubeArray: | ||
| 197 | glTextureStorage3D(texture.handle, params.GetNumLevels(), internal_format, | ||
| 198 | params.GetWidth(), params.GetHeight(), params.GetDepth()); | ||
| 199 | break; | ||
| 200 | default: | ||
| 201 | UNREACHABLE(); | ||
| 202 | } | ||
| 203 | |||
| 204 | ApplyTextureDefaults(params, texture.handle); | ||
| 205 | |||
| 206 | return texture; | ||
| 207 | } | ||
| 208 | |||
| 209 | void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer, | ||
| 210 | u32 level) { | ||
| 211 | const u32 width{params.GetMipWidth(level)}; | ||
| 212 | const u32 height{params.GetMipHeight(level)}; | ||
| 213 | const u32 block_height{params.GetMipBlockHeight(level)}; | ||
| 214 | const u32 block_depth{params.GetMipBlockDepth(level)}; | ||
| 215 | |||
| 216 | std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)}; | ||
| 217 | if (params.IsLayered()) { | ||
| 218 | std::size_t host_offset{0}; | ||
| 219 | const std::size_t guest_stride = params.GetGuestLayerSize(); | ||
| 220 | const std::size_t host_stride = params.GetHostLayerSize(level); | ||
| 221 | for (u32 layer = 0; layer < params.GetNumLayers(); layer++) { | ||
| 222 | MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth, | ||
| 223 | 1, params.GetTileWidthSpacing(), buffer + host_offset, | ||
| 224 | memory + guest_offset); | ||
| 225 | guest_offset += guest_stride; | ||
| 226 | host_offset += host_stride; | ||
| 227 | } | ||
| 228 | } else { | ||
| 229 | MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth, | ||
| 230 | params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer, | ||
| 231 | memory + guest_offset); | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | } // Anonymous namespace | ||
| 236 | |||
| 237 | CachedSurface::CachedSurface(const SurfaceParams& params) | ||
| 238 | : VideoCommon::SurfaceBaseContextless<CachedSurfaceView>{params} { | ||
| 239 | const auto& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())}; | ||
| 240 | internal_format = tuple.internal_format; | ||
| 241 | format = tuple.format; | ||
| 242 | type = tuple.type; | ||
| 243 | is_compressed = tuple.compressed; | ||
| 244 | texture = CreateTexture(params, internal_format); | ||
| 245 | staging_buffer.resize(params.GetHostSizeInBytes()); | ||
| 246 | } | ||
| 247 | |||
| 248 | CachedSurface::~CachedSurface() = default; | ||
| 249 | |||
| 250 | void CachedSurface::LoadBuffer() { | ||
| 251 | if (params.IsTiled()) { | ||
| 252 | ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}", | ||
| 253 | params.GetBlockWidth(), static_cast<u32>(params.GetTarget())); | ||
| 254 | for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||
| 255 | u8* const buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)}; | ||
| 256 | SwizzleFunc(MortonSwizzleMode::MortonToLinear, GetHostPtr(), params, buffer, level); | ||
| 257 | } | ||
| 258 | } else { | ||
| 259 | ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented"); | ||
| 260 | const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT}; | ||
| 261 | const u32 block_width{VideoCore::Surface::GetDefaultBlockWidth(params.GetPixelFormat())}; | ||
| 262 | const u32 block_height{VideoCore::Surface::GetDefaultBlockHeight(params.GetPixelFormat())}; | ||
| 263 | const u32 width{(params.GetWidth() + block_width - 1) / block_width}; | ||
| 264 | const u32 height{(params.GetHeight() + block_height - 1) / block_height}; | ||
| 265 | const u32 copy_size{width * bpp}; | ||
| 266 | if (params.GetPitch() == copy_size) { | ||
| 267 | std::memcpy(staging_buffer.data(), GetHostPtr(), params.GetHostSizeInBytes()); | ||
| 268 | } else { | ||
| 269 | const u8* start{GetHostPtr()}; | ||
| 270 | u8* write_to{staging_buffer.data()}; | ||
| 271 | for (u32 h = height; h > 0; --h) { | ||
| 272 | std::memcpy(write_to, start, copy_size); | ||
| 273 | start += params.GetPitch(); | ||
| 274 | write_to += copy_size; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||
| 280 | ConvertFromGuestToHost(staging_buffer.data() + params.GetHostMipmapLevelOffset(level), | ||
| 281 | params.GetPixelFormat(), params.GetMipWidth(level), | ||
| 282 | params.GetMipHeight(level), params.GetMipDepth(level), true, true); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | void CachedSurface::FlushBufferImpl() { | ||
| 287 | if (!IsModified()) { | ||
| 288 | return; | ||
| 289 | } | ||
| 290 | |||
| 291 | // TODO(Rodrigo): Optimize alignment | ||
| 292 | glPixelStorei(GL_PACK_ALIGNMENT, 1); | ||
| 293 | SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); | ||
| 294 | |||
| 295 | for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||
| 296 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); | ||
| 297 | if (is_compressed) { | ||
| 298 | glGetCompressedTextureImage( | ||
| 299 | texture.handle, level, static_cast<GLsizei>(params.GetHostMipmapSize(level)), | ||
| 300 | staging_buffer.data() + params.GetHostMipmapLevelOffset(level)); | ||
| 301 | } else { | ||
| 302 | glGetTextureImage(texture.handle, level, format, type, | ||
| 303 | static_cast<GLsizei>(params.GetHostMipmapSize(level)), | ||
| 304 | staging_buffer.data() + params.GetHostMipmapLevelOffset(level)); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | if (params.IsTiled()) { | ||
| 309 | ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}", | ||
| 310 | params.GetBlockWidth()); | ||
| 311 | for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||
| 312 | u8* const buffer = staging_buffer.data() + params.GetHostMipmapLevelOffset(level); | ||
| 313 | SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level); | ||
| 314 | } | ||
| 315 | } else { | ||
| 316 | UNIMPLEMENTED(); | ||
| 317 | /* | ||
| 318 | ASSERT(params.GetTarget() == SurfaceTarget::Texture2D); | ||
| 319 | ASSERT(params.GetNumLevels() == 1); | ||
| 320 | |||
| 321 | const u32 bpp{params.GetFormatBpp() / 8}; | ||
| 322 | const u32 copy_size{params.GetWidth() * bpp}; | ||
| 323 | if (params.GetPitch() == copy_size) { | ||
| 324 | std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes()); | ||
| 325 | } else { | ||
| 326 | u8* start{host_ptr}; | ||
| 327 | const u8* read_to{staging_buffer.data()}; | ||
| 328 | for (u32 h = params.GetHeight(); h > 0; --h) { | ||
| 329 | std::memcpy(start, read_to, copy_size); | ||
| 330 | start += params.GetPitch(); | ||
| 331 | read_to += copy_size; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | */ | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | void CachedSurface::UploadTextureImpl() { | ||
| 339 | for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||
| 340 | UploadTextureMipmap(level); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | void CachedSurface::UploadTextureMipmap(u32 level) { | ||
| 345 | u8* buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)}; | ||
| 346 | |||
| 347 | // TODO(Rodrigo): Optimize alignment | ||
| 348 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||
| 349 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); | ||
| 350 | SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); }); | ||
| 351 | |||
| 352 | if (is_compressed) { | ||
| 353 | const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))}; | ||
| 354 | GLint expected_size; | ||
| 355 | glGetTextureLevelParameteriv(texture.handle, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, | ||
| 356 | &expected_size); | ||
| 357 | switch (params.GetTarget()) { | ||
| 358 | case SurfaceTarget::Texture2D: | ||
| 359 | glCompressedTextureSubImage2D(texture.handle, level, 0, 0, | ||
| 360 | static_cast<GLsizei>(params.GetMipWidth(level)), | ||
| 361 | static_cast<GLsizei>(params.GetMipHeight(level)), | ||
| 362 | internal_format, image_size, buffer); | ||
| 363 | break; | ||
| 364 | case SurfaceTarget::Texture3D: | ||
| 365 | case SurfaceTarget::Texture2DArray: | ||
| 366 | case SurfaceTarget::TextureCubeArray: | ||
| 367 | glCompressedTextureSubImage3D(texture.handle, level, 0, 0, 0, | ||
| 368 | static_cast<GLsizei>(params.GetMipWidth(level)), | ||
| 369 | static_cast<GLsizei>(params.GetMipHeight(level)), | ||
| 370 | static_cast<GLsizei>(params.GetMipDepth(level)), | ||
| 371 | internal_format, image_size, buffer); | ||
| 372 | break; | ||
| 373 | case SurfaceTarget::TextureCubemap: { | ||
| 374 | const std::size_t layer_size{params.GetHostLayerSize(level)}; | ||
| 375 | for (std::size_t face = 0; face < params.GetDepth(); ++face) { | ||
| 376 | glCompressedTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face), | ||
| 377 | static_cast<GLsizei>(params.GetMipWidth(level)), | ||
| 378 | static_cast<GLsizei>(params.GetMipHeight(level)), 1, | ||
| 379 | internal_format, static_cast<GLsizei>(layer_size), | ||
| 380 | buffer); | ||
| 381 | buffer += layer_size; | ||
| 382 | } | ||
| 383 | break; | ||
| 384 | } | ||
| 385 | default: | ||
| 386 | UNREACHABLE(); | ||
| 387 | } | ||
| 388 | } else { | ||
| 389 | switch (params.GetTarget()) { | ||
| 390 | case SurfaceTarget::Texture1D: | ||
| 391 | glTextureSubImage1D(texture.handle, level, 0, params.GetMipWidth(level), format, type, | ||
| 392 | buffer); | ||
| 393 | break; | ||
| 394 | case SurfaceTarget::Texture1DArray: | ||
| 395 | case SurfaceTarget::Texture2D: | ||
| 396 | glTextureSubImage2D(texture.handle, level, 0, 0, params.GetMipWidth(level), | ||
| 397 | params.GetMipHeight(level), format, type, buffer); | ||
| 398 | break; | ||
| 399 | case SurfaceTarget::Texture3D: | ||
| 400 | case SurfaceTarget::Texture2DArray: | ||
| 401 | case SurfaceTarget::TextureCubeArray: | ||
| 402 | glTextureSubImage3D( | ||
| 403 | texture.handle, level, 0, 0, 0, static_cast<GLsizei>(params.GetMipWidth(level)), | ||
| 404 | static_cast<GLsizei>(params.GetMipHeight(level)), | ||
| 405 | static_cast<GLsizei>(params.GetMipDepth(level)), format, type, buffer); | ||
| 406 | break; | ||
| 407 | case SurfaceTarget::TextureCubemap: | ||
| 408 | for (std::size_t face = 0; face < params.GetDepth(); ++face) { | ||
| 409 | glTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face), | ||
| 410 | params.GetMipWidth(level), params.GetMipHeight(level), 1, | ||
| 411 | format, type, buffer); | ||
| 412 | buffer += params.GetHostLayerSize(level); | ||
| 413 | } | ||
| 414 | break; | ||
| 415 | default: | ||
| 416 | UNREACHABLE(); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) { | ||
| 422 | return std::make_unique<CachedSurfaceView>(*this, view_key); | ||
| 423 | } | ||
| 424 | |||
| 425 | CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, ViewKey key) | ||
| 426 | : surface{surface}, key{key}, params{surface.GetSurfaceParams()} {} | ||
| 427 | |||
| 428 | CachedSurfaceView::~CachedSurfaceView() = default; | ||
| 429 | |||
| 430 | GLuint CachedSurfaceView::GetTexture() { | ||
| 431 | // TODO(Rodrigo): Remove this entry and attach the super texture to the framebuffer through | ||
| 432 | // legacy API (also dropping Intel driver issues). | ||
| 433 | if (texture_view_2d.texture.handle == 0) { | ||
| 434 | texture_view_2d = CreateTextureView(GL_TEXTURE_2D); | ||
| 435 | } | ||
| 436 | return texture_view_2d.texture.handle; | ||
| 437 | } | ||
| 438 | |||
| 439 | GLuint CachedSurfaceView::GetTexture(Tegra::Shader::TextureType texture_type, bool is_array, | ||
| 440 | SwizzleSource x_source, SwizzleSource y_source, | ||
| 441 | SwizzleSource z_source, SwizzleSource w_source) { | ||
| 442 | const auto [texture_view, target] = GetTextureView(texture_type, is_array); | ||
| 443 | if (texture_view.get().texture.handle == 0) { | ||
| 444 | texture_view.get() = std::move(CreateTextureView(target)); | ||
| 445 | } | ||
| 446 | ApplySwizzle(texture_view, x_source, y_source, z_source, w_source); | ||
| 447 | return texture_view.get().texture.handle; | ||
| 448 | } | ||
| 449 | |||
| 450 | void CachedSurfaceView::ApplySwizzle(TextureView& texture_view, SwizzleSource x_source, | ||
| 451 | SwizzleSource y_source, SwizzleSource z_source, | ||
| 452 | SwizzleSource w_source) { | ||
| 453 | const std::array<SwizzleSource, 4> swizzle = {x_source, y_source, z_source, w_source}; | ||
| 454 | if (swizzle == texture_view.swizzle) { | ||
| 455 | return; | ||
| 456 | } | ||
| 457 | const std::array<GLint, 4> gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source), | ||
| 458 | GetSwizzleSource(z_source), | ||
| 459 | GetSwizzleSource(w_source)}; | ||
| 460 | glTextureParameteriv(texture_view.texture.handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data()); | ||
| 461 | texture_view.swizzle = swizzle; | ||
| 462 | } | ||
| 463 | |||
| 464 | CachedSurfaceView::TextureView CachedSurfaceView::CreateTextureView(GLenum target) const { | ||
| 465 | TextureView texture_view; | ||
| 466 | glGenTextures(1, &texture_view.texture.handle); | ||
| 467 | |||
| 468 | const GLuint handle{texture_view.texture.handle}; | ||
| 469 | const FormatTuple& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())}; | ||
| 470 | |||
| 471 | glTextureView(handle, target, surface.texture.handle, tuple.internal_format, key.base_level, | ||
| 472 | key.num_levels, key.base_layer, key.num_layers); | ||
| 473 | ApplyTextureDefaults(params, handle); | ||
| 474 | |||
| 475 | return texture_view; | ||
| 476 | } | ||
| 477 | |||
| 478 | std::pair<std::reference_wrapper<CachedSurfaceView::TextureView>, GLenum> | ||
| 479 | CachedSurfaceView::GetTextureView(Tegra::Shader::TextureType texture_type, bool is_array) { | ||
| 480 | using Pair = std::pair<std::reference_wrapper<TextureView>, GLenum>; | ||
| 481 | switch (texture_type) { | ||
| 482 | case Tegra::Shader::TextureType::Texture1D: | ||
| 483 | return is_array ? Pair{texture_view_1d_array, GL_TEXTURE_1D_ARRAY} | ||
| 484 | : Pair{texture_view_1d, GL_TEXTURE_1D}; | ||
| 485 | case Tegra::Shader::TextureType::Texture2D: | ||
| 486 | return is_array ? Pair{texture_view_2d_array, GL_TEXTURE_2D_ARRAY} | ||
| 487 | : Pair{texture_view_2d, GL_TEXTURE_2D}; | ||
| 488 | case Tegra::Shader::TextureType::Texture3D: | ||
| 489 | ASSERT(!is_array); | ||
| 490 | return {texture_view_3d, GL_TEXTURE_3D}; | ||
| 491 | case Tegra::Shader::TextureType::TextureCube: | ||
| 492 | return is_array ? Pair{texture_view_cube_array, GL_TEXTURE_CUBE_MAP_ARRAY} | ||
| 493 | : Pair{texture_view_cube, GL_TEXTURE_CUBE_MAP}; | ||
| 494 | } | ||
| 495 | UNREACHABLE(); | ||
| 496 | } | ||
| 497 | |||
| 498 | TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, | ||
| 499 | VideoCore::RasterizerInterface& rasterizer) | ||
| 500 | : TextureCacheBase{system, rasterizer} {} | ||
| 501 | |||
| 502 | TextureCacheOpenGL::~TextureCacheOpenGL() = default; | ||
| 503 | |||
| 504 | CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView( | ||
| 505 | VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, bool preserve_contents, | ||
| 506 | const std::vector<CachedSurface*>& overlaps) { | ||
| 507 | return nullptr; | ||
| 508 | } | ||
| 509 | |||
| 510 | std::unique_ptr<CachedSurface> TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) { | ||
| 511 | return std::make_unique<CachedSurface>(params); | ||
| 512 | } | ||
| 513 | |||
| 514 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h new file mode 100644 index 000000000..f0a524882 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <functional> | ||
| 9 | #include <utility> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include <glad/glad.h> | ||
| 13 | |||
| 14 | #include "common/common_types.h" | ||
| 15 | #include "video_core/engines/shader_bytecode.h" | ||
| 16 | #include "video_core/texture_cache.h" | ||
| 17 | |||
| 18 | namespace OpenGL { | ||
| 19 | |||
| 20 | using VideoCommon::SurfaceParams; | ||
| 21 | using VideoCommon::ViewKey; | ||
| 22 | using VideoCore::Surface::ComponentType; | ||
| 23 | using VideoCore::Surface::PixelFormat; | ||
| 24 | using VideoCore::Surface::SurfaceTarget; | ||
| 25 | using VideoCore::Surface::SurfaceType; | ||
| 26 | |||
| 27 | class CachedSurfaceView; | ||
| 28 | class CachedSurface; | ||
| 29 | |||
| 30 | using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>; | ||
| 31 | |||
| 32 | class CachedSurface final : public VideoCommon::SurfaceBaseContextless<CachedSurfaceView> { | ||
| 33 | friend CachedSurfaceView; | ||
| 34 | |||
| 35 | public: | ||
| 36 | explicit CachedSurface(const SurfaceParams& params); | ||
| 37 | ~CachedSurface(); | ||
| 38 | |||
| 39 | void LoadBuffer(); | ||
| 40 | |||
| 41 | GLuint GetTexture() const { | ||
| 42 | return texture.handle; | ||
| 43 | } | ||
| 44 | |||
| 45 | protected: | ||
| 46 | std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key); | ||
| 47 | |||
| 48 | void FlushBufferImpl(); | ||
| 49 | |||
| 50 | void UploadTextureImpl(); | ||
| 51 | |||
| 52 | private: | ||
| 53 | void UploadTextureMipmap(u32 level); | ||
| 54 | |||
| 55 | GLenum internal_format{}; | ||
| 56 | GLenum format{}; | ||
| 57 | GLenum type{}; | ||
| 58 | bool is_compressed{}; | ||
| 59 | |||
| 60 | OGLTexture texture; | ||
| 61 | |||
| 62 | std::vector<u8> staging_buffer; | ||
| 63 | u8* host_ptr{}; | ||
| 64 | }; | ||
| 65 | |||
| 66 | class CachedSurfaceView final { | ||
| 67 | public: | ||
| 68 | explicit CachedSurfaceView(CachedSurface& surface, ViewKey key); | ||
| 69 | ~CachedSurfaceView(); | ||
| 70 | |||
| 71 | GLuint GetTexture(); | ||
| 72 | |||
| 73 | GLuint GetTexture(Tegra::Shader::TextureType texture_type, bool is_array, | ||
| 74 | Tegra::Texture::SwizzleSource x_source, | ||
| 75 | Tegra::Texture::SwizzleSource y_source, | ||
| 76 | Tegra::Texture::SwizzleSource z_source, | ||
| 77 | Tegra::Texture::SwizzleSource w_source); | ||
| 78 | |||
| 79 | void MarkAsModified(bool is_modified) { | ||
| 80 | surface.MarkAsModified(is_modified); | ||
| 81 | } | ||
| 82 | |||
| 83 | const SurfaceParams& GetSurfaceParams() const { | ||
| 84 | return params; | ||
| 85 | } | ||
| 86 | |||
| 87 | private: | ||
| 88 | struct TextureView { | ||
| 89 | OGLTexture texture; | ||
| 90 | std::array<Tegra::Texture::SwizzleSource, 4> swizzle{ | ||
| 91 | Tegra::Texture::SwizzleSource::R, Tegra::Texture::SwizzleSource::G, | ||
| 92 | Tegra::Texture::SwizzleSource::B, Tegra::Texture::SwizzleSource::A}; | ||
| 93 | }; | ||
| 94 | |||
| 95 | void ApplySwizzle(TextureView& texture_view, Tegra::Texture::SwizzleSource x_source, | ||
| 96 | Tegra::Texture::SwizzleSource y_source, | ||
| 97 | Tegra::Texture::SwizzleSource z_source, | ||
| 98 | Tegra::Texture::SwizzleSource w_source); | ||
| 99 | |||
| 100 | TextureView CreateTextureView(GLenum target) const; | ||
| 101 | |||
| 102 | std::pair<std::reference_wrapper<TextureView>, GLenum> GetTextureView( | ||
| 103 | Tegra::Shader::TextureType texture_type, bool is_array); | ||
| 104 | |||
| 105 | CachedSurface& surface; | ||
| 106 | const ViewKey key; | ||
| 107 | const SurfaceParams params; | ||
| 108 | |||
| 109 | TextureView texture_view_1d; | ||
| 110 | TextureView texture_view_1d_array; | ||
| 111 | TextureView texture_view_2d; | ||
| 112 | TextureView texture_view_2d_array; | ||
| 113 | TextureView texture_view_3d; | ||
| 114 | TextureView texture_view_cube; | ||
| 115 | TextureView texture_view_cube_array; | ||
| 116 | }; | ||
| 117 | |||
| 118 | class TextureCacheOpenGL final : public TextureCacheBase { | ||
| 119 | public: | ||
| 120 | explicit TextureCacheOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer); | ||
| 121 | ~TextureCacheOpenGL(); | ||
| 122 | |||
| 123 | protected: | ||
| 124 | CachedSurfaceView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, | ||
| 125 | const SurfaceParams& params, bool preserve_contents, | ||
| 126 | const std::vector<CachedSurface*>& overlaps); | ||
| 127 | |||
| 128 | std::unique_ptr<CachedSurface> CreateSurface(const SurfaceParams& params); | ||
| 129 | }; | ||
| 130 | |||
| 131 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index aafd6f31b..710bf8303 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -460,6 +460,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum | |||
| 460 | switch (severity) { | 460 | switch (severity) { |
| 461 | case GL_DEBUG_SEVERITY_HIGH: | 461 | case GL_DEBUG_SEVERITY_HIGH: |
| 462 | LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message); | 462 | LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message); |
| 463 | __debugbreak(); | ||
| 463 | break; | 464 | break; |
| 464 | case GL_DEBUG_SEVERITY_MEDIUM: | 465 | case GL_DEBUG_SEVERITY_MEDIUM: |
| 465 | LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message); | 466 | LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message); |
diff --git a/src/video_core/texture_cache.cpp b/src/video_core/texture_cache.cpp index e96eba7cc..c42365a82 100644 --- a/src/video_core/texture_cache.cpp +++ b/src/video_core/texture_cache.cpp | |||
| @@ -163,7 +163,7 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const { | |||
| 163 | return block_height; | 163 | return block_height; |
| 164 | } | 164 | } |
| 165 | const u32 height{GetMipHeight(level)}; | 165 | const u32 height{GetMipHeight(level)}; |
| 166 | const u32 default_block_height{GetDefaultBlockHeight(pixel_format)}; | 166 | const u32 default_block_height{GetDefaultBlockHeight()}; |
| 167 | const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; | 167 | const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; |
| 168 | u32 block_height = 16; | 168 | u32 block_height = 16; |
| 169 | while (block_height > 1 && blocks_in_y <= block_height * 4) { | 169 | while (block_height > 1 && blocks_in_y <= block_height * 4) { |
| @@ -205,6 +205,10 @@ std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { | |||
| 205 | return offset; | 205 | return offset; |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { | ||
| 209 | return GetInnerMipmapMemorySize(level, true, true, false) * GetNumLayers(); | ||
| 210 | } | ||
| 211 | |||
| 208 | std::size_t SurfaceParams::GetGuestLayerSize() const { | 212 | std::size_t SurfaceParams::GetGuestLayerSize() const { |
| 209 | return GetInnerMemorySize(false, true, false); | 213 | return GetInnerMemorySize(false, true, false); |
| 210 | } | 214 | } |
| @@ -213,6 +217,22 @@ std::size_t SurfaceParams::GetHostLayerSize(u32 level) const { | |||
| 213 | return GetInnerMipmapMemorySize(level, true, IsLayered(), false); | 217 | return GetInnerMipmapMemorySize(level, true, IsLayered(), false); |
| 214 | } | 218 | } |
| 215 | 219 | ||
| 220 | u32 SurfaceParams::GetDefaultBlockWidth() const { | ||
| 221 | return VideoCore::Surface::GetDefaultBlockWidth(pixel_format); | ||
| 222 | } | ||
| 223 | |||
| 224 | u32 SurfaceParams::GetDefaultBlockHeight() const { | ||
| 225 | return VideoCore::Surface::GetDefaultBlockHeight(pixel_format); | ||
| 226 | } | ||
| 227 | |||
| 228 | u32 SurfaceParams::GetBitsPerPixel() const { | ||
| 229 | return VideoCore::Surface::GetFormatBpp(pixel_format); | ||
| 230 | } | ||
| 231 | |||
| 232 | u32 SurfaceParams::GetBytesPerPixel() const { | ||
| 233 | return VideoCore::Surface::GetBytesPerPixel(pixel_format); | ||
| 234 | } | ||
| 235 | |||
| 216 | bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const { | 236 | bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const { |
| 217 | if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) != | 237 | if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) != |
| 218 | std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format, | 238 | std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format, |
| @@ -257,7 +277,7 @@ void SurfaceParams::CalculateCachedValues() { | |||
| 257 | 277 | ||
| 258 | // ASTC is uncompressed in software, in emulated as RGBA8 | 278 | // ASTC is uncompressed in software, in emulated as RGBA8 |
| 259 | if (IsPixelFormatASTC(pixel_format)) { | 279 | if (IsPixelFormatASTC(pixel_format)) { |
| 260 | host_size_in_bytes = width * height * depth * 4; | 280 | host_size_in_bytes = static_cast<std::size_t>(width * height * depth) * 4ULL; |
| 261 | } else { | 281 | } else { |
| 262 | host_size_in_bytes = GetInnerMemorySize(true, false, false); | 282 | host_size_in_bytes = GetInnerMemorySize(true, false, false); |
| 263 | } | 283 | } |
| @@ -282,13 +302,11 @@ void SurfaceParams::CalculateCachedValues() { | |||
| 282 | std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only, | 302 | std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only, |
| 283 | bool uncompressed) const { | 303 | bool uncompressed) const { |
| 284 | const bool tiled{as_host_size ? false : is_tiled}; | 304 | const bool tiled{as_host_size ? false : is_tiled}; |
| 285 | const u32 tile_x{GetDefaultBlockWidth(pixel_format)}; | 305 | const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())}; |
| 286 | const u32 tile_y{GetDefaultBlockHeight(pixel_format)}; | 306 | const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())}; |
| 287 | const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), tile_x)}; | ||
| 288 | const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), tile_y)}; | ||
| 289 | const u32 depth{layer_only ? 1U : GetMipDepth(level)}; | 307 | const u32 depth{layer_only ? 1U : GetMipDepth(level)}; |
| 290 | return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(pixel_format), width, height, | 308 | return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth, |
| 291 | depth, GetMipBlockHeight(level), GetMipBlockDepth(level)); | 309 | GetMipBlockHeight(level), GetMipBlockDepth(level)); |
| 292 | } | 310 | } |
| 293 | 311 | ||
| 294 | std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, | 312 | std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, |
| @@ -297,7 +315,7 @@ std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only | |||
| 297 | for (u32 level = 0; level < num_levels; ++level) { | 315 | for (u32 level = 0; level < num_levels; ++level) { |
| 298 | size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed); | 316 | size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed); |
| 299 | } | 317 | } |
| 300 | if (!as_host_size && is_tiled) { | 318 | if (is_tiled && !as_host_size) { |
| 301 | size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); | 319 | size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); |
| 302 | } | 320 | } |
| 303 | return size; | 321 | return size; |
| @@ -309,6 +327,7 @@ std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const { | |||
| 309 | case SurfaceTarget::Texture1D: | 327 | case SurfaceTarget::Texture1D: |
| 310 | case SurfaceTarget::Texture2D: | 328 | case SurfaceTarget::Texture2D: |
| 311 | case SurfaceTarget::Texture3D: { | 329 | case SurfaceTarget::Texture3D: { |
| 330 | // TODO(Rodrigo): Add layer iterations for 3D textures | ||
| 312 | constexpr u32 layer = 0; | 331 | constexpr u32 layer = 0; |
| 313 | for (u32 level = 0; level < num_levels; ++level) { | 332 | for (u32 level = 0; level < num_levels; ++level) { |
| 314 | const std::size_t offset{GetGuestMipmapLevelOffset(level)}; | 333 | const std::size_t offset{GetGuestMipmapLevelOffset(level)}; |
diff --git a/src/video_core/texture_cache.h b/src/video_core/texture_cache.h index 041551691..9fd5f074e 100644 --- a/src/video_core/texture_cache.h +++ b/src/video_core/texture_cache.h | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include "video_core/engines/fermi_2d.h" | 20 | #include "video_core/engines/fermi_2d.h" |
| 21 | #include "video_core/engines/maxwell_3d.h" | 21 | #include "video_core/engines/maxwell_3d.h" |
| 22 | #include "video_core/gpu.h" | 22 | #include "video_core/gpu.h" |
| 23 | #include "video_core/memory_manager.h" | ||
| 23 | #include "video_core/rasterizer_interface.h" | 24 | #include "video_core/rasterizer_interface.h" |
| 24 | #include "video_core/surface.h" | 25 | #include "video_core/surface.h" |
| 25 | 26 | ||
| @@ -43,6 +44,10 @@ public: | |||
| 43 | 44 | ||
| 44 | bool operator==(const HasheableSurfaceParams& rhs) const; | 45 | bool operator==(const HasheableSurfaceParams& rhs) const; |
| 45 | 46 | ||
| 47 | bool operator!=(const HasheableSurfaceParams& rhs) const { | ||
| 48 | return !operator==(rhs); | ||
| 49 | } | ||
| 50 | |||
| 46 | protected: | 51 | protected: |
| 47 | // Avoid creation outside of a managed environment. | 52 | // Avoid creation outside of a managed environment. |
| 48 | HasheableSurfaceParams() = default; | 53 | HasheableSurfaceParams() = default; |
| @@ -167,12 +172,27 @@ public: | |||
| 167 | /// Returns the offset in bytes in host memory (linear) of a given mipmap level. | 172 | /// Returns the offset in bytes in host memory (linear) of a given mipmap level. |
| 168 | std::size_t GetHostMipmapLevelOffset(u32 level) const; | 173 | std::size_t GetHostMipmapLevelOffset(u32 level) const; |
| 169 | 174 | ||
| 175 | /// Returns the size in bytes in host memory (linear) of a given mipmap level. | ||
| 176 | std::size_t GetHostMipmapSize(u32 level) const; | ||
| 177 | |||
| 170 | /// Returns the size of a layer in bytes in guest memory. | 178 | /// Returns the size of a layer in bytes in guest memory. |
| 171 | std::size_t GetGuestLayerSize() const; | 179 | std::size_t GetGuestLayerSize() const; |
| 172 | 180 | ||
| 173 | /// Returns the size of a layer in bytes in host memory for a given mipmap level. | 181 | /// Returns the size of a layer in bytes in host memory for a given mipmap level. |
| 174 | std::size_t GetHostLayerSize(u32 level) const; | 182 | std::size_t GetHostLayerSize(u32 level) const; |
| 175 | 183 | ||
| 184 | /// Returns the default block width. | ||
| 185 | u32 GetDefaultBlockWidth() const; | ||
| 186 | |||
| 187 | /// Returns the default block height. | ||
| 188 | u32 GetDefaultBlockHeight() const; | ||
| 189 | |||
| 190 | /// Returns the bits per pixel. | ||
| 191 | u32 GetBitsPerPixel() const; | ||
| 192 | |||
| 193 | /// Returns the bytes per pixel. | ||
| 194 | u32 GetBytesPerPixel() const; | ||
| 195 | |||
| 176 | /// Returns true if another surface can be familiar with this. This is a loosely defined term | 196 | /// Returns true if another surface can be familiar with this. This is a loosely defined term |
| 177 | /// that reflects the possibility of these two surface parameters potentially being part of a | 197 | /// that reflects the possibility of these two surface parameters potentially being part of a |
| 178 | /// bigger superset. | 198 | /// bigger superset. |
| @@ -370,6 +390,7 @@ private: | |||
| 370 | template <typename TSurface, typename TView, typename TExecutionContext> | 390 | template <typename TSurface, typename TView, typename TExecutionContext> |
| 371 | class TextureCache { | 391 | class TextureCache { |
| 372 | static_assert(std::is_trivially_copyable_v<TExecutionContext>); | 392 | static_assert(std::is_trivially_copyable_v<TExecutionContext>); |
| 393 | |||
| 373 | using ResultType = std::tuple<TView*, TExecutionContext>; | 394 | using ResultType = std::tuple<TView*, TExecutionContext>; |
| 374 | using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<TSurface*>>; | 395 | using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<TSurface*>>; |
| 375 | using IntervalType = typename IntervalMap::interval_type; | 396 | using IntervalType = typename IntervalMap::interval_type; |
| @@ -583,4 +604,79 @@ private: | |||
| 583 | std::unordered_map<SurfaceParams, std::list<std::unique_ptr<TSurface>>> surface_reserve; | 604 | std::unordered_map<SurfaceParams, std::list<std::unique_ptr<TSurface>>> surface_reserve; |
| 584 | }; | 605 | }; |
| 585 | 606 | ||
| 607 | struct DummyExecutionContext {}; | ||
| 608 | |||
| 609 | template <typename TSurface, typename TView> | ||
| 610 | class TextureCacheContextless : protected TextureCache<TSurface, TView, DummyExecutionContext> { | ||
| 611 | using Base = TextureCache<TSurface, TView, DummyExecutionContext>; | ||
| 612 | |||
| 613 | public: | ||
| 614 | void InvalidateRegion(CacheAddr addr, std::size_t size) { | ||
| 615 | Base::InvalidateRegion(addr, size); | ||
| 616 | } | ||
| 617 | |||
| 618 | TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { | ||
| 619 | return RemoveContext(Base::GetTextureSurface({}, config)); | ||
| 620 | } | ||
| 621 | |||
| 622 | TView* GetDepthBufferSurface(bool preserve_contents) { | ||
| 623 | return RemoveContext(Base::GetDepthBufferSurface({}, preserve_contents)); | ||
| 624 | } | ||
| 625 | |||
| 626 | TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) { | ||
| 627 | return RemoveContext(Base::GetColorBufferSurface({}, index, preserve_contents)); | ||
| 628 | } | ||
| 629 | |||
| 630 | TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) { | ||
| 631 | return RemoveContext(Base::GetFermiSurface({}, config)); | ||
| 632 | } | ||
| 633 | |||
| 634 | TSurface* TryFindFramebufferSurface(const u8* host_ptr) const { | ||
| 635 | return Base::TryFindFramebufferSurface(host_ptr); | ||
| 636 | } | ||
| 637 | |||
| 638 | protected: | ||
| 639 | explicit TextureCacheContextless(Core::System& system, | ||
| 640 | VideoCore::RasterizerInterface& rasterizer) | ||
| 641 | : TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {} | ||
| 642 | |||
| 643 | virtual TView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, | ||
| 644 | bool preserve_contents, | ||
| 645 | const std::vector<TSurface*>& overlaps) = 0; | ||
| 646 | |||
| 647 | private: | ||
| 648 | std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView( | ||
| 649 | DummyExecutionContext, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, | ||
| 650 | bool preserve_contents, const std::vector<TSurface*>& overlaps) { | ||
| 651 | return {TryFastGetSurfaceView(cpu_addr, host_ptr, params, preserve_contents, overlaps), {}}; | ||
| 652 | } | ||
| 653 | |||
| 654 | TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) { | ||
| 655 | const auto [view, exctx] = return_value; | ||
| 656 | return view; | ||
| 657 | } | ||
| 658 | }; | ||
| 659 | |||
| 660 | template <typename TView> | ||
| 661 | class SurfaceBaseContextless : public SurfaceBase<TView, DummyExecutionContext> { | ||
| 662 | public: | ||
| 663 | DummyExecutionContext FlushBuffer(DummyExecutionContext) { | ||
| 664 | FlushBufferImpl(); | ||
| 665 | return {}; | ||
| 666 | } | ||
| 667 | |||
| 668 | DummyExecutionContext UploadTexture(DummyExecutionContext) { | ||
| 669 | UploadTextureImpl(); | ||
| 670 | return {}; | ||
| 671 | } | ||
| 672 | |||
| 673 | protected: | ||
| 674 | explicit SurfaceBaseContextless(const SurfaceParams& params) | ||
| 675 | : SurfaceBase<TView, DummyExecutionContext>{params} {} | ||
| 676 | |||
| 677 | virtual void FlushBufferImpl() = 0; | ||
| 678 | |||
| 679 | virtual void UploadTextureImpl() = 0; | ||
| 680 | }; | ||
| 681 | |||
| 586 | } // namespace VideoCommon | 682 | } // namespace VideoCommon |
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 217805386..664ed4b56 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -359,7 +359,8 @@ std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height | |||
| 359 | const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x); | 359 | const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x); |
| 360 | const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height); | 360 | const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height); |
| 361 | const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth); | 361 | const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth); |
| 362 | return aligned_width * aligned_height * aligned_depth; | 362 | const u32 size = aligned_width * aligned_height * aligned_depth; |
| 363 | return size; | ||
| 363 | } else { | 364 | } else { |
| 364 | return width * height * depth * bytes_per_pixel; | 365 | return width * height * depth * bytes_per_pixel; |
| 365 | } | 366 | } |