diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 397b546be..e67cc7f6f 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -128,7 +128,7 @@ target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) create_target_directory_groups(video_core) target_link_libraries(video_core PUBLIC citra_common citra_core) -target_link_libraries(video_core PRIVATE glad tsl::robin_map json-headers dds-ktx nihstro-headers Boost::serialization) +target_link_libraries(video_core PRIVATE Boost::serialization dds-ktx glad json-headers nihstro-headers tsl::robin_map) set_target_properties(video_core PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO}) if ("x86_64" IN_LIST ARCHITECTURE) diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index 2186515e7..c37aac79d 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -492,7 +492,7 @@ SurfaceId RasterizerCache::GetTextureSurface(const Pica::Texture::TextureInfo const u32 min_width = info.width >> max_level; const u32 min_height = info.height >> max_level; if (min_width % 8 != 0 || min_height % 8 != 0) { - if (min_width % 4 == 0 && min_height % 4 == 0 && min_width * min_height <= 32) { + if (min_width % 4 == 0 && min_height % 4 == 0) { const auto [src_surface_id, rect] = GetSurfaceSubRect(params, ScaleMatch::Ignore, true); Surface& src_surface = slot_surfaces[src_surface_id]; @@ -519,7 +519,8 @@ SurfaceId RasterizerCache::GetTextureSurface(const Pica::Texture::TextureInfo return NULL_SURFACE_ID; } - return GetSurface(params, ScaleMatch::Ignore, true); + SurfaceId surface_id = GetSurface(params, ScaleMatch::Ignore, true); + return surface_id ? surface_id : NULL_SURFACE_ID; } template @@ -562,22 +563,21 @@ typename T::Surface& RasterizerCache::GetTextureCube(const TextureCubeConfig& continue; } - SurfaceId& face_surface_id = cube.face_ids[i]; - if (!face_surface_id) { + SurfaceId& face_id = cube.face_ids[i]; + if (!face_id) { info.physical_address = addresses[i]; - face_surface_id = GetTextureSurface(info, config.levels - 1); - ASSERT_MSG(slot_surfaces[face_surface_id].levels == config.levels, + face_id = GetTextureSurface(info, config.levels - 1); + ASSERT_MSG(slot_surfaces[face_id].levels == config.levels, "Texture cube face levels do not match with the levels requested"); } - - Surface& face_surface = slot_surfaces[face_surface_id]; - face_surface.flags |= SurfaceFlagBits::Tracked; - if (cube.ticks[i] == face_surface.ModificationTick()) { + Surface& surface = slot_surfaces[face_id]; + surface.flags |= SurfaceFlagBits::Tracked; + if (cube.ticks[i] == surface.modification_tick) { continue; } - + cube.ticks[i] = surface.modification_tick; Surface& cube_surface = slot_surfaces[cube.surface_id]; - for (u32 level = 0; level < face_surface.levels; level++) { + for (u32 level = 0; level < surface.levels; level++) { const u32 width_lod = scaled_size >> level; const TextureCopy texture_copy = { .src_level = level, @@ -588,9 +588,8 @@ typename T::Surface& RasterizerCache::GetTextureCube(const TextureCubeConfig& .dst_offset = {0, 0}, .extent = {width_lod, width_lod}, }; - runtime.CopyTextures(face_surface, cube_surface, texture_copy); + runtime.CopyTextures(surface, cube_surface, texture_copy); } - cube.ticks[i] = face_surface.ModificationTick(); } return slot_surfaces[cube.surface_id]; @@ -745,7 +744,7 @@ template void RasterizerCache::ForEachSurfaceInRegion(PAddr addr, size_t size, Func&& func) { using FuncReturn = typename std::invoke_result::type; static constexpr bool BOOL_BREAK = std::is_same_v; - boost::container::small_vector surfaces; + boost::container::small_vector surfaces; ForEachPage(addr, size, [this, &surfaces, addr, size, func](u64 page) { const auto it = page_table.find(page); if (it == page_table.end()) { @@ -1327,12 +1326,19 @@ void RasterizerCache::UnregisterSurface(SurfaceId surface_id) { }); if (True(surface.flags & SurfaceFlagBits::Tracked)) { - for (auto& [config, cube] : texture_cube_cache) { - std::array& face_ids = cube.face_ids; - const auto it = std::find(face_ids.begin(), face_ids.end(), surface_id); - if (it != face_ids.end()) { - *it = SurfaceId{}; + auto it = texture_cube_cache.begin(); + while (it != texture_cube_cache.end()) { + std::array& face_ids = it->second.face_ids; + const auto array_it = std::find(face_ids.begin(), face_ids.end(), surface_id); + if (array_it != face_ids.end()) { + *array_it = SurfaceId{}; } + if (std::none_of(face_ids.begin(), face_ids.end(), [](SurfaceId id) { return id; })) { + slot_surfaces.erase(it->second.surface_id); + it = texture_cube_cache.erase(it); + continue; + } + it++; } } diff --git a/src/video_core/rasterizer_cache/slot_vector.h b/src/video_core/rasterizer_cache/slot_vector.h index c1dc47e4f..ba02f2ab5 100644 --- a/src/video_core/rasterizer_cache/slot_vector.h +++ b/src/video_core/rasterizer_cache/slot_vector.h @@ -1,5 +1,6 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. #pragma once diff --git a/src/video_core/renderer_opengl/gl_blit_helper.cpp b/src/video_core/renderer_opengl/gl_blit_helper.cpp index aed7269d2..00a37eb2f 100644 --- a/src/video_core/renderer_opengl/gl_blit_helper.cpp +++ b/src/video_core/renderer_opengl/gl_blit_helper.cpp @@ -143,22 +143,17 @@ bool BlitHelper::ConvertRGBA4ToRGB5A1(Surface& source, Surface& dest, } bool BlitHelper::Filter(Surface& surface, const VideoCore::TextureBlit& blit) { - // Filtering to depth stencil surfaces isn't supported. - if (surface.type == SurfaceType::Depth || surface.type == SurfaceType::DepthStencil) { + const auto filter = Settings::values.texture_filter.GetValue(); + const bool is_depth = + surface.type == SurfaceType::Depth || surface.type == SurfaceType::DepthStencil; + if (filter == Settings::TextureFilter::None || is_depth) { return false; } - // Avoid filtering for mipmaps as the result often looks terrible. if (blit.src_level != 0) { return true; } - const OpenGLState prev_state = OpenGLState::GetCurState(); - state.texture_units[0].texture_2d = surface.Handle(0); - - const auto filter{Settings::values.texture_filter.GetValue()}; switch (filter) { - case TextureFilter::None: - break; case TextureFilter::Anime4K: FilterAnime4K(surface, blit); break; @@ -174,15 +169,19 @@ bool BlitHelper::Filter(Surface& surface, const VideoCore::TextureBlit& blit) { case TextureFilter::xBRZ: FilterXbrz(surface, blit); break; + default: + LOG_ERROR(Render_OpenGL, "Unknown texture filter {}", filter); } - prev_state.Apply(); return true; } void BlitHelper::FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& blit) { static constexpr u8 internal_scale_factor = 2; + const OpenGLState prev_state = OpenGLState::GetCurState(); + SCOPE_EXIT({ prev_state.Apply(); }); + const auto& tuple = surface.Tuple(); const u32 src_width = blit.src_rect.GetWidth(); const u32 src_height = blit.src_rect.GetHeight(); @@ -233,22 +232,33 @@ void BlitHelper::FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& b } void BlitHelper::FilterBicubic(Surface& surface, const VideoCore::TextureBlit& blit) { + const OpenGLState prev_state = OpenGLState::GetCurState(); + SCOPE_EXIT({ prev_state.Apply(); }); + state.texture_units[0].texture_2d = surface.Handle(0); SetParams(bicubic_program, surface.RealExtent(false), blit.src_rect); Draw(bicubic_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect); } void BlitHelper::FilterNearest(Surface& surface, const VideoCore::TextureBlit& blit) { + const OpenGLState prev_state = OpenGLState::GetCurState(); + SCOPE_EXIT({ prev_state.Apply(); }); state.texture_units[2].texture_2d = surface.Handle(0); SetParams(nearest_program, surface.RealExtent(false), blit.src_rect); Draw(nearest_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect); } void BlitHelper::FilterScaleForce(Surface& surface, const VideoCore::TextureBlit& blit) { + const OpenGLState prev_state = OpenGLState::GetCurState(); + SCOPE_EXIT({ prev_state.Apply(); }); + state.texture_units[0].texture_2d = surface.Handle(0); SetParams(scale_force_program, surface.RealExtent(false), blit.src_rect); Draw(scale_force_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect); } void BlitHelper::FilterXbrz(Surface& surface, const VideoCore::TextureBlit& blit) { + const OpenGLState prev_state = OpenGLState::GetCurState(); + SCOPE_EXIT({ prev_state.Apply(); }); + state.texture_units[0].texture_2d = surface.Handle(0); glProgramUniform1f(xbrz_program.handle, 2, static_cast(surface.res_scale)); SetParams(xbrz_program, surface.RealExtent(false), blit.src_rect); Draw(xbrz_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect); diff --git a/src/video_core/renderer_opengl/gl_texture_runtime.cpp b/src/video_core/renderer_opengl/gl_texture_runtime.cpp index 3aaac00ec..f69528854 100644 --- a/src/video_core/renderer_opengl/gl_texture_runtime.cpp +++ b/src/video_core/renderer_opengl/gl_texture_runtime.cpp @@ -257,10 +257,7 @@ bool TextureRuntime::Reinterpret(Surface& source, Surface& dest, } bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) { - const auto prev_state = OpenGLState::GetCurState(); - - // Setup scissor rectangle according to the clear rectangle - OpenGLState state; + OpenGLState state = OpenGLState::GetCurState(); state.scissor.enabled = true; state.scissor.x = clear.texture_rect.left; state.scissor.y = clear.texture_rect.bottom; @@ -269,42 +266,27 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea state.draw.draw_framebuffer = draw_fbos[FboIndex(surface.type)].handle; state.Apply(); + surface.Attach(GL_DRAW_FRAMEBUFFER, clear.texture_level, 0); + switch (surface.type) { case SurfaceType::Color: case SurfaceType::Texture: - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - surface.Handle(), clear.texture_level); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, - 0); - state.color_mask.red_enabled = true; state.color_mask.green_enabled = true; state.color_mask.blue_enabled = true; state.color_mask.alpha_enabled = true; state.Apply(); - glClearBufferfv(GL_COLOR, 0, clear.value.color.AsArray()); break; case SurfaceType::Depth: - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - surface.Handle(), clear.texture_level); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - state.depth.write_mask = GL_TRUE; state.Apply(); - glClearBufferfv(GL_DEPTH, 0, &clear.value.depth); break; case SurfaceType::DepthStencil: - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - surface.Handle(), clear.texture_level); - state.depth.write_mask = GL_TRUE; state.stencil.write_mask = -1; state.Apply(); - glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.value.depth, clear.value.stencil); break; default: @@ -312,7 +294,6 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea return false; } - prev_state.Apply(); return true; } diff --git a/src/video_core/renderer_opengl/gl_texture_runtime.h b/src/video_core/renderer_opengl/gl_texture_runtime.h index 2ffd45a4b..bfe78e2b9 100644 --- a/src/video_core/renderer_opengl/gl_texture_runtime.h +++ b/src/video_core/renderer_opengl/gl_texture_runtime.h @@ -94,7 +94,7 @@ public: const FormatTuple& GetFormatTuple(VideoCore::PixelFormat pixel_format) const; const FormatTuple& GetFormatTuple(VideoCore::CustomPixelFormat pixel_format); - /// Attempts to reinterpret + /// Attempts to reinterpret a rectangle of source to another rectangle of dest bool Reinterpret(Surface& source, Surface& dest, const VideoCore::TextureBlit& blit); /// Fills the rectangle of the texture with the clear value provided @@ -110,13 +110,13 @@ public: void GenerateMipmaps(Surface& surface); private: + /// Takes back ownership of the allocation for recycling + void Recycle(const HostTextureTag tag, Allocation&& alloc); + /// Allocates a texture with the specified dimentions and format Allocation Allocate(const VideoCore::SurfaceParams& params, const VideoCore::Material* material = nullptr); - /// Takes back ownership of the allocation for recycling - void Recycle(const HostTextureTag tag, Allocation&& alloc); - /// Returns the OpenGL driver class const Driver& GetDriver() const { return driver;