rasterizer_cache: Minor cleanups
* Cleanup texture cubes when all the faces have been unregistered from the cache
This commit is contained in:
@@ -128,7 +128,7 @@ target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
|
|||||||
create_target_directory_groups(video_core)
|
create_target_directory_groups(video_core)
|
||||||
|
|
||||||
target_link_libraries(video_core PUBLIC citra_common citra_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})
|
set_target_properties(video_core PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
|
||||||
|
|
||||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||||
|
@@ -492,7 +492,7 @@ SurfaceId RasterizerCache<T>::GetTextureSurface(const Pica::Texture::TextureInfo
|
|||||||
const u32 min_width = info.width >> max_level;
|
const u32 min_width = info.width >> max_level;
|
||||||
const u32 min_height = info.height >> max_level;
|
const u32 min_height = info.height >> max_level;
|
||||||
if (min_width % 8 != 0 || min_height % 8 != 0) {
|
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);
|
const auto [src_surface_id, rect] = GetSurfaceSubRect(params, ScaleMatch::Ignore, true);
|
||||||
Surface& src_surface = slot_surfaces[src_surface_id];
|
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 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>
|
template <class T>
|
||||||
@@ -562,22 +563,21 @@ typename T::Surface& RasterizerCache<T>::GetTextureCube(const TextureCubeConfig&
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceId& face_surface_id = cube.face_ids[i];
|
SurfaceId& face_id = cube.face_ids[i];
|
||||||
if (!face_surface_id) {
|
if (!face_id) {
|
||||||
info.physical_address = addresses[i];
|
info.physical_address = addresses[i];
|
||||||
face_surface_id = GetTextureSurface(info, config.levels - 1);
|
face_id = GetTextureSurface(info, config.levels - 1);
|
||||||
ASSERT_MSG(slot_surfaces[face_surface_id].levels == config.levels,
|
ASSERT_MSG(slot_surfaces[face_id].levels == config.levels,
|
||||||
"Texture cube face levels do not match with the levels requested");
|
"Texture cube face levels do not match with the levels requested");
|
||||||
}
|
}
|
||||||
|
Surface& surface = slot_surfaces[face_id];
|
||||||
Surface& face_surface = slot_surfaces[face_surface_id];
|
surface.flags |= SurfaceFlagBits::Tracked;
|
||||||
face_surface.flags |= SurfaceFlagBits::Tracked;
|
if (cube.ticks[i] == surface.modification_tick) {
|
||||||
if (cube.ticks[i] == face_surface.ModificationTick()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
cube.ticks[i] = surface.modification_tick;
|
||||||
Surface& cube_surface = slot_surfaces[cube.surface_id];
|
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 u32 width_lod = scaled_size >> level;
|
||||||
const TextureCopy texture_copy = {
|
const TextureCopy texture_copy = {
|
||||||
.src_level = level,
|
.src_level = level,
|
||||||
@@ -588,9 +588,8 @@ typename T::Surface& RasterizerCache<T>::GetTextureCube(const TextureCubeConfig&
|
|||||||
.dst_offset = {0, 0},
|
.dst_offset = {0, 0},
|
||||||
.extent = {width_lod, width_lod},
|
.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];
|
return slot_surfaces[cube.surface_id];
|
||||||
@@ -745,7 +744,7 @@ template <typename Func>
|
|||||||
void RasterizerCache<T>::ForEachSurfaceInRegion(PAddr addr, size_t size, Func&& func) {
|
void RasterizerCache<T>::ForEachSurfaceInRegion(PAddr addr, size_t size, Func&& func) {
|
||||||
using FuncReturn = typename std::invoke_result<Func, SurfaceId, Surface&>::type;
|
using FuncReturn = typename std::invoke_result<Func, SurfaceId, Surface&>::type;
|
||||||
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
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) {
|
ForEachPage(addr, size, [this, &surfaces, addr, size, func](u64 page) {
|
||||||
const auto it = page_table.find(page);
|
const auto it = page_table.find(page);
|
||||||
if (it == page_table.end()) {
|
if (it == page_table.end()) {
|
||||||
@@ -1327,12 +1326,19 @@ void RasterizerCache<T>::UnregisterSurface(SurfaceId surface_id) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (True(surface.flags & SurfaceFlagBits::Tracked)) {
|
if (True(surface.flags & SurfaceFlagBits::Tracked)) {
|
||||||
for (auto& [config, cube] : texture_cube_cache) {
|
auto it = texture_cube_cache.begin();
|
||||||
std::array<SurfaceId, 6>& face_ids = cube.face_ids;
|
while (it != texture_cube_cache.end()) {
|
||||||
const auto it = std::find(face_ids.begin(), face_ids.end(), surface_id);
|
std::array<SurfaceId, 6>& face_ids = it->second.face_ids;
|
||||||
if (it != face_ids.end()) {
|
const auto array_it = std::find(face_ids.begin(), face_ids.end(), surface_id);
|
||||||
*it = SurfaceId{};
|
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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@@ -143,22 +143,17 @@ bool BlitHelper::ConvertRGBA4ToRGB5A1(Surface& source, Surface& dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BlitHelper::Filter(Surface& surface, const VideoCore::TextureBlit& blit) {
|
bool BlitHelper::Filter(Surface& surface, const VideoCore::TextureBlit& blit) {
|
||||||
// Filtering to depth stencil surfaces isn't supported.
|
const auto filter = Settings::values.texture_filter.GetValue();
|
||||||
if (surface.type == SurfaceType::Depth || surface.type == SurfaceType::DepthStencil) {
|
const bool is_depth =
|
||||||
|
surface.type == SurfaceType::Depth || surface.type == SurfaceType::DepthStencil;
|
||||||
|
if (filter == Settings::TextureFilter::None || is_depth) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Avoid filtering for mipmaps as the result often looks terrible.
|
|
||||||
if (blit.src_level != 0) {
|
if (blit.src_level != 0) {
|
||||||
return true;
|
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) {
|
switch (filter) {
|
||||||
case TextureFilter::None:
|
|
||||||
break;
|
|
||||||
case TextureFilter::Anime4K:
|
case TextureFilter::Anime4K:
|
||||||
FilterAnime4K(surface, blit);
|
FilterAnime4K(surface, blit);
|
||||||
break;
|
break;
|
||||||
@@ -174,15 +169,19 @@ bool BlitHelper::Filter(Surface& surface, const VideoCore::TextureBlit& blit) {
|
|||||||
case TextureFilter::xBRZ:
|
case TextureFilter::xBRZ:
|
||||||
FilterXbrz(surface, blit);
|
FilterXbrz(surface, blit);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR(Render_OpenGL, "Unknown texture filter {}", filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_state.Apply();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitHelper::FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& blit) {
|
void BlitHelper::FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& blit) {
|
||||||
static constexpr u8 internal_scale_factor = 2;
|
static constexpr u8 internal_scale_factor = 2;
|
||||||
|
|
||||||
|
const OpenGLState prev_state = OpenGLState::GetCurState();
|
||||||
|
SCOPE_EXIT({ prev_state.Apply(); });
|
||||||
|
|
||||||
const auto& tuple = surface.Tuple();
|
const auto& tuple = surface.Tuple();
|
||||||
const u32 src_width = blit.src_rect.GetWidth();
|
const u32 src_width = blit.src_rect.GetWidth();
|
||||||
const u32 src_height = blit.src_rect.GetHeight();
|
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) {
|
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);
|
SetParams(bicubic_program, surface.RealExtent(false), blit.src_rect);
|
||||||
Draw(bicubic_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
Draw(bicubic_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitHelper::FilterNearest(Surface& surface, const VideoCore::TextureBlit& blit) {
|
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);
|
state.texture_units[2].texture_2d = surface.Handle(0);
|
||||||
SetParams(nearest_program, surface.RealExtent(false), blit.src_rect);
|
SetParams(nearest_program, surface.RealExtent(false), blit.src_rect);
|
||||||
Draw(nearest_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
Draw(nearest_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitHelper::FilterScaleForce(Surface& surface, const VideoCore::TextureBlit& blit) {
|
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);
|
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);
|
Draw(scale_force_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitHelper::FilterXbrz(Surface& surface, const VideoCore::TextureBlit& blit) {
|
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));
|
glProgramUniform1f(xbrz_program.handle, 2, static_cast<GLfloat>(surface.res_scale));
|
||||||
SetParams(xbrz_program, surface.RealExtent(false), blit.src_rect);
|
SetParams(xbrz_program, surface.RealExtent(false), blit.src_rect);
|
||||||
Draw(xbrz_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
Draw(xbrz_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
||||||
|
@@ -257,10 +257,7 @@ bool TextureRuntime::Reinterpret(Surface& source, Surface& dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) {
|
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) {
|
||||||
const auto prev_state = OpenGLState::GetCurState();
|
OpenGLState state = OpenGLState::GetCurState();
|
||||||
|
|
||||||
// Setup scissor rectangle according to the clear rectangle
|
|
||||||
OpenGLState state;
|
|
||||||
state.scissor.enabled = true;
|
state.scissor.enabled = true;
|
||||||
state.scissor.x = clear.texture_rect.left;
|
state.scissor.x = clear.texture_rect.left;
|
||||||
state.scissor.y = clear.texture_rect.bottom;
|
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.draw.draw_framebuffer = draw_fbos[FboIndex(surface.type)].handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
|
surface.Attach(GL_DRAW_FRAMEBUFFER, clear.texture_level, 0);
|
||||||
|
|
||||||
switch (surface.type) {
|
switch (surface.type) {
|
||||||
case SurfaceType::Color:
|
case SurfaceType::Color:
|
||||||
case SurfaceType::Texture:
|
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.red_enabled = true;
|
||||||
state.color_mask.green_enabled = true;
|
state.color_mask.green_enabled = true;
|
||||||
state.color_mask.blue_enabled = true;
|
state.color_mask.blue_enabled = true;
|
||||||
state.color_mask.alpha_enabled = true;
|
state.color_mask.alpha_enabled = true;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glClearBufferfv(GL_COLOR, 0, clear.value.color.AsArray());
|
glClearBufferfv(GL_COLOR, 0, clear.value.color.AsArray());
|
||||||
break;
|
break;
|
||||||
case SurfaceType::Depth:
|
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.depth.write_mask = GL_TRUE;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glClearBufferfv(GL_DEPTH, 0, &clear.value.depth);
|
glClearBufferfv(GL_DEPTH, 0, &clear.value.depth);
|
||||||
break;
|
break;
|
||||||
case SurfaceType::DepthStencil:
|
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.depth.write_mask = GL_TRUE;
|
||||||
state.stencil.write_mask = -1;
|
state.stencil.write_mask = -1;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.value.depth, clear.value.stencil);
|
glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.value.depth, clear.value.stencil);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -312,7 +294,6 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_state.Apply();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -94,7 +94,7 @@ public:
|
|||||||
const FormatTuple& GetFormatTuple(VideoCore::PixelFormat pixel_format) const;
|
const FormatTuple& GetFormatTuple(VideoCore::PixelFormat pixel_format) const;
|
||||||
const FormatTuple& GetFormatTuple(VideoCore::CustomPixelFormat pixel_format);
|
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);
|
bool Reinterpret(Surface& source, Surface& dest, const VideoCore::TextureBlit& blit);
|
||||||
|
|
||||||
/// Fills the rectangle of the texture with the clear value provided
|
/// Fills the rectangle of the texture with the clear value provided
|
||||||
@@ -110,13 +110,13 @@ public:
|
|||||||
void GenerateMipmaps(Surface& surface);
|
void GenerateMipmaps(Surface& surface);
|
||||||
|
|
||||||
private:
|
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
|
/// Allocates a texture with the specified dimentions and format
|
||||||
Allocation Allocate(const VideoCore::SurfaceParams& params,
|
Allocation Allocate(const VideoCore::SurfaceParams& params,
|
||||||
const VideoCore::Material* material = nullptr);
|
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
|
/// Returns the OpenGL driver class
|
||||||
const Driver& GetDriver() const {
|
const Driver& GetDriver() const {
|
||||||
return driver;
|
return driver;
|
||||||
|
Reference in New Issue
Block a user