rasterizer_cache: Minor cleanups

* Cleanup texture cubes when all the faces have been unregistered from the cache
This commit is contained in:
GPUCode
2023-04-30 10:46:28 +03:00
parent 9bd065640d
commit 4f9af86cba
6 changed files with 57 additions and 59 deletions

View File

@@ -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)

View File

@@ -492,7 +492,7 @@ SurfaceId RasterizerCache<T>::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<T>::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 <class T>
@@ -562,22 +563,21 @@ typename T::Surface& RasterizerCache<T>::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<T>::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 <typename Func>
void RasterizerCache<T>::ForEachSurfaceInRegion(PAddr addr, size_t size, Func&& func) {
using FuncReturn = typename std::invoke_result<Func, SurfaceId, Surface&>::type;
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
boost::container::small_vector<SurfaceId, 32> surfaces;
boost::container::small_vector<SurfaceId, 8> 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<T>::UnregisterSurface(SurfaceId surface_id) {
});
if (True(surface.flags & SurfaceFlagBits::Tracked)) {
for (auto& [config, cube] : texture_cube_cache) {
std::array<SurfaceId, 6>& 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<SurfaceId, 6>& 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++;
}
}

View File

@@ -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

View File

@@ -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<GLfloat>(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);

View File

@@ -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;
}

View File

@@ -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;