mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	gl_texture_cache: Initial implementation
This commit is contained in:
		
							parent
							
								
									80a8456af8
								
							
						
					
					
						commit
						bab21e8cb3
					
				| @ -45,8 +45,6 @@ add_library(video_core STATIC | ||||
|     renderer_opengl/gl_global_cache.h | ||||
|     renderer_opengl/gl_rasterizer.cpp | ||||
|     renderer_opengl/gl_rasterizer.h | ||||
|     renderer_opengl/gl_rasterizer_cache.cpp | ||||
|     renderer_opengl/gl_rasterizer_cache.h | ||||
|     renderer_opengl/gl_resource_manager.cpp | ||||
|     renderer_opengl/gl_resource_manager.h | ||||
|     renderer_opengl/gl_sampler_cache.cpp | ||||
| @ -67,6 +65,8 @@ add_library(video_core STATIC | ||||
|     renderer_opengl/gl_state.h | ||||
|     renderer_opengl/gl_stream_buffer.cpp | ||||
|     renderer_opengl/gl_stream_buffer.h | ||||
|     renderer_opengl/gl_texture_cache.cpp | ||||
|     renderer_opengl/gl_texture_cache.h | ||||
|     renderer_opengl/maxwell_to_gl.h | ||||
|     renderer_opengl/renderer_opengl.cpp | ||||
|     renderer_opengl/renderer_opengl.h | ||||
|  | ||||
| @ -100,7 +100,7 @@ struct FramebufferCacheKey { | ||||
| 
 | ||||
| RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, | ||||
|                                    ScreenInfo& info) | ||||
|     : res_cache{*this}, shader_cache{*this, system, emu_window, device}, | ||||
|     : texture_cache{system, *this}, shader_cache{*this, system, emu_window, device}, | ||||
|       global_cache{*this}, system{system}, screen_info{info}, | ||||
|       buffer_cache(*this, STREAM_BUFFER_SIZE) { | ||||
|     OpenGLState::ApplyDefaultState(); | ||||
| @ -478,9 +478,9 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | ||||
|     } | ||||
|     current_framebuffer_config_state = fb_config_state; | ||||
| 
 | ||||
|     Surface depth_surface; | ||||
|     CachedSurfaceView* depth_surface{}; | ||||
|     if (using_depth_fb) { | ||||
|         depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); | ||||
|         depth_surface = texture_cache.GetDepthBufferSurface(preserve_contents); | ||||
|     } | ||||
| 
 | ||||
|     UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0); | ||||
| @ -493,42 +493,43 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | ||||
|     if (using_color_fb) { | ||||
|         if (single_color_target) { | ||||
|             // Used when just a single color attachment is enabled, e.g. for clearing a color buffer
 | ||||
|             Surface color_surface = | ||||
|                 res_cache.GetColorBufferSurface(*single_color_target, preserve_contents); | ||||
|             CachedSurfaceView* color_surface{ | ||||
|                 texture_cache.GetColorBufferSurface(*single_color_target, preserve_contents)}; | ||||
| 
 | ||||
|             if (color_surface) { | ||||
|                 // Assume that a surface will be written to if it is used as a framebuffer, even if
 | ||||
|                 // the shader doesn't actually write to it.
 | ||||
|                 color_surface->MarkAsModified(true, res_cache); | ||||
|                 color_surface->MarkAsModified(true); | ||||
|                 // Workaround for and issue in nvidia drivers
 | ||||
|                 // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
 | ||||
|                 state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion; | ||||
|                 // state.framebuffer_srgb.enabled |=
 | ||||
|                 // color_surface->GetSurfaceParams().srgb_conversion;
 | ||||
|             } | ||||
| 
 | ||||
|             fbkey.is_single_buffer = true; | ||||
|             fbkey.color_attachments[0] = | ||||
|                 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target); | ||||
|             fbkey.colors[0] = color_surface != nullptr ? color_surface->Texture().handle : 0; | ||||
|             fbkey.colors[0] = color_surface != nullptr ? color_surface->GetTexture() : 0; | ||||
|         } else { | ||||
|             // Multiple color attachments are enabled
 | ||||
|             for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||||
|                 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); | ||||
|                 CachedSurfaceView* color_surface{ | ||||
|                     texture_cache.GetColorBufferSurface(index, preserve_contents)}; | ||||
| 
 | ||||
|                 if (color_surface) { | ||||
|                     // Assume that a surface will be written to if it is used as a framebuffer, even
 | ||||
|                     // if the shader doesn't actually write to it.
 | ||||
|                     color_surface->MarkAsModified(true, res_cache); | ||||
|                     color_surface->MarkAsModified(true); | ||||
|                     // Enable sRGB only for supported formats
 | ||||
|                     // Workaround for and issue in nvidia drivers
 | ||||
|                     // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
 | ||||
|                     state.framebuffer_srgb.enabled |= | ||||
|                         color_surface->GetSurfaceParams().srgb_conversion; | ||||
|                     // state.framebuffer_srgb.enabled |=
 | ||||
|                     //     color_surface->GetSurfaceParams().srgb_conversion;
 | ||||
|                 } | ||||
| 
 | ||||
|                 fbkey.color_attachments[index] = | ||||
|                     GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); | ||||
|                 fbkey.colors[index] = | ||||
|                     color_surface != nullptr ? color_surface->Texture().handle : 0; | ||||
|                 fbkey.colors[index] = color_surface != nullptr ? color_surface->GetTexture() : 0; | ||||
|             } | ||||
|             fbkey.is_single_buffer = false; | ||||
|             fbkey.colors_count = regs.rt_control.count; | ||||
| @ -541,11 +542,11 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( | ||||
|     if (depth_surface) { | ||||
|         // Assume that a surface will be written to if it is used as a framebuffer, even if
 | ||||
|         // the shader doesn't actually write to it.
 | ||||
|         depth_surface->MarkAsModified(true, res_cache); | ||||
|         depth_surface->MarkAsModified(true); | ||||
| 
 | ||||
|         fbkey.zeta = depth_surface->Texture().handle; | ||||
|         fbkey.stencil_enable = regs.stencil_enable && | ||||
|                                depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil; | ||||
|         fbkey.zeta = depth_surface->GetTexture(); | ||||
|         fbkey.stencil_enable = regs.stencil_enable && depth_surface->GetSurfaceParams().GetType() == | ||||
|                                                           SurfaceType::DepthStencil; | ||||
|     } | ||||
| 
 | ||||
|     SetupCachedFramebuffer(fbkey, current_state); | ||||
| @ -704,9 +705,7 @@ void RasterizerOpenGL::DrawArrays() { | ||||
|     shader_program_manager->ApplyTo(state); | ||||
|     state.Apply(); | ||||
| 
 | ||||
|     res_cache.SignalPreDrawCall(); | ||||
|     params.DispatchDraw(); | ||||
|     res_cache.SignalPostDrawCall(); | ||||
| 
 | ||||
|     accelerate_draw = AccelDraw::Disabled; | ||||
| } | ||||
| @ -718,7 +717,7 @@ void RasterizerOpenGL::FlushRegion(CacheAddr addr, u64 size) { | ||||
|     if (!addr || !size) { | ||||
|         return; | ||||
|     } | ||||
|     res_cache.FlushRegion(addr, size); | ||||
|     // texture_cache.FlushRegion(addr, size);
 | ||||
|     global_cache.FlushRegion(addr, size); | ||||
| } | ||||
| 
 | ||||
| @ -727,7 +726,7 @@ void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) { | ||||
|     if (!addr || !size) { | ||||
|         return; | ||||
|     } | ||||
|     res_cache.InvalidateRegion(addr, size); | ||||
|     texture_cache.InvalidateRegion(addr, size); | ||||
|     shader_cache.InvalidateRegion(addr, size); | ||||
|     global_cache.InvalidateRegion(addr, size); | ||||
|     buffer_cache.InvalidateRegion(addr, size); | ||||
| @ -743,7 +742,8 @@ bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs | ||||
|                                              const Common::Rectangle<u32>& src_rect, | ||||
|                                              const Common::Rectangle<u32>& dst_rect) { | ||||
|     MICROPROFILE_SCOPE(OpenGL_Blits); | ||||
|     res_cache.FermiCopySurface(src, dst, src_rect, dst_rect); | ||||
|     UNIMPLEMENTED(); | ||||
|     // texture_cache.FermiCopySurface(src, dst, src_rect, dst_rect);
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| @ -755,7 +755,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
| 
 | ||||
|     MICROPROFILE_SCOPE(OpenGL_CacheManagement); | ||||
| 
 | ||||
|     const auto& surface{res_cache.TryFindFramebufferSurface(Memory::GetPointer(framebuffer_addr))}; | ||||
|     const auto surface{ | ||||
|         texture_cache.TryFindFramebufferSurface(Memory::GetPointer(framebuffer_addr))}; | ||||
|     if (!surface) { | ||||
|         return {}; | ||||
|     } | ||||
| @ -764,14 +765,14 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||||
|     const auto& params{surface->GetSurfaceParams()}; | ||||
|     const auto& pixel_format{ | ||||
|         VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)}; | ||||
|     ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); | ||||
|     ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); | ||||
|     ASSERT_MSG(params.GetWidth() == config.width, "Framebuffer width is different"); | ||||
|     ASSERT_MSG(params.GetHeight() == config.height, "Framebuffer height is different"); | ||||
| 
 | ||||
|     if (params.pixel_format != pixel_format) { | ||||
|     if (params.GetPixelFormat() != pixel_format) { | ||||
|         LOG_WARNING(Render_OpenGL, "Framebuffer pixel_format is different"); | ||||
|     } | ||||
| 
 | ||||
|     screen_info.display_texture = surface->Texture().handle; | ||||
|     screen_info.display_texture = surface->GetTexture(); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| @ -862,11 +863,10 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s | ||||
| 
 | ||||
|         state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc); | ||||
| 
 | ||||
|         if (Surface surface = res_cache.GetTextureSurface(texture, entry); surface) { | ||||
|             state.texture_units[current_bindpoint].texture = | ||||
|                 surface->Texture(entry.IsArray()).handle; | ||||
|             surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, | ||||
|                                    texture.tic.w_source); | ||||
|         if (const auto surface{texture_cache.GetTextureSurface(texture)}; surface) { | ||||
|             state.texture_units[current_bindpoint].texture = surface->GetTexture( | ||||
|                 entry.GetType(), entry.IsArray(), texture.tic.x_source, texture.tic.y_source, | ||||
|                 texture.tic.z_source, texture.tic.w_source); | ||||
|         } else { | ||||
|             // Can occur when texture addr is null or its memory is unmapped/invalid
 | ||||
|             state.texture_units[current_bindpoint].texture = 0; | ||||
|  | ||||
| @ -24,13 +24,13 @@ | ||||
| #include "video_core/renderer_opengl/gl_buffer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_device.h" | ||||
| #include "video_core/renderer_opengl/gl_global_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_sampler_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_decompiler.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
| #include "video_core/renderer_opengl/gl_texture_cache.h" | ||||
| #include "video_core/renderer_opengl/utils.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| @ -181,7 +181,7 @@ private: | ||||
|     const Device device; | ||||
|     OpenGLState state; | ||||
| 
 | ||||
|     RasterizerCacheOpenGL res_cache; | ||||
|     TextureCacheOpenGL texture_cache; | ||||
|     ShaderCacheOpenGL shader_cache; | ||||
|     GlobalRegionCacheOpenGL global_cache; | ||||
|     SamplerCacheOpenGL sampler_cache; | ||||
|  | ||||
							
								
								
									
										514
									
								
								src/video_core/renderer_opengl/gl_texture_cache.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										514
									
								
								src/video_core/renderer_opengl/gl_texture_cache.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,514 @@ | ||||
| // Copyright 2019 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/scope_exit.h" | ||||
| #include "video_core/morton.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_texture_cache.h" | ||||
| #include "video_core/texture_cache.h" | ||||
| #include "video_core/textures/convert.h" | ||||
| #include "video_core/textures/texture.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| using Tegra::Texture::ConvertFromGuestToHost; | ||||
| using Tegra::Texture::SwizzleSource; | ||||
| using VideoCore::MortonSwizzleMode; | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| struct FormatTuple { | ||||
|     GLint internal_format; | ||||
|     GLenum format; | ||||
|     GLenum type; | ||||
|     ComponentType component_type; | ||||
|     bool compressed; | ||||
| }; | ||||
| 
 | ||||
| constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
 | ||||
|     {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false},                     // ABGR8S
 | ||||
|     {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false},   // ABGR8UI
 | ||||
|     {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U
 | ||||
|     {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm, | ||||
|      false}, // A2B10G10R10U
 | ||||
|     {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U
 | ||||
|     {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},                    // R8U
 | ||||
|     {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false},           // R8UI
 | ||||
|     {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false},                 // RGBA16F
 | ||||
|     {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, ComponentType::UNorm, false},              // RGBA16U
 | ||||
|     {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false},     // RGBA16UI
 | ||||
|     {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, | ||||
|      false},                                                                     // R11FG11FB10F
 | ||||
|     {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI
 | ||||
|     {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true}, // DXT1
 | ||||
|     {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true}, // DXT23
 | ||||
|     {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true},                                                                                 // DXT45
 | ||||
|     {GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXN1
 | ||||
|     {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true},                                                                     // DXN2UNORM
 | ||||
|     {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
 | ||||
|     {GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true}, // BC7U
 | ||||
|     {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, | ||||
|      true}, // BC6H_UF16
 | ||||
|     {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, | ||||
|      true},                                                                    // BC6H_SF16
 | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},        // ASTC_2D_4X4
 | ||||
|     {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},        // BGRA8
 | ||||
|     {GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false},              // RGBA32F
 | ||||
|     {GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false},                  // RG32F
 | ||||
|     {GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false},                  // R32F
 | ||||
|     {GL_R16F, GL_RED, GL_HALF_FLOAT, ComponentType::Float, false},             // R16F
 | ||||
|     {GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false},          // R16U
 | ||||
|     {GL_R16_SNORM, GL_RED, GL_SHORT, ComponentType::SNorm, false},             // R16S
 | ||||
|     {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // R16UI
 | ||||
|     {GL_R16I, GL_RED_INTEGER, GL_SHORT, ComponentType::SInt, false},           // R16I
 | ||||
|     {GL_RG16, GL_RG, GL_UNSIGNED_SHORT, ComponentType::UNorm, false},          // RG16
 | ||||
|     {GL_RG16F, GL_RG, GL_HALF_FLOAT, ComponentType::Float, false},             // RG16F
 | ||||
|     {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RG16UI
 | ||||
|     {GL_RG16I, GL_RG_INTEGER, GL_SHORT, ComponentType::SInt, false},           // RG16I
 | ||||
|     {GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false},             // RG16S
 | ||||
|     {GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false},                // RGB32F
 | ||||
|     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, | ||||
|      false},                                                                   // RGBA8_SRGB
 | ||||
|     {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},            // RG8U
 | ||||
|     {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false},                     // RG8S
 | ||||
|     {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false},   // RG32UI
 | ||||
|     {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false},   // R32UI
 | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},        // ASTC_2D_8X8
 | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},        // ASTC_2D_8X5
 | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},        // ASTC_2D_5X4
 | ||||
|     {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8
 | ||||
|     // Compressed sRGB formats
 | ||||
|     {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true}, // DXT1_SRGB
 | ||||
|     {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true}, // DXT23_SRGB
 | ||||
|     {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true}, // DXT45_SRGB
 | ||||
|     {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||||
|      true},                                                                    // BC7U_SRGB
 | ||||
|     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB
 | ||||
|     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
 | ||||
|     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
 | ||||
|     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB
 | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},        // ASTC_2D_5X5
 | ||||
|     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB
 | ||||
|     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false},        // ASTC_2D_10X8
 | ||||
|     {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB
 | ||||
| 
 | ||||
|     // Depth formats
 | ||||
|     {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
 | ||||
|     {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, ComponentType::UNorm, | ||||
|      false}, // Z16
 | ||||
| 
 | ||||
|     // DepthStencil formats
 | ||||
|     {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, | ||||
|      false}, // Z24S8
 | ||||
|     {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, | ||||
|      false}, // S8Z24
 | ||||
|     {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, | ||||
|      ComponentType::Float, false}, // Z32FS8
 | ||||
| }}; | ||||
| 
 | ||||
| const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { | ||||
|     ASSERT(static_cast<std::size_t>(pixel_format) < tex_format_tuples.size()); | ||||
|     const auto& format{tex_format_tuples[static_cast<std::size_t>(pixel_format)]}; | ||||
|     ASSERT(component_type == format.component_type); | ||||
|     return format; | ||||
| } | ||||
| 
 | ||||
| GLenum GetTextureTarget(const SurfaceParams& params) { | ||||
|     switch (params.GetTarget()) { | ||||
|     case SurfaceTarget::Texture1D: | ||||
|         return GL_TEXTURE_1D; | ||||
|     case SurfaceTarget::Texture2D: | ||||
|         return GL_TEXTURE_2D; | ||||
|     case SurfaceTarget::Texture3D: | ||||
|         return GL_TEXTURE_3D; | ||||
|     case SurfaceTarget::Texture1DArray: | ||||
|         return GL_TEXTURE_1D_ARRAY; | ||||
|     case SurfaceTarget::Texture2DArray: | ||||
|         return GL_TEXTURE_2D_ARRAY; | ||||
|     case SurfaceTarget::TextureCubemap: | ||||
|         return GL_TEXTURE_CUBE_MAP; | ||||
|     case SurfaceTarget::TextureCubeArray: | ||||
|         return GL_TEXTURE_CUBE_MAP_ARRAY; | ||||
|     } | ||||
|     UNREACHABLE(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| GLint GetSwizzleSource(SwizzleSource source) { | ||||
|     switch (source) { | ||||
|     case SwizzleSource::Zero: | ||||
|         return GL_ZERO; | ||||
|     case SwizzleSource::R: | ||||
|         return GL_RED; | ||||
|     case SwizzleSource::G: | ||||
|         return GL_GREEN; | ||||
|     case SwizzleSource::B: | ||||
|         return GL_BLUE; | ||||
|     case SwizzleSource::A: | ||||
|         return GL_ALPHA; | ||||
|     case SwizzleSource::OneInt: | ||||
|     case SwizzleSource::OneFloat: | ||||
|         return GL_ONE; | ||||
|     } | ||||
|     UNREACHABLE(); | ||||
|     return GL_NONE; | ||||
| } | ||||
| 
 | ||||
| void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { | ||||
|     glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||
|     glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||
|     glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|     glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|     glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, params.GetNumLevels() - 1); | ||||
|     if (params.GetNumLevels() == 1) { | ||||
|         glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| OGLTexture CreateTexture(const SurfaceParams& params, GLenum internal_format) { | ||||
|     OGLTexture texture; | ||||
|     texture.Create(GetTextureTarget(params)); | ||||
| 
 | ||||
|     switch (params.GetTarget()) { | ||||
|     case SurfaceTarget::Texture1D: | ||||
|         glTextureStorage1D(texture.handle, params.GetNumLevels(), internal_format, | ||||
|                            params.GetWidth()); | ||||
|         break; | ||||
|     case SurfaceTarget::Texture2D: | ||||
|     case SurfaceTarget::TextureCubemap: | ||||
|         glTextureStorage2D(texture.handle, params.GetNumLevels(), internal_format, | ||||
|                            params.GetWidth(), params.GetHeight()); | ||||
|         break; | ||||
|     case SurfaceTarget::Texture3D: | ||||
|     case SurfaceTarget::Texture2DArray: | ||||
|     case SurfaceTarget::TextureCubeArray: | ||||
|         glTextureStorage3D(texture.handle, params.GetNumLevels(), internal_format, | ||||
|                            params.GetWidth(), params.GetHeight(), params.GetDepth()); | ||||
|         break; | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     ApplyTextureDefaults(params, texture.handle); | ||||
| 
 | ||||
|     return texture; | ||||
| } | ||||
| 
 | ||||
| void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer, | ||||
|                  u32 level) { | ||||
|     const u32 width{params.GetMipWidth(level)}; | ||||
|     const u32 height{params.GetMipHeight(level)}; | ||||
|     const u32 block_height{params.GetMipBlockHeight(level)}; | ||||
|     const u32 block_depth{params.GetMipBlockDepth(level)}; | ||||
| 
 | ||||
|     std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)}; | ||||
|     if (params.IsLayered()) { | ||||
|         std::size_t host_offset{0}; | ||||
|         const std::size_t guest_stride = params.GetGuestLayerSize(); | ||||
|         const std::size_t host_stride = params.GetHostLayerSize(level); | ||||
|         for (u32 layer = 0; layer < params.GetNumLayers(); layer++) { | ||||
|             MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth, | ||||
|                           1, params.GetTileWidthSpacing(), buffer + host_offset, | ||||
|                           memory + guest_offset); | ||||
|             guest_offset += guest_stride; | ||||
|             host_offset += host_stride; | ||||
|         } | ||||
|     } else { | ||||
|         MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth, | ||||
|                       params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer, | ||||
|                       memory + guest_offset); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| CachedSurface::CachedSurface(const SurfaceParams& params) | ||||
|     : VideoCommon::SurfaceBaseContextless<CachedSurfaceView>{params} { | ||||
|     const auto& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())}; | ||||
|     internal_format = tuple.internal_format; | ||||
|     format = tuple.format; | ||||
|     type = tuple.type; | ||||
|     is_compressed = tuple.compressed; | ||||
|     texture = CreateTexture(params, internal_format); | ||||
|     staging_buffer.resize(params.GetHostSizeInBytes()); | ||||
| } | ||||
| 
 | ||||
| CachedSurface::~CachedSurface() = default; | ||||
| 
 | ||||
| void CachedSurface::LoadBuffer() { | ||||
|     if (params.IsTiled()) { | ||||
|         ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}", | ||||
|                    params.GetBlockWidth(), static_cast<u32>(params.GetTarget())); | ||||
|         for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||||
|             u8* const buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)}; | ||||
|             SwizzleFunc(MortonSwizzleMode::MortonToLinear, GetHostPtr(), params, buffer, level); | ||||
|         } | ||||
|     } else { | ||||
|         ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented"); | ||||
|         const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT}; | ||||
|         const u32 block_width{VideoCore::Surface::GetDefaultBlockWidth(params.GetPixelFormat())}; | ||||
|         const u32 block_height{VideoCore::Surface::GetDefaultBlockHeight(params.GetPixelFormat())}; | ||||
|         const u32 width{(params.GetWidth() + block_width - 1) / block_width}; | ||||
|         const u32 height{(params.GetHeight() + block_height - 1) / block_height}; | ||||
|         const u32 copy_size{width * bpp}; | ||||
|         if (params.GetPitch() == copy_size) { | ||||
|             std::memcpy(staging_buffer.data(), GetHostPtr(), params.GetHostSizeInBytes()); | ||||
|         } else { | ||||
|             const u8* start{GetHostPtr()}; | ||||
|             u8* write_to{staging_buffer.data()}; | ||||
|             for (u32 h = height; h > 0; --h) { | ||||
|                 std::memcpy(write_to, start, copy_size); | ||||
|                 start += params.GetPitch(); | ||||
|                 write_to += copy_size; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||||
|         ConvertFromGuestToHost(staging_buffer.data() + params.GetHostMipmapLevelOffset(level), | ||||
|                                params.GetPixelFormat(), params.GetMipWidth(level), | ||||
|                                params.GetMipHeight(level), params.GetMipDepth(level), true, true); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CachedSurface::FlushBufferImpl() { | ||||
|     if (!IsModified()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // TODO(Rodrigo): Optimize alignment
 | ||||
|     glPixelStorei(GL_PACK_ALIGNMENT, 1); | ||||
|     SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); | ||||
| 
 | ||||
|     for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||||
|         glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); | ||||
|         if (is_compressed) { | ||||
|             glGetCompressedTextureImage( | ||||
|                 texture.handle, level, static_cast<GLsizei>(params.GetHostMipmapSize(level)), | ||||
|                 staging_buffer.data() + params.GetHostMipmapLevelOffset(level)); | ||||
|         } else { | ||||
|             glGetTextureImage(texture.handle, level, format, type, | ||||
|                               static_cast<GLsizei>(params.GetHostMipmapSize(level)), | ||||
|                               staging_buffer.data() + params.GetHostMipmapLevelOffset(level)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (params.IsTiled()) { | ||||
|         ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}", | ||||
|                    params.GetBlockWidth()); | ||||
|         for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||||
|             u8* const buffer = staging_buffer.data() + params.GetHostMipmapLevelOffset(level); | ||||
|             SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level); | ||||
|         } | ||||
|     } else { | ||||
|         UNIMPLEMENTED(); | ||||
|         /*
 | ||||
|         ASSERT(params.GetTarget() == SurfaceTarget::Texture2D); | ||||
|         ASSERT(params.GetNumLevels() == 1); | ||||
| 
 | ||||
|         const u32 bpp{params.GetFormatBpp() / 8}; | ||||
|         const u32 copy_size{params.GetWidth() * bpp}; | ||||
|         if (params.GetPitch() == copy_size) { | ||||
|             std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes()); | ||||
|         } else { | ||||
|             u8* start{host_ptr}; | ||||
|             const u8* read_to{staging_buffer.data()}; | ||||
|             for (u32 h = params.GetHeight(); h > 0; --h) { | ||||
|                 std::memcpy(start, read_to, copy_size); | ||||
|                 start += params.GetPitch(); | ||||
|                 read_to += copy_size; | ||||
|             } | ||||
|         } | ||||
|         */ | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CachedSurface::UploadTextureImpl() { | ||||
|     for (u32 level = 0; level < params.GetNumLevels(); ++level) { | ||||
|         UploadTextureMipmap(level); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CachedSurface::UploadTextureMipmap(u32 level) { | ||||
|     u8* buffer{staging_buffer.data() + params.GetHostMipmapLevelOffset(level)}; | ||||
| 
 | ||||
|     // TODO(Rodrigo): Optimize alignment
 | ||||
|     glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||||
|     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); | ||||
|     SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); }); | ||||
| 
 | ||||
|     if (is_compressed) { | ||||
|         const auto image_size{static_cast<GLsizei>(params.GetHostMipmapSize(level))}; | ||||
|         GLint expected_size; | ||||
|         glGetTextureLevelParameteriv(texture.handle, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, | ||||
|                                      &expected_size); | ||||
|         switch (params.GetTarget()) { | ||||
|         case SurfaceTarget::Texture2D: | ||||
|             glCompressedTextureSubImage2D(texture.handle, level, 0, 0, | ||||
|                                           static_cast<GLsizei>(params.GetMipWidth(level)), | ||||
|                                           static_cast<GLsizei>(params.GetMipHeight(level)), | ||||
|                                           internal_format, image_size, buffer); | ||||
|             break; | ||||
|         case SurfaceTarget::Texture3D: | ||||
|         case SurfaceTarget::Texture2DArray: | ||||
|         case SurfaceTarget::TextureCubeArray: | ||||
|             glCompressedTextureSubImage3D(texture.handle, level, 0, 0, 0, | ||||
|                                           static_cast<GLsizei>(params.GetMipWidth(level)), | ||||
|                                           static_cast<GLsizei>(params.GetMipHeight(level)), | ||||
|                                           static_cast<GLsizei>(params.GetMipDepth(level)), | ||||
|                                           internal_format, image_size, buffer); | ||||
|             break; | ||||
|         case SurfaceTarget::TextureCubemap: { | ||||
|             const std::size_t layer_size{params.GetHostLayerSize(level)}; | ||||
|             for (std::size_t face = 0; face < params.GetDepth(); ++face) { | ||||
|                 glCompressedTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face), | ||||
|                                               static_cast<GLsizei>(params.GetMipWidth(level)), | ||||
|                                               static_cast<GLsizei>(params.GetMipHeight(level)), 1, | ||||
|                                               internal_format, static_cast<GLsizei>(layer_size), | ||||
|                                               buffer); | ||||
|                 buffer += layer_size; | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             UNREACHABLE(); | ||||
|         } | ||||
|     } else { | ||||
|         switch (params.GetTarget()) { | ||||
|         case SurfaceTarget::Texture1D: | ||||
|             glTextureSubImage1D(texture.handle, level, 0, params.GetMipWidth(level), format, type, | ||||
|                                 buffer); | ||||
|             break; | ||||
|         case SurfaceTarget::Texture1DArray: | ||||
|         case SurfaceTarget::Texture2D: | ||||
|             glTextureSubImage2D(texture.handle, level, 0, 0, params.GetMipWidth(level), | ||||
|                                 params.GetMipHeight(level), format, type, buffer); | ||||
|             break; | ||||
|         case SurfaceTarget::Texture3D: | ||||
|         case SurfaceTarget::Texture2DArray: | ||||
|         case SurfaceTarget::TextureCubeArray: | ||||
|             glTextureSubImage3D( | ||||
|                 texture.handle, level, 0, 0, 0, static_cast<GLsizei>(params.GetMipWidth(level)), | ||||
|                 static_cast<GLsizei>(params.GetMipHeight(level)), | ||||
|                 static_cast<GLsizei>(params.GetMipDepth(level)), format, type, buffer); | ||||
|             break; | ||||
|         case SurfaceTarget::TextureCubemap: | ||||
|             for (std::size_t face = 0; face < params.GetDepth(); ++face) { | ||||
|                 glTextureSubImage3D(texture.handle, level, 0, 0, static_cast<GLint>(face), | ||||
|                                     params.GetMipWidth(level), params.GetMipHeight(level), 1, | ||||
|                                     format, type, buffer); | ||||
|                 buffer += params.GetHostLayerSize(level); | ||||
|             } | ||||
|             break; | ||||
|         default: | ||||
|             UNREACHABLE(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<CachedSurfaceView> CachedSurface::CreateView(const ViewKey& view_key) { | ||||
|     return std::make_unique<CachedSurfaceView>(*this, view_key); | ||||
| } | ||||
| 
 | ||||
| CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, ViewKey key) | ||||
|     : surface{surface}, key{key}, params{surface.GetSurfaceParams()} {} | ||||
| 
 | ||||
| CachedSurfaceView::~CachedSurfaceView() = default; | ||||
| 
 | ||||
| GLuint CachedSurfaceView::GetTexture() { | ||||
|     // TODO(Rodrigo): Remove this entry and attach the super texture to the framebuffer through
 | ||||
|     // legacy API (also dropping Intel driver issues).
 | ||||
|     if (texture_view_2d.texture.handle == 0) { | ||||
|         texture_view_2d = CreateTextureView(GL_TEXTURE_2D); | ||||
|     } | ||||
|     return texture_view_2d.texture.handle; | ||||
| } | ||||
| 
 | ||||
| GLuint CachedSurfaceView::GetTexture(Tegra::Shader::TextureType texture_type, bool is_array, | ||||
|                                      SwizzleSource x_source, SwizzleSource y_source, | ||||
|                                      SwizzleSource z_source, SwizzleSource w_source) { | ||||
|     const auto [texture_view, target] = GetTextureView(texture_type, is_array); | ||||
|     if (texture_view.get().texture.handle == 0) { | ||||
|         texture_view.get() = std::move(CreateTextureView(target)); | ||||
|     } | ||||
|     ApplySwizzle(texture_view, x_source, y_source, z_source, w_source); | ||||
|     return texture_view.get().texture.handle; | ||||
| } | ||||
| 
 | ||||
| void CachedSurfaceView::ApplySwizzle(TextureView& texture_view, SwizzleSource x_source, | ||||
|                                      SwizzleSource y_source, SwizzleSource z_source, | ||||
|                                      SwizzleSource w_source) { | ||||
|     const std::array<SwizzleSource, 4> swizzle = {x_source, y_source, z_source, w_source}; | ||||
|     if (swizzle == texture_view.swizzle) { | ||||
|         return; | ||||
|     } | ||||
|     const std::array<GLint, 4> gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source), | ||||
|                                              GetSwizzleSource(z_source), | ||||
|                                              GetSwizzleSource(w_source)}; | ||||
|     glTextureParameteriv(texture_view.texture.handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data()); | ||||
|     texture_view.swizzle = swizzle; | ||||
| } | ||||
| 
 | ||||
| CachedSurfaceView::TextureView CachedSurfaceView::CreateTextureView(GLenum target) const { | ||||
|     TextureView texture_view; | ||||
|     glGenTextures(1, &texture_view.texture.handle); | ||||
| 
 | ||||
|     const GLuint handle{texture_view.texture.handle}; | ||||
|     const FormatTuple& tuple{GetFormatTuple(params.GetPixelFormat(), params.GetComponentType())}; | ||||
| 
 | ||||
|     glTextureView(handle, target, surface.texture.handle, tuple.internal_format, key.base_level, | ||||
|                   key.num_levels, key.base_layer, key.num_layers); | ||||
|     ApplyTextureDefaults(params, handle); | ||||
| 
 | ||||
|     return texture_view; | ||||
| } | ||||
| 
 | ||||
| std::pair<std::reference_wrapper<CachedSurfaceView::TextureView>, GLenum> | ||||
| CachedSurfaceView::GetTextureView(Tegra::Shader::TextureType texture_type, bool is_array) { | ||||
|     using Pair = std::pair<std::reference_wrapper<TextureView>, GLenum>; | ||||
|     switch (texture_type) { | ||||
|     case Tegra::Shader::TextureType::Texture1D: | ||||
|         return is_array ? Pair{texture_view_1d_array, GL_TEXTURE_1D_ARRAY} | ||||
|                         : Pair{texture_view_1d, GL_TEXTURE_1D}; | ||||
|     case Tegra::Shader::TextureType::Texture2D: | ||||
|         return is_array ? Pair{texture_view_2d_array, GL_TEXTURE_2D_ARRAY} | ||||
|                         : Pair{texture_view_2d, GL_TEXTURE_2D}; | ||||
|     case Tegra::Shader::TextureType::Texture3D: | ||||
|         ASSERT(!is_array); | ||||
|         return {texture_view_3d, GL_TEXTURE_3D}; | ||||
|     case Tegra::Shader::TextureType::TextureCube: | ||||
|         return is_array ? Pair{texture_view_cube_array, GL_TEXTURE_CUBE_MAP_ARRAY} | ||||
|                         : Pair{texture_view_cube, GL_TEXTURE_CUBE_MAP}; | ||||
|     } | ||||
|     UNREACHABLE(); | ||||
| } | ||||
| 
 | ||||
| TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, | ||||
|                                        VideoCore::RasterizerInterface& rasterizer) | ||||
|     : TextureCacheBase{system, rasterizer} {} | ||||
| 
 | ||||
| TextureCacheOpenGL::~TextureCacheOpenGL() = default; | ||||
| 
 | ||||
| CachedSurfaceView* TextureCacheOpenGL::TryFastGetSurfaceView( | ||||
|     VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, bool preserve_contents, | ||||
|     const std::vector<CachedSurface*>& overlaps) { | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<CachedSurface> TextureCacheOpenGL::CreateSurface(const SurfaceParams& params) { | ||||
|     return std::make_unique<CachedSurface>(params); | ||||
| } | ||||
| 
 | ||||
| } // namespace OpenGL
 | ||||
							
								
								
									
										131
									
								
								src/video_core/renderer_opengl/gl_texture_cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/video_core/renderer_opengl/gl_texture_cache.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,131 @@ | ||||
| // Copyright 2019 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <functional> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include <glad/glad.h> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/texture_cache.h" | ||||
| 
 | ||||
| namespace OpenGL { | ||||
| 
 | ||||
| using VideoCommon::SurfaceParams; | ||||
| using VideoCommon::ViewKey; | ||||
| using VideoCore::Surface::ComponentType; | ||||
| using VideoCore::Surface::PixelFormat; | ||||
| using VideoCore::Surface::SurfaceTarget; | ||||
| using VideoCore::Surface::SurfaceType; | ||||
| 
 | ||||
| class CachedSurfaceView; | ||||
| class CachedSurface; | ||||
| 
 | ||||
| using TextureCacheBase = VideoCommon::TextureCacheContextless<CachedSurface, CachedSurfaceView>; | ||||
| 
 | ||||
| class CachedSurface final : public VideoCommon::SurfaceBaseContextless<CachedSurfaceView> { | ||||
|     friend CachedSurfaceView; | ||||
| 
 | ||||
| public: | ||||
|     explicit CachedSurface(const SurfaceParams& params); | ||||
|     ~CachedSurface(); | ||||
| 
 | ||||
|     void LoadBuffer(); | ||||
| 
 | ||||
|     GLuint GetTexture() const { | ||||
|         return texture.handle; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     std::unique_ptr<CachedSurfaceView> CreateView(const ViewKey& view_key); | ||||
| 
 | ||||
|     void FlushBufferImpl(); | ||||
| 
 | ||||
|     void UploadTextureImpl(); | ||||
| 
 | ||||
| private: | ||||
|     void UploadTextureMipmap(u32 level); | ||||
| 
 | ||||
|     GLenum internal_format{}; | ||||
|     GLenum format{}; | ||||
|     GLenum type{}; | ||||
|     bool is_compressed{}; | ||||
| 
 | ||||
|     OGLTexture texture; | ||||
| 
 | ||||
|     std::vector<u8> staging_buffer; | ||||
|     u8* host_ptr{}; | ||||
| }; | ||||
| 
 | ||||
| class CachedSurfaceView final { | ||||
| public: | ||||
|     explicit CachedSurfaceView(CachedSurface& surface, ViewKey key); | ||||
|     ~CachedSurfaceView(); | ||||
| 
 | ||||
|     GLuint GetTexture(); | ||||
| 
 | ||||
|     GLuint GetTexture(Tegra::Shader::TextureType texture_type, bool is_array, | ||||
|                       Tegra::Texture::SwizzleSource x_source, | ||||
|                       Tegra::Texture::SwizzleSource y_source, | ||||
|                       Tegra::Texture::SwizzleSource z_source, | ||||
|                       Tegra::Texture::SwizzleSource w_source); | ||||
| 
 | ||||
|     void MarkAsModified(bool is_modified) { | ||||
|         surface.MarkAsModified(is_modified); | ||||
|     } | ||||
| 
 | ||||
|     const SurfaceParams& GetSurfaceParams() const { | ||||
|         return params; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     struct TextureView { | ||||
|         OGLTexture texture; | ||||
|         std::array<Tegra::Texture::SwizzleSource, 4> swizzle{ | ||||
|             Tegra::Texture::SwizzleSource::R, Tegra::Texture::SwizzleSource::G, | ||||
|             Tegra::Texture::SwizzleSource::B, Tegra::Texture::SwizzleSource::A}; | ||||
|     }; | ||||
| 
 | ||||
|     void ApplySwizzle(TextureView& texture_view, Tegra::Texture::SwizzleSource x_source, | ||||
|                       Tegra::Texture::SwizzleSource y_source, | ||||
|                       Tegra::Texture::SwizzleSource z_source, | ||||
|                       Tegra::Texture::SwizzleSource w_source); | ||||
| 
 | ||||
|     TextureView CreateTextureView(GLenum target) const; | ||||
| 
 | ||||
|     std::pair<std::reference_wrapper<TextureView>, GLenum> GetTextureView( | ||||
|         Tegra::Shader::TextureType texture_type, bool is_array); | ||||
| 
 | ||||
|     CachedSurface& surface; | ||||
|     const ViewKey key; | ||||
|     const SurfaceParams params; | ||||
| 
 | ||||
|     TextureView texture_view_1d; | ||||
|     TextureView texture_view_1d_array; | ||||
|     TextureView texture_view_2d; | ||||
|     TextureView texture_view_2d_array; | ||||
|     TextureView texture_view_3d; | ||||
|     TextureView texture_view_cube; | ||||
|     TextureView texture_view_cube_array; | ||||
| }; | ||||
| 
 | ||||
| class TextureCacheOpenGL final : public TextureCacheBase { | ||||
| public: | ||||
|     explicit TextureCacheOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer); | ||||
|     ~TextureCacheOpenGL(); | ||||
| 
 | ||||
| protected: | ||||
|     CachedSurfaceView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, | ||||
|                                              const SurfaceParams& params, bool preserve_contents, | ||||
|                                              const std::vector<CachedSurface*>& overlaps); | ||||
| 
 | ||||
|     std::unique_ptr<CachedSurface> CreateSurface(const SurfaceParams& params); | ||||
| }; | ||||
| 
 | ||||
| } // namespace OpenGL
 | ||||
| @ -460,6 +460,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum | ||||
|     switch (severity) { | ||||
|     case GL_DEBUG_SEVERITY_HIGH: | ||||
|         LOG_CRITICAL(Render_OpenGL, format, str_source, str_type, id, message); | ||||
|         __debugbreak(); | ||||
|         break; | ||||
|     case GL_DEBUG_SEVERITY_MEDIUM: | ||||
|         LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message); | ||||
|  | ||||
| @ -163,7 +163,7 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const { | ||||
|         return block_height; | ||||
|     } | ||||
|     const u32 height{GetMipHeight(level)}; | ||||
|     const u32 default_block_height{GetDefaultBlockHeight(pixel_format)}; | ||||
|     const u32 default_block_height{GetDefaultBlockHeight()}; | ||||
|     const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; | ||||
|     u32 block_height = 16; | ||||
|     while (block_height > 1 && blocks_in_y <= block_height * 4) { | ||||
| @ -205,6 +205,10 @@ std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { | ||||
|     return offset; | ||||
| } | ||||
| 
 | ||||
| std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { | ||||
|     return GetInnerMipmapMemorySize(level, true, true, false) * GetNumLayers(); | ||||
| } | ||||
| 
 | ||||
| std::size_t SurfaceParams::GetGuestLayerSize() const { | ||||
|     return GetInnerMemorySize(false, true, false); | ||||
| } | ||||
| @ -213,6 +217,22 @@ std::size_t SurfaceParams::GetHostLayerSize(u32 level) const { | ||||
|     return GetInnerMipmapMemorySize(level, true, IsLayered(), false); | ||||
| } | ||||
| 
 | ||||
| u32 SurfaceParams::GetDefaultBlockWidth() const { | ||||
|     return VideoCore::Surface::GetDefaultBlockWidth(pixel_format); | ||||
| } | ||||
| 
 | ||||
| u32 SurfaceParams::GetDefaultBlockHeight() const { | ||||
|     return VideoCore::Surface::GetDefaultBlockHeight(pixel_format); | ||||
| } | ||||
| 
 | ||||
| u32 SurfaceParams::GetBitsPerPixel() const { | ||||
|     return VideoCore::Surface::GetFormatBpp(pixel_format); | ||||
| } | ||||
| 
 | ||||
| u32 SurfaceParams::GetBytesPerPixel() const { | ||||
|     return VideoCore::Surface::GetBytesPerPixel(pixel_format); | ||||
| } | ||||
| 
 | ||||
| bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const { | ||||
|     if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) != | ||||
|         std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format, | ||||
| @ -257,7 +277,7 @@ void SurfaceParams::CalculateCachedValues() { | ||||
| 
 | ||||
|     // ASTC is uncompressed in software, in emulated as RGBA8
 | ||||
|     if (IsPixelFormatASTC(pixel_format)) { | ||||
|         host_size_in_bytes = width * height * depth * 4; | ||||
|         host_size_in_bytes = static_cast<std::size_t>(width * height * depth) * 4ULL; | ||||
|     } else { | ||||
|         host_size_in_bytes = GetInnerMemorySize(true, false, false); | ||||
|     } | ||||
| @ -282,13 +302,11 @@ void SurfaceParams::CalculateCachedValues() { | ||||
| std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only, | ||||
|                                                     bool uncompressed) const { | ||||
|     const bool tiled{as_host_size ? false : is_tiled}; | ||||
|     const u32 tile_x{GetDefaultBlockWidth(pixel_format)}; | ||||
|     const u32 tile_y{GetDefaultBlockHeight(pixel_format)}; | ||||
|     const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), tile_x)}; | ||||
|     const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), tile_y)}; | ||||
|     const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())}; | ||||
|     const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())}; | ||||
|     const u32 depth{layer_only ? 1U : GetMipDepth(level)}; | ||||
|     return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(pixel_format), width, height, | ||||
|                                          depth, GetMipBlockHeight(level), GetMipBlockDepth(level)); | ||||
|     return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth, | ||||
|                                          GetMipBlockHeight(level), GetMipBlockDepth(level)); | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
|     for (u32 level = 0; level < num_levels; ++level) { | ||||
|         size += GetInnerMipmapMemorySize(level, as_host_size, layer_only, uncompressed); | ||||
|     } | ||||
|     if (!as_host_size && is_tiled) { | ||||
|     if (is_tiled && !as_host_size) { | ||||
|         size = Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); | ||||
|     } | ||||
|     return size; | ||||
| @ -309,6 +327,7 @@ std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const { | ||||
|     case SurfaceTarget::Texture1D: | ||||
|     case SurfaceTarget::Texture2D: | ||||
|     case SurfaceTarget::Texture3D: { | ||||
|         // TODO(Rodrigo): Add layer iterations for 3D textures
 | ||||
|         constexpr u32 layer = 0; | ||||
|         for (u32 level = 0; level < num_levels; ++level) { | ||||
|             const std::size_t offset{GetGuestMipmapLevelOffset(level)}; | ||||
|  | ||||
| @ -20,6 +20,7 @@ | ||||
| #include "video_core/engines/fermi_2d.h" | ||||
| #include "video_core/engines/maxwell_3d.h" | ||||
| #include "video_core/gpu.h" | ||||
| #include "video_core/memory_manager.h" | ||||
| #include "video_core/rasterizer_interface.h" | ||||
| #include "video_core/surface.h" | ||||
| 
 | ||||
| @ -43,6 +44,10 @@ public: | ||||
| 
 | ||||
|     bool operator==(const HasheableSurfaceParams& rhs) const; | ||||
| 
 | ||||
|     bool operator!=(const HasheableSurfaceParams& rhs) const { | ||||
|         return !operator==(rhs); | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     // Avoid creation outside of a managed environment.
 | ||||
|     HasheableSurfaceParams() = default; | ||||
| @ -167,12 +172,27 @@ public: | ||||
|     /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
 | ||||
|     std::size_t GetHostMipmapLevelOffset(u32 level) const; | ||||
| 
 | ||||
|     /// Returns the size in bytes in host memory (linear) of a given mipmap level.
 | ||||
|     std::size_t GetHostMipmapSize(u32 level) const; | ||||
| 
 | ||||
|     /// Returns the size of a layer in bytes in guest memory.
 | ||||
|     std::size_t GetGuestLayerSize() const; | ||||
| 
 | ||||
|     /// Returns the size of a layer in bytes in host memory for a given mipmap level.
 | ||||
|     std::size_t GetHostLayerSize(u32 level) const; | ||||
| 
 | ||||
|     /// Returns the default block width.
 | ||||
|     u32 GetDefaultBlockWidth() const; | ||||
| 
 | ||||
|     /// Returns the default block height.
 | ||||
|     u32 GetDefaultBlockHeight() const; | ||||
| 
 | ||||
|     /// Returns the bits per pixel.
 | ||||
|     u32 GetBitsPerPixel() const; | ||||
| 
 | ||||
|     /// Returns the bytes per pixel.
 | ||||
|     u32 GetBytesPerPixel() const; | ||||
| 
 | ||||
|     /// Returns true if another surface can be familiar with this. This is a loosely defined term
 | ||||
|     /// that reflects the possibility of these two surface parameters potentially being part of a
 | ||||
|     /// bigger superset.
 | ||||
| @ -370,6 +390,7 @@ private: | ||||
| template <typename TSurface, typename TView, typename TExecutionContext> | ||||
| class TextureCache { | ||||
|     static_assert(std::is_trivially_copyable_v<TExecutionContext>); | ||||
| 
 | ||||
|     using ResultType = std::tuple<TView*, TExecutionContext>; | ||||
|     using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<TSurface*>>; | ||||
|     using IntervalType = typename IntervalMap::interval_type; | ||||
| @ -583,4 +604,79 @@ private: | ||||
|     std::unordered_map<SurfaceParams, std::list<std::unique_ptr<TSurface>>> surface_reserve; | ||||
| }; | ||||
| 
 | ||||
| struct DummyExecutionContext {}; | ||||
| 
 | ||||
| template <typename TSurface, typename TView> | ||||
| class TextureCacheContextless : protected TextureCache<TSurface, TView, DummyExecutionContext> { | ||||
|     using Base = TextureCache<TSurface, TView, DummyExecutionContext>; | ||||
| 
 | ||||
| public: | ||||
|     void InvalidateRegion(CacheAddr addr, std::size_t size) { | ||||
|         Base::InvalidateRegion(addr, size); | ||||
|     } | ||||
| 
 | ||||
|     TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { | ||||
|         return RemoveContext(Base::GetTextureSurface({}, config)); | ||||
|     } | ||||
| 
 | ||||
|     TView* GetDepthBufferSurface(bool preserve_contents) { | ||||
|         return RemoveContext(Base::GetDepthBufferSurface({}, preserve_contents)); | ||||
|     } | ||||
| 
 | ||||
|     TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) { | ||||
|         return RemoveContext(Base::GetColorBufferSurface({}, index, preserve_contents)); | ||||
|     } | ||||
| 
 | ||||
|     TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) { | ||||
|         return RemoveContext(Base::GetFermiSurface({}, config)); | ||||
|     } | ||||
| 
 | ||||
|     TSurface* TryFindFramebufferSurface(const u8* host_ptr) const { | ||||
|         return Base::TryFindFramebufferSurface(host_ptr); | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     explicit TextureCacheContextless(Core::System& system, | ||||
|                                      VideoCore::RasterizerInterface& rasterizer) | ||||
|         : TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {} | ||||
| 
 | ||||
|     virtual TView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, | ||||
|                                          bool preserve_contents, | ||||
|                                          const std::vector<TSurface*>& overlaps) = 0; | ||||
| 
 | ||||
| private: | ||||
|     std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView( | ||||
|         DummyExecutionContext, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, | ||||
|         bool preserve_contents, const std::vector<TSurface*>& overlaps) { | ||||
|         return {TryFastGetSurfaceView(cpu_addr, host_ptr, params, preserve_contents, overlaps), {}}; | ||||
|     } | ||||
| 
 | ||||
|     TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) { | ||||
|         const auto [view, exctx] = return_value; | ||||
|         return view; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| template <typename TView> | ||||
| class SurfaceBaseContextless : public SurfaceBase<TView, DummyExecutionContext> { | ||||
| public: | ||||
|     DummyExecutionContext FlushBuffer(DummyExecutionContext) { | ||||
|         FlushBufferImpl(); | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     DummyExecutionContext UploadTexture(DummyExecutionContext) { | ||||
|         UploadTextureImpl(); | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     explicit SurfaceBaseContextless(const SurfaceParams& params) | ||||
|         : SurfaceBase<TView, DummyExecutionContext>{params} {} | ||||
| 
 | ||||
|     virtual void FlushBufferImpl() = 0; | ||||
| 
 | ||||
|     virtual void UploadTextureImpl() = 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace VideoCommon
 | ||||
|  | ||||
| @ -359,7 +359,8 @@ std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height | ||||
|         const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x); | ||||
|         const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height); | ||||
|         const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth); | ||||
|         return aligned_width * aligned_height * aligned_depth; | ||||
|         const u32 size = aligned_width * aligned_height * aligned_depth; | ||||
|         return size; | ||||
|     } else { | ||||
|         return width * height * depth * bytes_per_pixel; | ||||
|     } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 ReinUsesLisp
						ReinUsesLisp