summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-04-11 17:14:55 -0300
committerGravatar ReinUsesLisp2019-06-20 21:36:11 -0300
commitbab21e8cb3df9c06e3c0a37a8fc68fed676f5d6e (patch)
tree860ce1a40373ff6002506bef72f78022de7d022c /src
parentMerge pull request #2596 from FernandoS27/revert-2590 (diff)
downloadyuzu-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.txt4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp66
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h4
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp514
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h131
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp1
-rw-r--r--src/video_core/texture_cache.cpp37
-rw-r--r--src/video_core/texture_cache.h96
-rw-r--r--src/video_core/textures/decoders.cpp3
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
101RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, 101RasterizerOpenGL::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
36namespace Core { 36namespace 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
15namespace OpenGL {
16
17using Tegra::Texture::ConvertFromGuestToHost;
18using Tegra::Texture::SwizzleSource;
19using VideoCore::MortonSwizzleMode;
20
21namespace {
22
23struct FormatTuple {
24 GLint internal_format;
25 GLenum format;
26 GLenum type;
27 ComponentType component_type;
28 bool compressed;
29};
30
31constexpr 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
121const 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
128GLenum 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
149GLint 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
169void 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
180OGLTexture 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
209void 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
237CachedSurface::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
248CachedSurface::~CachedSurface() = default;
249
250void 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
286void 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
338void CachedSurface::UploadTextureImpl() {
339 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
340 UploadTextureMipmap(level);
341 }
342}
343
344void 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
421std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) {
422 return std::make_unique<CachedSurfaceView>(*this, view_key);
423}
424
425CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, ViewKey key)
426 : surface{surface}, key{key}, params{surface.GetSurfaceParams()} {}
427
428CachedSurfaceView::~CachedSurfaceView() = default;
429
430GLuint 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
439GLuint 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
450void 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
464CachedSurfaceView::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
478std::pair<std::reference_wrapper<CachedSurfaceView::TextureView>, GLenum>
479CachedSurfaceView::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
498TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system,
499 VideoCore::RasterizerInterface& rasterizer)
500 : TextureCacheBase{system, rasterizer} {}
501
502TextureCacheOpenGL::~TextureCacheOpenGL() = default;
503
504CachedSurfaceView* 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
510std::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
18namespace OpenGL {
19
20using VideoCommon::SurfaceParams;
21using VideoCommon::ViewKey;
22using VideoCore::Surface::ComponentType;
23using VideoCore::Surface::PixelFormat;
24using VideoCore::Surface::SurfaceTarget;
25using VideoCore::Surface::SurfaceType;
26
27class CachedSurfaceView;
28class CachedSurface;
29
30using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>;
31
32class CachedSurface final : public VideoCommon::SurfaceBaseContextless<CachedSurfaceView> {
33 friend CachedSurfaceView;
34
35public:
36 explicit CachedSurface(const SurfaceParams& params);
37 ~CachedSurface();
38
39 void LoadBuffer();
40
41 GLuint GetTexture() const {
42 return texture.handle;
43 }
44
45protected:
46 std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key);
47
48 void FlushBufferImpl();
49
50 void UploadTextureImpl();
51
52private:
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
66class CachedSurfaceView final {
67public:
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
87private:
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
118class TextureCacheOpenGL final : public TextureCacheBase {
119public:
120 explicit TextureCacheOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
121 ~TextureCacheOpenGL();
122
123protected:
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
208std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const {
209 return GetInnerMipmapMemorySize(level, true, true, false) * GetNumLayers();
210}
211
208std::size_t SurfaceParams::GetGuestLayerSize() const { 212std::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
220u32 SurfaceParams::GetDefaultBlockWidth() const {
221 return VideoCore::Surface::GetDefaultBlockWidth(pixel_format);
222}
223
224u32 SurfaceParams::GetDefaultBlockHeight() const {
225 return VideoCore::Surface::GetDefaultBlockHeight(pixel_format);
226}
227
228u32 SurfaceParams::GetBitsPerPixel() const {
229 return VideoCore::Surface::GetFormatBpp(pixel_format);
230}
231
232u32 SurfaceParams::GetBytesPerPixel() const {
233 return VideoCore::Surface::GetBytesPerPixel(pixel_format);
234}
235
216bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const { 236bool 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() {
282std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only, 302std::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
294std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, 312std::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
46protected: 51protected:
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:
370template <typename TSurface, typename TView, typename TExecutionContext> 390template <typename TSurface, typename TView, typename TExecutionContext>
371class TextureCache { 391class 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
607struct DummyExecutionContext {};
608
609template <typename TSurface, typename TView>
610class TextureCacheContextless : protected TextureCache<TSurface, TView, DummyExecutionContext> {
611 using Base = TextureCache<TSurface, TView, DummyExecutionContext>;
612
613public:
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
638protected:
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
647private:
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
660template <typename TView>
661class SurfaceBaseContextless : public SurfaceBase<TView, DummyExecutionContext> {
662public:
663 DummyExecutionContext FlushBuffer(DummyExecutionContext) {
664 FlushBufferImpl();
665 return {};
666 }
667
668 DummyExecutionContext UploadTexture(DummyExecutionContext) {
669 UploadTextureImpl();
670 return {};
671 }
672
673protected:
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 }