diff options
-rw-r--r-- | src/video_core/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 66 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 4 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.cpp | 514 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_texture_cache.h | 131 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 1 | ||||
-rw-r--r-- | src/video_core/texture_cache.cpp | 37 | ||||
-rw-r--r-- | src/video_core/texture_cache.h | 96 | ||||
-rw-r--r-- | src/video_core/textures/decoders.cpp | 3 |
9 files changed, 809 insertions, 47 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f8b67cbe1..64cff27a4 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -45,8 +45,6 @@ add_library(video_core STATIC 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 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 { 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; 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 @@ #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; 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 @@ +// 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 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 @@ +// 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 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 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); 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 { 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)}; 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 @@ #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 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 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; } |