diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 47270ab36..f8c3a4f94 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -132,8 +132,6 @@ void Config::ReadValues() { static_cast(sdl2_config->GetInteger("Renderer", "use_vsync_new", 1)); Settings::values.texture_filter_name = sdl2_config->GetString("Renderer", "texture_filter_name", "none"); - Settings::values.texture_filter_factor = - sdl2_config->GetInteger("Renderer", "texture_filter_factor", 1); Settings::values.render_3d = static_cast( sdl2_config->GetInteger("Renderer", "render_3d", 0)); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 881700913..b7996d1cb 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -132,9 +132,8 @@ use_disk_shader_cache = # factor for the 3DS resolution resolution_factor = -# Texture filter name and scale factor +# Texture filter name texture_filter_name = -texture_filter_factor = # Turns on the frame limiter, which will limit frames output to the target game speed # 0: Off, 1: On (default) diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index d139a89e9..0bc28a43a 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -454,8 +454,6 @@ void Config::ReadRendererValues() { ReadSetting(QStringLiteral("texture_filter_name"), QStringLiteral("none")) .toString() .toStdString(); - Settings::values.texture_filter_factor = - ReadSetting(QStringLiteral("texture_filter_factor"), 1).toInt(); qt_config->endGroup(); } @@ -893,8 +891,6 @@ void Config::SaveRendererValues() { WriteSetting(QStringLiteral("texture_filter_name"), QString::fromStdString(Settings::values.texture_filter_name), QStringLiteral("none")); - WriteSetting(QStringLiteral("texture_filter_factor"), Settings::values.texture_filter_factor, - 1); qt_config->endGroup(); } diff --git a/src/citra_qt/configuration/configure_enhancements.cpp b/src/citra_qt/configuration/configure_enhancements.cpp index e1c6b6bdd..f25b9c1e1 100644 --- a/src/citra_qt/configuration/configure_enhancements.cpp +++ b/src/citra_qt/configuration/configure_enhancements.cpp @@ -8,17 +8,14 @@ #include "core/settings.h" #include "ui_configure_enhancements.h" #include "video_core/renderer_opengl/post_processing_opengl.h" -#include "video_core/renderer_opengl/texture_filters/texture_filter_manager.h" +#include "video_core/renderer_opengl/texture_filters/texture_filterer.h" ConfigureEnhancements::ConfigureEnhancements(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureEnhancements) { ui->setupUi(this); - for (const auto& filter : OpenGL::TextureFilterManager::TextureFilterMap()) - ui->texture_filter_combobox->addItem(QString::fromStdString(filter.first.data())); - - connect(ui->texture_filter_combobox, QOverload::of(&QComboBox::currentIndexChanged), this, - &ConfigureEnhancements::updateTextureFilter); + for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames()) + ui->texture_filter_combobox->addItem(QString::fromStdString(filter.data())); SetConfiguration(); @@ -60,7 +57,6 @@ void ConfigureEnhancements::SetConfiguration() { ui->factor_3d->setValue(Settings::values.factor_3d); updateShaders(Settings::values.render_3d); ui->toggle_linear_filter->setChecked(Settings::values.filter_mode); - ui->texture_scale_spinbox->setValue(Settings::values.texture_filter_factor); int tex_filter_idx = ui->texture_filter_combobox->findText( QString::fromStdString(Settings::values.texture_filter_name)); if (tex_filter_idx == -1) { @@ -68,7 +64,6 @@ void ConfigureEnhancements::SetConfiguration() { } else { ui->texture_filter_combobox->setCurrentIndex(tex_filter_idx); } - updateTextureFilter(tex_filter_idx); ui->layout_combobox->setCurrentIndex(static_cast(Settings::values.layout_option)); ui->swap_screen->setChecked(Settings::values.swap_screen); ui->toggle_disk_shader_cache->setChecked(Settings::values.use_hw_shader && @@ -105,17 +100,6 @@ void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_op } } -void ConfigureEnhancements::updateTextureFilter(int index) { - if (index == -1) - return; - ui->texture_filter_group->setEnabled(index != 0); - const auto& clamp = OpenGL::TextureFilterManager::TextureFilterMap() - .at(ui->texture_filter_combobox->currentText().toStdString()) - .clamp_scale; - ui->texture_scale_spinbox->setMinimum(clamp.min); - ui->texture_scale_spinbox->setMaximum(clamp.max); -} - void ConfigureEnhancements::RetranslateUI() { ui->retranslateUi(this); } @@ -130,7 +114,6 @@ void ConfigureEnhancements::ApplyConfiguration() { ui->shader_combobox->itemText(ui->shader_combobox->currentIndex()).toStdString(); Settings::values.filter_mode = ui->toggle_linear_filter->isChecked(); Settings::values.texture_filter_name = ui->texture_filter_combobox->currentText().toStdString(); - Settings::values.texture_filter_factor = ui->texture_scale_spinbox->value(); Settings::values.layout_option = static_cast(ui->layout_combobox->currentIndex()); Settings::values.swap_screen = ui->swap_screen->isChecked(); diff --git a/src/citra_qt/configuration/configure_enhancements.ui b/src/citra_qt/configuration/configure_enhancements.ui index d3193e9eb..909a98643 100644 --- a/src/citra_qt/configuration/configure_enhancements.ui +++ b/src/citra_qt/configuration/configure_enhancements.ui @@ -131,42 +131,6 @@ - - - - - 16 - - - 0 - - - 0 - - - 0 - - - - - - - Texture Scale Factor - - - - - - - 1 - - - - - - - - diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 13b1e965f..6af80205b 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -13,7 +13,6 @@ #include "core/hle/service/mic_u.h" #include "core/settings.h" #include "video_core/renderer_base.h" -#include "video_core/renderer_opengl/texture_filters/texture_filter_manager.h" #include "video_core/video_core.h" namespace Settings { @@ -38,9 +37,7 @@ void Apply() { VideoCore::g_renderer_bg_color_update_requested = true; VideoCore::g_renderer_sampler_update_requested = true; VideoCore::g_renderer_shader_update_requested = true; - - OpenGL::TextureFilterManager::GetInstance().SetTextureFilter(values.texture_filter_name, - values.texture_filter_factor); + VideoCore::g_texture_filter_update_requested = true; auto& system = Core::System::GetInstance(); if (system.IsPoweredOn()) { @@ -88,7 +85,6 @@ void LogSettings() { LogSetting("Renderer_FrameLimit", Settings::values.frame_limit); LogSetting("Renderer_PostProcessingShader", Settings::values.pp_shader_name); LogSetting("Renderer_FilterMode", Settings::values.filter_mode); - LogSetting("Renderer_TextureFilterFactor", Settings::values.texture_filter_factor); LogSetting("Renderer_TextureFilterName", Settings::values.texture_filter_name); LogSetting("Stereoscopy_Render3d", static_cast(Settings::values.render_3d)); LogSetting("Stereoscopy_Factor3d", Settings::values.factor_3d); diff --git a/src/core/settings.h b/src/core/settings.h index aa7e781b5..980156663 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -148,7 +148,6 @@ struct Values { u16 resolution_factor; bool use_frame_limit; u16 frame_limit; - u16 texture_filter_factor; std::string texture_filter_name; LayoutOption layout_option; diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index a7dbc42de..3553fe0a8 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -43,6 +43,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_surface_params.cpp + renderer_opengl/gl_surface_params.h renderer_opengl/gl_vars.cpp renderer_opengl/gl_vars.h renderer_opengl/pica_to_gl.h @@ -54,9 +56,9 @@ add_library(video_core STATIC renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h renderer_opengl/texture_filters/bicubic/bicubic.cpp renderer_opengl/texture_filters/bicubic/bicubic.h - renderer_opengl/texture_filters/texture_filter_interface.h - renderer_opengl/texture_filters/texture_filter_manager.cpp - renderer_opengl/texture_filters/texture_filter_manager.h + renderer_opengl/texture_filters/texture_filter_base.h + renderer_opengl/texture_filters/texture_filterer.cpp + renderer_opengl/texture_filters/texture_filterer.h renderer_opengl/texture_filters/xbrz/xbrz_freescale.cpp renderer_opengl/texture_filters/xbrz/xbrz_freescale.h shader/debug_data.h diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 56d65133f..868bcaecd 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -35,7 +35,7 @@ #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/gl_vars.h" -#include "video_core/renderer_opengl/texture_filters/texture_filter_manager.h" +#include "video_core/renderer_opengl/texture_filters/texture_filterer.h" #include "video_core/utils.h" #include "video_core/video_core.h" @@ -494,125 +494,6 @@ static bool FillSurface(const Surface& surface, const u8* fill_data, return true; } -SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { - SurfaceParams params = *this; - const u32 tiled_size = is_tiled ? 8 : 1; - const u32 stride_tiled_bytes = BytesInPixels(stride * tiled_size); - PAddr aligned_start = - addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes); - PAddr aligned_end = - addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes); - - if (aligned_end - aligned_start > stride_tiled_bytes) { - params.addr = aligned_start; - params.height = (aligned_end - aligned_start) / BytesInPixels(stride); - } else { - // 1 row - ASSERT(aligned_end - aligned_start == stride_tiled_bytes); - const u32 tiled_alignment = BytesInPixels(is_tiled ? 8 * 8 : 1); - aligned_start = - addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment); - aligned_end = - addr + Common::AlignUp(boost::icl::last_next(interval) - addr, tiled_alignment); - params.addr = aligned_start; - params.width = PixelsInBytes(aligned_end - aligned_start) / tiled_size; - params.stride = params.width; - params.height = tiled_size; - } - params.UpdateParams(); - - return params; -} - -SurfaceInterval SurfaceParams::GetSubRectInterval(Common::Rectangle unscaled_rect) const { - if (unscaled_rect.GetHeight() == 0 || unscaled_rect.GetWidth() == 0) { - return {}; - } - - if (is_tiled) { - unscaled_rect.left = Common::AlignDown(unscaled_rect.left, 8) * 8; - unscaled_rect.bottom = Common::AlignDown(unscaled_rect.bottom, 8) / 8; - unscaled_rect.right = Common::AlignUp(unscaled_rect.right, 8) * 8; - unscaled_rect.top = Common::AlignUp(unscaled_rect.top, 8) / 8; - } - - const u32 stride_tiled = !is_tiled ? stride : stride * 8; - - const u32 pixel_offset = - stride_tiled * (!is_tiled ? unscaled_rect.bottom : (height / 8) - unscaled_rect.top) + - unscaled_rect.left; - - const u32 pixels = (unscaled_rect.GetHeight() - 1) * stride_tiled + unscaled_rect.GetWidth(); - - return {addr + BytesInPixels(pixel_offset), addr + BytesInPixels(pixel_offset + pixels)}; -} - -Common::Rectangle SurfaceParams::GetSubRect(const SurfaceParams& sub_surface) const { - const u32 begin_pixel_index = PixelsInBytes(sub_surface.addr - addr); - - if (is_tiled) { - const int x0 = (begin_pixel_index % (stride * 8)) / 8; - const int y0 = (begin_pixel_index / (stride * 8)) * 8; - // Top to bottom - return Common::Rectangle(x0, height - y0, x0 + sub_surface.width, - height - (y0 + sub_surface.height)); - } - - const int x0 = begin_pixel_index % stride; - const int y0 = begin_pixel_index / stride; - // Bottom to top - return Common::Rectangle(x0, y0 + sub_surface.height, x0 + sub_surface.width, y0); -} - -Common::Rectangle SurfaceParams::GetScaledSubRect(const SurfaceParams& sub_surface) const { - auto rect = GetSubRect(sub_surface); - rect.left = rect.left * res_scale; - rect.right = rect.right * res_scale; - rect.top = rect.top * res_scale; - rect.bottom = rect.bottom * res_scale; - return rect; -} - -bool SurfaceParams::ExactMatch(const SurfaceParams& other_surface) const { - return std::tie(other_surface.addr, other_surface.width, other_surface.height, - other_surface.stride, other_surface.pixel_format, other_surface.is_tiled) == - std::tie(addr, width, height, stride, pixel_format, is_tiled) && - pixel_format != PixelFormat::Invalid; -} - -bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const { - return sub_surface.addr >= addr && sub_surface.end <= end && - sub_surface.pixel_format == pixel_format && pixel_format != PixelFormat::Invalid && - sub_surface.is_tiled == is_tiled && - (sub_surface.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 && - (sub_surface.stride == stride || sub_surface.height <= (is_tiled ? 8u : 1u)) && - GetSubRect(sub_surface).right <= stride; -} - -bool SurfaceParams::CanExpand(const SurfaceParams& expanded_surface) const { - return pixel_format != PixelFormat::Invalid && pixel_format == expanded_surface.pixel_format && - addr <= expanded_surface.end && expanded_surface.addr <= end && - is_tiled == expanded_surface.is_tiled && stride == expanded_surface.stride && - (std::max(expanded_surface.addr, addr) - std::min(expanded_surface.addr, addr)) % - BytesInPixels(stride * (is_tiled ? 8 : 1)) == - 0; -} - -bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const { - if (pixel_format == PixelFormat::Invalid || addr > texcopy_params.addr || - end < texcopy_params.end) { - return false; - } - if (texcopy_params.width != texcopy_params.stride) { - const u32 tile_stride = BytesInPixels(stride * (is_tiled ? 8 : 1)); - return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 && - texcopy_params.width % BytesInPixels(is_tiled ? 64 : 1) == 0 && - (texcopy_params.height == 1 || texcopy_params.stride == tile_stride) && - ((texcopy_params.addr - addr) % tile_stride) + texcopy_params.width <= tile_stride; - } - return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval(); -} - bool CachedSurface::CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const { if (type == SurfaceType::Fill && IsRegionValid(fill_interval) && @@ -654,47 +535,6 @@ bool CachedSurface::CanCopy(const SurfaceParams& dest_surface, return false; } -SurfaceInterval SurfaceParams::GetCopyableInterval(const Surface& src_surface) const { - SurfaceInterval result{}; - const auto valid_regions = - SurfaceRegions(GetInterval() & src_surface->GetInterval()) - src_surface->invalid_regions; - for (auto& valid_interval : valid_regions) { - const SurfaceInterval aligned_interval{ - addr + Common::AlignUp(boost::icl::first(valid_interval) - addr, - BytesInPixels(is_tiled ? 8 * 8 : 1)), - addr + Common::AlignDown(boost::icl::last_next(valid_interval) - addr, - BytesInPixels(is_tiled ? 8 * 8 : 1))}; - - if (BytesInPixels(is_tiled ? 8 * 8 : 1) > boost::icl::length(valid_interval) || - boost::icl::length(aligned_interval) == 0) { - continue; - } - - // Get the rectangle within aligned_interval - const u32 stride_bytes = BytesInPixels(stride) * (is_tiled ? 8 : 1); - SurfaceInterval rect_interval{ - addr + Common::AlignUp(boost::icl::first(aligned_interval) - addr, stride_bytes), - addr + Common::AlignDown(boost::icl::last_next(aligned_interval) - addr, stride_bytes), - }; - if (boost::icl::first(rect_interval) > boost::icl::last_next(rect_interval)) { - // 1 row - rect_interval = aligned_interval; - } else if (boost::icl::length(rect_interval) == 0) { - // 2 rows that do not make a rectangle, return the larger one - const SurfaceInterval row1{boost::icl::first(aligned_interval), - boost::icl::first(rect_interval)}; - const SurfaceInterval row2{boost::icl::first(rect_interval), - boost::icl::last_next(aligned_interval)}; - rect_interval = (boost::icl::length(row1) > boost::icl::length(row2)) ? row1 : row2; - } - - if (boost::icl::length(rect_interval) > boost::icl::length(result)) { - result = rect_interval; - } - } - return result; -} - MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface, SurfaceInterval copy_interval) { @@ -956,10 +796,6 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect, GLuint read_fb_ if (Settings::values.custom_textures) is_custom = LoadCustomTexture(tex_hash, custom_tex_info); - TextureFilterInterface* const texture_filter = - is_custom ? nullptr : TextureFilterManager::GetInstance().GetTextureFilter(); - const u16 default_scale = texture_filter ? texture_filter->scale_factor : 1; - // Load data from memory to the surface GLint x0 = static_cast(rect.left); GLint y0 = static_cast(rect.bottom); @@ -971,7 +807,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect, GLuint read_fb_ // If not 1x scale, create 1x texture that we will blit from to replace texture subrect in // surface OGLTexture unscaled_tex; - if (res_scale != default_scale) { + if (res_scale != 1) { x0 = 0; y0 = 0; @@ -980,8 +816,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect, GLuint read_fb_ AllocateSurfaceTexture(unscaled_tex.handle, GetFormatTuple(PixelFormat::RGBA8), custom_tex_info.width, custom_tex_info.height); } else { - AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth() * default_scale, - rect.GetHeight() * default_scale); + AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight()); } target_tex = unscaled_tex.handle; } @@ -1007,16 +842,6 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect, GLuint read_fb_ glActiveTexture(GL_TEXTURE0); glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, custom_tex_info.width, custom_tex_info.height, GL_RGBA, GL_UNSIGNED_BYTE, custom_tex_info.tex.data()); - } else if (texture_filter) { - if (res_scale == default_scale) { - AllocateSurfaceTexture(texture.handle, GetFormatTuple(pixel_format), - rect.GetWidth() * default_scale, - rect.GetHeight() * default_scale); - cur_state.texture_units[0].texture_2d = texture.handle; - cur_state.Apply(); - } - texture_filter->scale(*this, {(u32)x0, (u32)y0, rect.GetWidth(), rect.GetHeight()}, - buffer_offset); } else { glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast(stride)); @@ -1027,13 +852,13 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect, GLuint read_fb_ } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - if (Settings::values.dump_textures && !is_custom && !texture_filter) + if (Settings::values.dump_textures && !is_custom) DumpTexture(target_tex, tex_hash); cur_state.texture_units[0].texture_2d = old_tex; cur_state.Apply(); - if (res_scale != default_scale) { + if (res_scale != 1) { auto scaled_rect = rect; scaled_rect.left *= res_scale; scaled_rect.top *= res_scale; @@ -1042,8 +867,11 @@ void CachedSurface::UploadGLTexture(Common::Rectangle rect, GLuint read_fb_ auto from_rect = is_custom ? Common::Rectangle{0, custom_tex_info.height, custom_tex_info.width, 0} : Common::Rectangle{0, rect.GetHeight(), rect.GetWidth(), 0}; - BlitTextures(unscaled_tex.handle, from_rect, texture.handle, scaled_rect, type, - read_fb_handle, draw_fb_handle); + if (!owner.texture_filterer->Filter(unscaled_tex.handle, from_rect, texture.handle, + scaled_rect, type, read_fb_handle, draw_fb_handle)) { + BlitTextures(unscaled_tex.handle, from_rect, texture.handle, scaled_rect, type, + read_fb_handle, draw_fb_handle); + } } InvalidateAllWatcher(); @@ -1232,6 +1060,10 @@ Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params } RasterizerCacheOpenGL::RasterizerCacheOpenGL() { + resolution_scale_factor = VideoCore::GetResolutionScaleFactor(); + texture_filterer = std::make_unique(Settings::values.texture_filter_name, + resolution_scale_factor); + read_framebuffer.Create(); draw_framebuffer.Create(); @@ -1508,11 +1340,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInf params.height = info.height; params.is_tiled = true; params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(info.format); - TextureFilterInterface* filter{}; - - params.res_scale = (filter = TextureFilterManager::GetInstance().GetTextureFilter()) - ? filter->scale_factor - : 1; + params.res_scale = texture_filterer->IsNull() ? 1 : resolution_scale_factor; params.UpdateParams(); u32 min_width = info.width >> max_level; @@ -1565,7 +1393,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInf glTexImage2D(GL_TEXTURE_2D, level, format_tuple.internal_format, width >> level, height >> level, 0, format_tuple.format, format_tuple.type, nullptr); } - if (surface->is_custom) { + if (surface->is_custom || !texture_filterer->IsNull()) { // TODO: proper mipmap support for custom textures glGenerateMipmap(GL_TEXTURE_2D); } @@ -1601,7 +1429,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInf } state.ResetTexture(level_surface->texture.handle); state.Apply(); - if (!surface->is_custom) { + if (!surface->is_custom && texture_filterer->IsNull()) { glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, level_surface->texture.handle, 0); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, @@ -1725,10 +1553,9 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( const auto& config = regs.framebuffer.framebuffer; // update resolution_scale_factor and reset cache if changed - static u16 resolution_scale_factor = VideoCore::GetResolutionScaleFactor(); - if (resolution_scale_factor != VideoCore::GetResolutionScaleFactor() || - TextureFilterManager::GetInstance().IsUpdated()) { - TextureFilterManager::GetInstance().Reset(); + if ((resolution_scale_factor != VideoCore::GetResolutionScaleFactor()) | + (VideoCore::g_texture_filter_update_requested.exchange(false) && + texture_filterer->Reset(Settings::values.texture_filter_name, resolution_scale_factor))) { resolution_scale_factor = VideoCore::GetResolutionScaleFactor(); FlushAll(); while (!surface_cache.empty()) @@ -1813,7 +1640,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( } Surface RasterizerCacheOpenGL::GetFillSurface(const GPU::Regs::MemoryFillConfig& config) { - Surface new_surface = std::make_shared(); + Surface new_surface = std::make_shared(*this); new_surface->addr = config.GetStartAddress(); new_surface->end = config.GetEndAddress(); @@ -2041,7 +1868,7 @@ void RasterizerCacheOpenGL::InvalidateRegion(PAddr addr, u32 size, const Surface } Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) { - Surface surface = std::make_shared(); + Surface surface = std::make_shared(*this); static_cast(*surface) = params; surface->texture.Create(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 466ebb8d0..dffcbb05c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -26,14 +26,15 @@ #include "common/common_types.h" #include "common/math_util.h" #include "core/custom_tex_cache.h" -#include "core/hw/gpu.h" -#include "video_core/regs_framebuffer.h" -#include "video_core/regs_texturing.h" #include "video_core/renderer_opengl/gl_resource_manager.h" +#include "video_core/renderer_opengl/gl_surface_params.h" #include "video_core/texture/texture_decode.h" namespace OpenGL { +class RasterizerCacheOpenGL; +class TextureFilterer; + struct TextureCubeConfig { PAddr px; PAddr nx; @@ -76,11 +77,8 @@ struct hash { namespace OpenGL { -struct CachedSurface; -using Surface = std::shared_ptr; using SurfaceSet = std::set; -using SurfaceInterval = boost::icl::right_open_interval; using SurfaceRegions = boost::icl::interval_set; using SurfaceMap = boost::icl::interval_map BPP_TABLE = { - 32, // RGBA8 - 24, // RGB8 - 16, // RGB5A1 - 16, // RGB565 - 16, // RGBA4 - 16, // IA8 - 16, // RG8 - 8, // I8 - 8, // A8 - 8, // IA4 - 4, // I4 - 4, // A4 - 4, // ETC1 - 8, // ETC1A4 - 16, // D16 - 0, - 24, // D24 - 32, // D24S8 - }; - -public: - enum class PixelFormat { - // First 5 formats are shared between textures and color buffers - RGBA8 = 0, - RGB8 = 1, - RGB5A1 = 2, - RGB565 = 3, - RGBA4 = 4, - - // Texture-only formats - IA8 = 5, - RG8 = 6, - I8 = 7, - A8 = 8, - IA4 = 9, - I4 = 10, - A4 = 11, - ETC1 = 12, - ETC1A4 = 13, - - // Depth buffer-only formats - D16 = 14, - // gap - D24 = 16, - D24S8 = 17, - - Invalid = 255, - }; - - enum class SurfaceType { - Color = 0, - Texture = 1, - Depth = 2, - DepthStencil = 3, - Fill = 4, - Invalid = 5 - }; - - static constexpr unsigned int GetFormatBpp(PixelFormat format) { - const auto format_idx = static_cast(format); - DEBUG_ASSERT_MSG(format_idx < BPP_TABLE.size(), "Invalid pixel format {}", format_idx); - return BPP_TABLE[format_idx]; - } - - unsigned int GetFormatBpp() const { - return GetFormatBpp(pixel_format); - } - - static PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) { - return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; - } - - static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) { - return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; - } - - static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) { - return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) - : PixelFormat::Invalid; - } - - static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) { - switch (format) { - // RGB565 and RGB5A1 are switched in PixelFormat compared to ColorFormat - case GPU::Regs::PixelFormat::RGB565: - return PixelFormat::RGB565; - case GPU::Regs::PixelFormat::RGB5A1: - return PixelFormat::RGB5A1; - default: - return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; - } - } - - static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { - SurfaceType a_type = GetFormatType(pixel_format_a); - SurfaceType b_type = GetFormatType(pixel_format_b); - - if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && - (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { - return true; - } - - if (a_type == SurfaceType::Depth && b_type == SurfaceType::Depth) { - return true; - } - - if (a_type == SurfaceType::DepthStencil && b_type == SurfaceType::DepthStencil) { - return true; - } - - return false; - } - - static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) { - if ((unsigned int)pixel_format < 5) { - return SurfaceType::Color; - } - - if ((unsigned int)pixel_format < 14) { - return SurfaceType::Texture; - } - - if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) { - return SurfaceType::Depth; - } - - if (pixel_format == PixelFormat::D24S8) { - return SurfaceType::DepthStencil; - } - - return SurfaceType::Invalid; - } - - /// Update the params "size", "end" and "type" from the already set "addr", "width", "height" - /// and "pixel_format" - void UpdateParams() { - if (stride == 0) { - stride = width; - } - type = GetFormatType(pixel_format); - size = !is_tiled ? BytesInPixels(stride * (height - 1) + width) - : BytesInPixels(stride * 8 * (height / 8 - 1) + width * 8); - end = addr + size; - } - - SurfaceInterval GetInterval() const { - return SurfaceInterval(addr, end); - } - - // Returns the outer rectangle containing "interval" - SurfaceParams FromInterval(SurfaceInterval interval) const; - - SurfaceInterval GetSubRectInterval(Common::Rectangle unscaled_rect) const; - - // Returns the region of the biggest valid rectange within interval - SurfaceInterval GetCopyableInterval(const Surface& src_surface) const; - - u32 GetScaledWidth() const { - return width * res_scale; - } - - u32 GetScaledHeight() const { - return height * res_scale; - } - - Common::Rectangle GetRect() const { - return {0, height, width, 0}; - } - - Common::Rectangle GetScaledRect() const { - return {0, GetScaledHeight(), GetScaledWidth(), 0}; - } - - u32 PixelsInBytes(u32 size) const { - return size * CHAR_BIT / GetFormatBpp(pixel_format); - } - - u32 BytesInPixels(u32 pixels) const { - return pixels * GetFormatBpp(pixel_format) / CHAR_BIT; - } - - bool ExactMatch(const SurfaceParams& other_surface) const; - bool CanSubRect(const SurfaceParams& sub_surface) const; - bool CanExpand(const SurfaceParams& expanded_surface) const; - bool CanTexCopy(const SurfaceParams& texcopy_params) const; - - Common::Rectangle GetSubRect(const SurfaceParams& sub_surface) const; - Common::Rectangle GetScaledSubRect(const SurfaceParams& sub_surface) const; - - PAddr addr = 0; - PAddr end = 0; - u32 size = 0; - - u32 width = 0; - u32 height = 0; - u32 stride = 0; - u16 res_scale = 1; - - bool is_tiled = false; - PixelFormat pixel_format = PixelFormat::Invalid; - SurfaceType type = SurfaceType::Invalid; -}; - /** * A watcher that notifies whether a cached surface has been changed. This is useful for caching * surface collection objects, including texture cube and mipmap. @@ -345,6 +137,8 @@ private: }; struct CachedSurface : SurfaceParams, std::enable_shared_from_this { + CachedSurface(RasterizerCacheOpenGL& owner) : owner{owner} {} + bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const; bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const; @@ -422,6 +216,7 @@ struct CachedSurface : SurfaceParams, std::enable_shared_from_this> watchers; }; @@ -519,8 +314,12 @@ private: OGLProgram d24s8_abgr_shader; GLint d24s8_abgr_tbo_size_u_id; GLint d24s8_abgr_viewport_u_id; + u16 resolution_scale_factor; std::unordered_map texture_cube_cache; + +public: + std::unique_ptr texture_filterer; }; struct FormatTuple { diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 5d655a127..cc7a864a2 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -38,13 +38,6 @@ constexpr GLuint ShadowTexturePZ = 5; constexpr GLuint ShadowTextureNZ = 6; } // namespace ImageUnits -struct Viewport { - GLint x; - GLint y; - GLsizei width; - GLsizei height; -}; - class OpenGLState { public: struct { @@ -142,7 +135,12 @@ public: GLsizei height; } scissor; - Viewport viewport; + struct { + GLint x; + GLint y; + GLsizei width; + GLsizei height; + } viewport; std::array clip_distance; // GL_CLIP_DISTANCE diff --git a/src/video_core/renderer_opengl/gl_surface_params.cpp b/src/video_core/renderer_opengl/gl_surface_params.cpp new file mode 100644 index 000000000..ceb0359ec --- /dev/null +++ b/src/video_core/renderer_opengl/gl_surface_params.cpp @@ -0,0 +1,171 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/alignment.h" +#include "video_core/renderer_opengl/gl_rasterizer_cache.h" +#include "video_core/renderer_opengl/gl_surface_params.h" + +namespace OpenGL { + +SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { + SurfaceParams params = *this; + const u32 tiled_size = is_tiled ? 8 : 1; + const u32 stride_tiled_bytes = BytesInPixels(stride * tiled_size); + PAddr aligned_start = + addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes); + PAddr aligned_end = + addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes); + + if (aligned_end - aligned_start > stride_tiled_bytes) { + params.addr = aligned_start; + params.height = (aligned_end - aligned_start) / BytesInPixels(stride); + } else { + // 1 row + ASSERT(aligned_end - aligned_start == stride_tiled_bytes); + const u32 tiled_alignment = BytesInPixels(is_tiled ? 8 * 8 : 1); + aligned_start = + addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment); + aligned_end = + addr + Common::AlignUp(boost::icl::last_next(interval) - addr, tiled_alignment); + params.addr = aligned_start; + params.width = PixelsInBytes(aligned_end - aligned_start) / tiled_size; + params.stride = params.width; + params.height = tiled_size; + } + params.UpdateParams(); + + return params; +} + +SurfaceInterval SurfaceParams::GetSubRectInterval(Common::Rectangle unscaled_rect) const { + if (unscaled_rect.GetHeight() == 0 || unscaled_rect.GetWidth() == 0) { + return {}; + } + + if (is_tiled) { + unscaled_rect.left = Common::AlignDown(unscaled_rect.left, 8) * 8; + unscaled_rect.bottom = Common::AlignDown(unscaled_rect.bottom, 8) / 8; + unscaled_rect.right = Common::AlignUp(unscaled_rect.right, 8) * 8; + unscaled_rect.top = Common::AlignUp(unscaled_rect.top, 8) / 8; + } + + const u32 stride_tiled = !is_tiled ? stride : stride * 8; + + const u32 pixel_offset = + stride_tiled * (!is_tiled ? unscaled_rect.bottom : (height / 8) - unscaled_rect.top) + + unscaled_rect.left; + + const u32 pixels = (unscaled_rect.GetHeight() - 1) * stride_tiled + unscaled_rect.GetWidth(); + + return {addr + BytesInPixels(pixel_offset), addr + BytesInPixels(pixel_offset + pixels)}; +} + +SurfaceInterval SurfaceParams::GetCopyableInterval(const Surface& src_surface) const { + SurfaceInterval result{}; + const auto valid_regions = + SurfaceRegions(GetInterval() & src_surface->GetInterval()) - src_surface->invalid_regions; + for (auto& valid_interval : valid_regions) { + const SurfaceInterval aligned_interval{ + addr + Common::AlignUp(boost::icl::first(valid_interval) - addr, + BytesInPixels(is_tiled ? 8 * 8 : 1)), + addr + Common::AlignDown(boost::icl::last_next(valid_interval) - addr, + BytesInPixels(is_tiled ? 8 * 8 : 1))}; + + if (BytesInPixels(is_tiled ? 8 * 8 : 1) > boost::icl::length(valid_interval) || + boost::icl::length(aligned_interval) == 0) { + continue; + } + + // Get the rectangle within aligned_interval + const u32 stride_bytes = BytesInPixels(stride) * (is_tiled ? 8 : 1); + SurfaceInterval rect_interval{ + addr + Common::AlignUp(boost::icl::first(aligned_interval) - addr, stride_bytes), + addr + Common::AlignDown(boost::icl::last_next(aligned_interval) - addr, stride_bytes), + }; + if (boost::icl::first(rect_interval) > boost::icl::last_next(rect_interval)) { + // 1 row + rect_interval = aligned_interval; + } else if (boost::icl::length(rect_interval) == 0) { + // 2 rows that do not make a rectangle, return the larger one + const SurfaceInterval row1{boost::icl::first(aligned_interval), + boost::icl::first(rect_interval)}; + const SurfaceInterval row2{boost::icl::first(rect_interval), + boost::icl::last_next(aligned_interval)}; + rect_interval = (boost::icl::length(row1) > boost::icl::length(row2)) ? row1 : row2; + } + + if (boost::icl::length(rect_interval) > boost::icl::length(result)) { + result = rect_interval; + } + } + return result; +} + +Common::Rectangle SurfaceParams::GetSubRect(const SurfaceParams& sub_surface) const { + const u32 begin_pixel_index = PixelsInBytes(sub_surface.addr - addr); + + if (is_tiled) { + const int x0 = (begin_pixel_index % (stride * 8)) / 8; + const int y0 = (begin_pixel_index / (stride * 8)) * 8; + // Top to bottom + return Common::Rectangle(x0, height - y0, x0 + sub_surface.width, + height - (y0 + sub_surface.height)); + } + + const int x0 = begin_pixel_index % stride; + const int y0 = begin_pixel_index / stride; + // Bottom to top + return Common::Rectangle(x0, y0 + sub_surface.height, x0 + sub_surface.width, y0); +} + +Common::Rectangle SurfaceParams::GetScaledSubRect(const SurfaceParams& sub_surface) const { + auto rect = GetSubRect(sub_surface); + rect.left = rect.left * res_scale; + rect.right = rect.right * res_scale; + rect.top = rect.top * res_scale; + rect.bottom = rect.bottom * res_scale; + return rect; +} + +bool SurfaceParams::ExactMatch(const SurfaceParams& other_surface) const { + return std::tie(other_surface.addr, other_surface.width, other_surface.height, + other_surface.stride, other_surface.pixel_format, other_surface.is_tiled) == + std::tie(addr, width, height, stride, pixel_format, is_tiled) && + pixel_format != PixelFormat::Invalid; +} + +bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const { + return sub_surface.addr >= addr && sub_surface.end <= end && + sub_surface.pixel_format == pixel_format && pixel_format != PixelFormat::Invalid && + sub_surface.is_tiled == is_tiled && + (sub_surface.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 && + (sub_surface.stride == stride || sub_surface.height <= (is_tiled ? 8u : 1u)) && + GetSubRect(sub_surface).right <= stride; +} + +bool SurfaceParams::CanExpand(const SurfaceParams& expanded_surface) const { + return pixel_format != PixelFormat::Invalid && pixel_format == expanded_surface.pixel_format && + addr <= expanded_surface.end && expanded_surface.addr <= end && + is_tiled == expanded_surface.is_tiled && stride == expanded_surface.stride && + (std::max(expanded_surface.addr, addr) - std::min(expanded_surface.addr, addr)) % + BytesInPixels(stride * (is_tiled ? 8 : 1)) == + 0; +} + +bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const { + if (pixel_format == PixelFormat::Invalid || addr > texcopy_params.addr || + end < texcopy_params.end) { + return false; + } + if (texcopy_params.width != texcopy_params.stride) { + const u32 tile_stride = BytesInPixels(stride * (is_tiled ? 8 : 1)); + return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 && + texcopy_params.width % BytesInPixels(is_tiled ? 64 : 1) == 0 && + (texcopy_params.height == 1 || texcopy_params.stride == tile_stride) && + ((texcopy_params.addr - addr) % tile_stride) + texcopy_params.width <= tile_stride; + } + return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval(); +} + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_surface_params.h b/src/video_core/renderer_opengl/gl_surface_params.h new file mode 100644 index 000000000..56d33e0d4 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_surface_params.h @@ -0,0 +1,229 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "common/assert.h" +#include "common/math_util.h" +#include "core/hw/gpu.h" +#include "video_core/regs_framebuffer.h" +#include "video_core/regs_texturing.h" + +namespace OpenGL { + +struct CachedSurface; +using Surface = std::shared_ptr; + +using SurfaceInterval = boost::icl::right_open_interval; + +struct SurfaceParams { +private: + static constexpr std::array BPP_TABLE = { + 32, // RGBA8 + 24, // RGB8 + 16, // RGB5A1 + 16, // RGB565 + 16, // RGBA4 + 16, // IA8 + 16, // RG8 + 8, // I8 + 8, // A8 + 8, // IA4 + 4, // I4 + 4, // A4 + 4, // ETC1 + 8, // ETC1A4 + 16, // D16 + 0, + 24, // D24 + 32, // D24S8 + }; + +public: + enum class PixelFormat { + // First 5 formats are shared between textures and color buffers + RGBA8 = 0, + RGB8 = 1, + RGB5A1 = 2, + RGB565 = 3, + RGBA4 = 4, + + // Texture-only formats + IA8 = 5, + RG8 = 6, + I8 = 7, + A8 = 8, + IA4 = 9, + I4 = 10, + A4 = 11, + ETC1 = 12, + ETC1A4 = 13, + + // Depth buffer-only formats + D16 = 14, + // gap + D24 = 16, + D24S8 = 17, + + Invalid = 255, + }; + + enum class SurfaceType { + Color = 0, + Texture = 1, + Depth = 2, + DepthStencil = 3, + Fill = 4, + Invalid = 5 + }; + + static constexpr unsigned int GetFormatBpp(PixelFormat format) { + const auto format_idx = static_cast(format); + DEBUG_ASSERT_MSG(format_idx < BPP_TABLE.size(), "Invalid pixel format {}", format_idx); + return BPP_TABLE[format_idx]; + } + + unsigned int GetFormatBpp() const { + return GetFormatBpp(pixel_format); + } + + static PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) { + return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; + } + + static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) { + return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; + } + + static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) { + return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) + : PixelFormat::Invalid; + } + + static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) { + switch (format) { + // RGB565 and RGB5A1 are switched in PixelFormat compared to ColorFormat + case GPU::Regs::PixelFormat::RGB565: + return PixelFormat::RGB565; + case GPU::Regs::PixelFormat::RGB5A1: + return PixelFormat::RGB5A1; + default: + return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; + } + } + + static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { + SurfaceType a_type = GetFormatType(pixel_format_a); + SurfaceType b_type = GetFormatType(pixel_format_b); + + if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && + (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { + return true; + } + + if (a_type == SurfaceType::Depth && b_type == SurfaceType::Depth) { + return true; + } + + if (a_type == SurfaceType::DepthStencil && b_type == SurfaceType::DepthStencil) { + return true; + } + + return false; + } + + static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) { + if ((unsigned int)pixel_format < 5) { + return SurfaceType::Color; + } + + if ((unsigned int)pixel_format < 14) { + return SurfaceType::Texture; + } + + if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) { + return SurfaceType::Depth; + } + + if (pixel_format == PixelFormat::D24S8) { + return SurfaceType::DepthStencil; + } + + return SurfaceType::Invalid; + } + + /// Update the params "size", "end" and "type" from the already set "addr", "width", "height" + /// and "pixel_format" + void UpdateParams() { + if (stride == 0) { + stride = width; + } + type = GetFormatType(pixel_format); + size = !is_tiled ? BytesInPixels(stride * (height - 1) + width) + : BytesInPixels(stride * 8 * (height / 8 - 1) + width * 8); + end = addr + size; + } + + SurfaceInterval GetInterval() const { + return SurfaceInterval(addr, end); + } + + // Returns the outer rectangle containing "interval" + SurfaceParams FromInterval(SurfaceInterval interval) const; + + SurfaceInterval GetSubRectInterval(Common::Rectangle unscaled_rect) const; + + // Returns the region of the biggest valid rectange within interval + SurfaceInterval GetCopyableInterval(const Surface& src_surface) const; + + u32 GetScaledWidth() const { + return width * res_scale; + } + + u32 GetScaledHeight() const { + return height * res_scale; + } + + Common::Rectangle GetRect() const { + return {0, height, width, 0}; + } + + Common::Rectangle GetScaledRect() const { + return {0, GetScaledHeight(), GetScaledWidth(), 0}; + } + + u32 PixelsInBytes(u32 size) const { + return size * CHAR_BIT / GetFormatBpp(pixel_format); + } + + u32 BytesInPixels(u32 pixels) const { + return pixels * GetFormatBpp(pixel_format) / CHAR_BIT; + } + + bool ExactMatch(const SurfaceParams& other_surface) const; + bool CanSubRect(const SurfaceParams& sub_surface) const; + bool CanExpand(const SurfaceParams& expanded_surface) const; + bool CanTexCopy(const SurfaceParams& texcopy_params) const; + + Common::Rectangle GetSubRect(const SurfaceParams& sub_surface) const; + Common::Rectangle GetScaledSubRect(const SurfaceParams& sub_surface) const; + + PAddr addr = 0; + PAddr end = 0; + u32 size = 0; + + u32 width = 0; + u32 height = 0; + u32 stride = 0; + u16 res_scale = 1; + + bool is_tiled = false; + PixelFormat pixel_format = PixelFormat::Invalid; + SurfaceType type = SurfaceType::Invalid; +}; + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index e7e0bb72f..5046895e0 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -32,7 +32,6 @@ #include "video_core/renderer_opengl/gl_vars.h" #include "video_core/renderer_opengl/post_processing_opengl.h" #include "video_core/renderer_opengl/renderer_opengl.h" -#include "video_core/renderer_opengl/texture_filters/texture_filter_manager.h" #include "video_core/video_core.h" namespace Frontend { @@ -1179,14 +1178,10 @@ VideoCore::ResultStatus RendererOpenGL::Init() { RefreshRasterizerSetting(); - TextureFilterManager::GetInstance().Reset(); - return VideoCore::ResultStatus::Success; } /// Shutdown the renderer -void RendererOpenGL::ShutDown() { - TextureFilterManager::GetInstance().Destroy(); -} +void RendererOpenGL::ShutDown() {} } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp b/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp index 86b4a85b6..b70cc14f4 100644 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp +++ b/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp @@ -42,18 +42,17 @@ namespace OpenGL { -Anime4kUltrafast::Anime4kUltrafast(u16 scale_factor) : TextureFilterInterface(scale_factor) { +Anime4kUltrafast::Anime4kUltrafast(u16 scale_factor) : TextureFilterBase(scale_factor) { const OpenGLState cur_state = OpenGLState::GetCurState(); - const auto setup_temp_tex = [this, scale_factor](TempTex& texture, GLint internal_format, - GLint format) { + const auto setup_temp_tex = [this](TempTex& texture, GLint internal_format, GLint format) { texture.fbo.Create(); texture.tex.Create(); state.draw.draw_framebuffer = texture.fbo.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_RECTANGLE, texture.tex.handle); - glTexImage2D(GL_TEXTURE_RECTANGLE, 0, internal_format, 1024 * scale_factor, - 1024 * scale_factor, 0, format, GL_HALF_FLOAT, nullptr); + glTexImage2D(GL_TEXTURE_RECTANGLE, 0, internal_format, 1024 * internal_scale_factor, + 1024 * internal_scale_factor, 0, format, GL_HALF_FLOAT, nullptr); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, texture.tex.handle, 0); }; @@ -61,7 +60,6 @@ Anime4kUltrafast::Anime4kUltrafast(u16 scale_factor) : TextureFilterInterface(sc setup_temp_tex(XY, GL_RG16F, GL_RG); vao.Create(); - out_fbo.Create(); for (std::size_t idx = 0; idx < samplers.size(); ++idx) { samplers[idx].Create(); @@ -86,30 +84,26 @@ Anime4kUltrafast::Anime4kUltrafast(u16 scale_factor) : TextureFilterInterface(sc state.draw.shader_program = refine_program.handle; state.Apply(); glUniform1i(glGetUniformLocation(refine_program.handle, "LUMAD"), 1); + glUniform1f(glGetUniformLocation(refine_program.handle, "final_scale"), + static_cast(internal_scale_factor) / scale_factor); cur_state.Apply(); } -void Anime4kUltrafast::scale(CachedSurface& surface, const Common::Rectangle& rect, - std::size_t buffer_offset) { +void Anime4kUltrafast::Filter(GLuint src_tex, const Common::Rectangle& src_rect, + GLuint dst_tex, const Common::Rectangle& dst_rect, + GLuint read_fb_handle, GLuint draw_fb_handle) { const OpenGLState cur_state = OpenGLState::GetCurState(); - OGLTexture src_tex; - src_tex.Create(); - - state.viewport = RectToViewport(rect); - - state.texture_units[0].texture_2d = src_tex.handle; + state.viewport = {static_cast(src_rect.left * internal_scale_factor), + static_cast(src_rect.bottom * internal_scale_factor), + static_cast(src_rect.GetWidth() * internal_scale_factor), + static_cast(src_rect.GetHeight() * internal_scale_factor)}; + state.texture_units[0].texture_2d = src_tex; state.draw.draw_framebuffer = XY.fbo.handle; state.draw.shader_program = gradient_x_program.handle; state.Apply(); - const FormatTuple tuple = GetFormatTuple(surface.pixel_format); - glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast(surface.stride)); - glActiveTexture(GL_TEXTURE0); - glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, rect.GetWidth(), rect.GetHeight(), 0, - tuple.format, tuple.type, &surface.gl_buffer[buffer_offset]); - glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_RECTANGLE, LUMAD.tex.handle); glActiveTexture(GL_TEXTURE2); @@ -124,14 +118,17 @@ void Anime4kUltrafast::scale(CachedSurface& surface, const Common::Rectangle(dst_rect.left), static_cast(dst_rect.bottom), + static_cast(dst_rect.GetWidth()), + static_cast(dst_rect.GetHeight())}; + state.draw.draw_framebuffer = draw_fb_handle; state.draw.shader_program = refine_program.handle; state.Apply(); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - cur_state.texture_units[0].texture_2d, 0); + + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); cur_state.Apply(); } diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h b/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h index 79a058fd5..9e89da816 100644 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h +++ b/src/video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h @@ -6,29 +6,25 @@ #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_state.h" -#include "video_core/renderer_opengl/texture_filters/texture_filter_interface.h" +#include "video_core/renderer_opengl/texture_filters/texture_filter_base.h" namespace OpenGL { -class Anime4kUltrafast : public TextureFilterInterface { +class Anime4kUltrafast : public TextureFilterBase { public: - static TextureFilterInfo GetInfo() { - TextureFilterInfo info; - info.name = "Anime4K Ultrafast"; - info.clamp_scale = {2, 2}; - info.constructor = std::make_unique; - return info; - } + static constexpr std::string_view NAME = "Anime4K Ultrafast"; - Anime4kUltrafast(u16 scale_factor); - void scale(CachedSurface& surface, const Common::Rectangle& rect, - std::size_t buffer_offset) override; + explicit Anime4kUltrafast(u16 scale_factor); + void Filter(GLuint src_tex, const Common::Rectangle& src_rect, GLuint dst_tex, + const Common::Rectangle& dst_rect, GLuint read_fb_handle, + GLuint draw_fb_handle) override; private: + static constexpr u8 internal_scale_factor = 2; + OpenGLState state{}; OGLVertexArray vao; - OGLFramebuffer out_fbo; struct TempTex { OGLTexture tex; diff --git a/src/video_core/renderer_opengl/texture_filters/anime4k/refine.frag b/src/video_core/renderer_opengl/texture_filters/anime4k/refine.frag index 26f2526ba..4417b96f6 100644 --- a/src/video_core/renderer_opengl/texture_filters/anime4k/refine.frag +++ b/src/video_core/renderer_opengl/texture_filters/anime4k/refine.frag @@ -8,6 +8,8 @@ uniform sampler2D HOOKED; uniform sampler2DRect LUMAD; uniform sampler2DRect LUMAG; +uniform float final_scale; + const float LINE_DETECT_THRESHOLD = 0.4; const float STRENGTH = 0.6; @@ -24,7 +26,7 @@ vec4 getAverage(vec4 cc, vec4 a, vec4 b, vec4 c) { #define GetRGBAL(offset) \ RGBAL(textureOffset(HOOKED, tex_coord, offset), \ - texture(LUMAD, clamp(gl_FragCoord.xy + offset, vec2(0.0), input_max)).x) + texture(LUMAD, clamp((gl_FragCoord.xy + offset) * final_scale, vec2(0.0), input_max)).x) float min3v(float a, float b, float c) { return min(min(a, b), c); diff --git a/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.cpp b/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.cpp index 6c0bc1f82..ce039c211 100644 --- a/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.cpp +++ b/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.cpp @@ -10,45 +10,36 @@ namespace OpenGL { -Bicubic::Bicubic(u16 scale_factor) : TextureFilterInterface(scale_factor) { +Bicubic::Bicubic(u16 scale_factor) : TextureFilterBase(scale_factor) { program.Create(tex_coord_vert.data(), bicubic_frag.data()); vao.Create(); - draw_fbo.Create(); src_sampler.Create(); state.draw.shader_program = program.handle; state.draw.vertex_array = vao.handle; state.draw.shader_program = program.handle; - state.draw.draw_framebuffer = draw_fbo.handle; state.texture_units[0].sampler = src_sampler.handle; glSamplerParameteri(src_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glSamplerParameteri(src_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(src_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glSamplerParameteri(src_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} +} // namespace OpenGL -void Bicubic::scale(CachedSurface& surface, const Common::Rectangle& rect, - std::size_t buffer_offset) { +void Bicubic::Filter(GLuint src_tex, const Common::Rectangle& src_rect, GLuint dst_tex, + const Common::Rectangle& dst_rect, GLuint read_fb_handle, + GLuint draw_fb_handle) { const OpenGLState cur_state = OpenGLState::GetCurState(); - - OGLTexture src_tex; - src_tex.Create(); - state.texture_units[0].texture_2d = src_tex.handle; - - state.viewport = RectToViewport(rect); + state.texture_units[0].texture_2d = src_tex; + state.draw.draw_framebuffer = draw_fb_handle; + state.viewport = {static_cast(dst_rect.left), static_cast(dst_rect.bottom), + static_cast(dst_rect.GetWidth()), + static_cast(dst_rect.GetHeight())}; state.Apply(); - const FormatTuple tuple = GetFormatTuple(surface.pixel_format); - glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast(surface.stride)); - glActiveTexture(GL_TEXTURE0); - glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, rect.GetWidth(), rect.GetHeight(), 0, - tuple.format, tuple.type, &surface.gl_buffer[buffer_offset]); - - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - cur_state.texture_units[0].texture_2d, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); cur_state.Apply(); } diff --git a/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.h b/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.h index a16bdafcf..b982cc973 100644 --- a/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.h +++ b/src/video_core/renderer_opengl/texture_filters/bicubic/bicubic.h @@ -6,27 +6,24 @@ #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_state.h" -#include "video_core/renderer_opengl/texture_filters/texture_filter_interface.h" +#include "video_core/renderer_opengl/texture_filters/texture_filter_base.h" namespace OpenGL { -class Bicubic : public TextureFilterInterface { -public: - static TextureFilterInfo GetInfo() { - TextureFilterInfo info; - info.name = "Bicubic"; - info.constructor = std::make_unique; - return info; - } - Bicubic(u16 scale_factor); - void scale(CachedSurface& surface, const Common::Rectangle& rect, - std::size_t buffer_offset) override; +class Bicubic : public TextureFilterBase { +public: + static constexpr std::string_view NAME = "Bicubic"; + + explicit Bicubic(u16 scale_factor); + void Filter(GLuint src_tex, const Common::Rectangle& src_rect, GLuint dst_tex, + const Common::Rectangle& dst_rect, GLuint read_fb_handle, + GLuint draw_fb_handle) override; private: OpenGLState state{}; OGLProgram program{}; OGLVertexArray vao{}; - OGLFramebuffer draw_fbo{}; OGLSampler src_sampler{}; }; + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/texture_filters/texture_filter_base.h b/src/video_core/renderer_opengl/texture_filters/texture_filter_base.h new file mode 100644 index 000000000..126fdb108 --- /dev/null +++ b/src/video_core/renderer_opengl/texture_filters/texture_filter_base.h @@ -0,0 +1,26 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "common/math_util.h" +#include "video_core/renderer_opengl/gl_surface_params.h" + +namespace OpenGL { + +class TextureFilterBase { + friend class TextureFilterer; + virtual void Filter(GLuint src_tex, const Common::Rectangle& src_rect, GLuint dst_tex, + const Common::Rectangle& dst_rect, GLuint read_fb_handle, + GLuint draw_fb_handle) = 0; + +public: + explicit TextureFilterBase(u16 scale_factor) : scale_factor{scale_factor} {}; + virtual ~TextureFilterBase() = default; + + const u16 scale_factor{}; +}; + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/texture_filters/texture_filter_interface.h b/src/video_core/renderer_opengl/texture_filters/texture_filter_interface.h deleted file mode 100644 index c2bf2a686..000000000 --- a/src/video_core/renderer_opengl/texture_filters/texture_filter_interface.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "common/common_types.h" -#include "common/math_util.h" - -namespace OpenGL { - -struct CachedSurface; -struct Viewport; - -class TextureFilterInterface { -public: - const u16 scale_factor{}; - TextureFilterInterface(u16 scale_factor) : scale_factor{scale_factor} {} - virtual void scale(CachedSurface& surface, const Common::Rectangle& rect, - std::size_t buffer_offset) = 0; - virtual ~TextureFilterInterface() = default; - -protected: - Viewport RectToViewport(const Common::Rectangle& rect); -}; - -// every texture filter should have a static GetInfo function -struct TextureFilterInfo { - std::string_view name; - struct { - u16 min, max; - } clamp_scale{1, 10}; - std::function(u16 scale_factor)> constructor; -}; - -} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/texture_filters/texture_filter_manager.cpp b/src/video_core/renderer_opengl/texture_filters/texture_filter_manager.cpp deleted file mode 100644 index 77d07111e..000000000 --- a/src/video_core/renderer_opengl/texture_filters/texture_filter_manager.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" -#include "video_core/renderer_opengl/gl_state.h" -#include "video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h" -#include "video_core/renderer_opengl/texture_filters/bicubic/bicubic.h" -#include "video_core/renderer_opengl/texture_filters/texture_filter_manager.h" -#include "video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.h" - -namespace OpenGL { - -Viewport TextureFilterInterface::RectToViewport(const Common::Rectangle& rect) { - return { - static_cast(rect.left) * scale_factor, - static_cast(rect.top) * scale_factor, - static_cast(rect.GetWidth()) * scale_factor, - static_cast(rect.GetHeight()) * scale_factor, - }; -} - -namespace { -template -std::pair FilterMapPair() { - return {T::GetInfo().name, T::GetInfo()}; -}; - -struct NoFilter { - static TextureFilterInfo GetInfo() { - TextureFilterInfo info; - info.name = TextureFilterManager::NONE; - info.clamp_scale = {1, 1}; - info.constructor = [](u16) { return nullptr; }; - return info; - } -}; -} // namespace - -const std::map& -TextureFilterManager::TextureFilterMap() { - static const std::map filter_map{ - FilterMapPair(), - FilterMapPair(), - FilterMapPair(), - FilterMapPair(), - }; - return filter_map; -} - -void TextureFilterManager::SetTextureFilter(std::string filter_name, u16 new_scale_factor) { - if (name == filter_name && scale_factor == new_scale_factor) - return; - std::lock_guard lock{mutex}; - name = std::move(filter_name); - scale_factor = new_scale_factor; - updated = true; -} - -TextureFilterInterface* TextureFilterManager::GetTextureFilter() const { - return filter.get(); -} - -bool TextureFilterManager::IsUpdated() const { - return updated; -} - -void TextureFilterManager::Reset() { - std::lock_guard lock{mutex}; - updated = false; - auto iter = TextureFilterMap().find(name); - if (iter == TextureFilterMap().end()) { - LOG_ERROR(Render_OpenGL, "Invalid texture filter: {}", name); - filter = nullptr; - return; - } - - const auto& filter_info = iter->second; - - u16 clamped_scale = - std::clamp(scale_factor, filter_info.clamp_scale.min, filter_info.clamp_scale.max); - if (clamped_scale != scale_factor) - LOG_ERROR(Render_OpenGL, "Invalid scale factor {} for texture filter {}, clamped to {}", - scale_factor, filter_info.name, clamped_scale); - - filter = filter_info.constructor(clamped_scale); -} - -} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/texture_filters/texture_filter_manager.h b/src/video_core/renderer_opengl/texture_filters/texture_filter_manager.h deleted file mode 100644 index 1299a9151..000000000 --- a/src/video_core/renderer_opengl/texture_filters/texture_filter_manager.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include "video_core/renderer_opengl/texture_filters/texture_filter_interface.h" - -namespace OpenGL { - -class TextureFilterManager { -public: - static constexpr std::string_view NONE = "none"; - struct FilterNameComp { - bool operator()(const std::string_view a, const std::string_view b) const { - bool na = a == NONE; - bool nb = b == NONE; - if (na | nb) - return na & !nb; - return a < b; - } - }; - // function ensures map is initialized before use - static const std::map& TextureFilterMap(); - - static TextureFilterManager& GetInstance() { - static TextureFilterManager singleton; - return singleton; - } - - void Destroy() { - filter.reset(); - } - void SetTextureFilter(std::string filter_name, u16 new_scale_factor); - TextureFilterInterface* GetTextureFilter() const; - // returns true if filter has been changed and a cache reset is needed - bool IsUpdated() const; - void Reset(); - -private: - std::atomic updated{false}; - std::mutex mutex; - std::string name{"none"}; - u16 scale_factor{1}; - - std::unique_ptr filter; -}; - -} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/texture_filters/texture_filterer.cpp b/src/video_core/renderer_opengl/texture_filters/texture_filterer.cpp new file mode 100644 index 000000000..0afa6b876 --- /dev/null +++ b/src/video_core/renderer_opengl/texture_filters/texture_filterer.cpp @@ -0,0 +1,86 @@ +/// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include "common/logging/log.h" +#include "video_core/renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h" +#include "video_core/renderer_opengl/texture_filters/bicubic/bicubic.h" +#include "video_core/renderer_opengl/texture_filters/texture_filter_base.h" +#include "video_core/renderer_opengl/texture_filters/texture_filterer.h" +#include "video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.h" + +namespace OpenGL { + +namespace { + +using TextureFilterContructor = std::function(u16)>; + +template +std::pair FilterMapPair() { + return {T::NAME, std::make_unique}; +}; + +static const std::unordered_map filter_map{ + {TextureFilterer::NONE, [](u16) { return nullptr; }}, + FilterMapPair(), + FilterMapPair(), + FilterMapPair(), +}; + +} // namespace + +TextureFilterer::TextureFilterer(std::string_view filter_name, u16 scale_factor) { + Reset(filter_name, scale_factor); +} + +bool TextureFilterer::Reset(std::string_view new_filter_name, u16 new_scale_factor) { + if (filter_name == new_filter_name && (IsNull() || filter->scale_factor == new_scale_factor)) + return false; + + auto iter = filter_map.find(new_filter_name); + if (iter == filter_map.end()) { + LOG_ERROR(Render_OpenGL, "Invalid texture filter: {}", new_filter_name); + filter = nullptr; + return true; + } + + filter_name = iter->first; + filter = iter->second(new_scale_factor); + return true; +} + +bool TextureFilterer::IsNull() const { + return !filter; +} + +bool TextureFilterer::Filter(GLuint src_tex, const Common::Rectangle& src_rect, GLuint dst_tex, + const Common::Rectangle& dst_rect, + SurfaceParams::SurfaceType type, GLuint read_fb_handle, + GLuint draw_fb_handle) { + // depth / stencil texture filtering is not supported for now + if (IsNull() || + (type != SurfaceParams::SurfaceType::Color && type != SurfaceParams::SurfaceType::Texture)) + return false; + filter->Filter(src_tex, src_rect, dst_tex, dst_rect, read_fb_handle, draw_fb_handle); + return true; +} + +std::vector TextureFilterer::GetFilterNames() { + std::vector ret; + std::transform(filter_map.begin(), filter_map.end(), std::back_inserter(ret), + [](auto pair) { return pair.first; }); + std::sort(ret.begin(), ret.end(), [](std::string_view lhs, std::string_view rhs) { + // sort lexicographically with none at the top + bool lhs_is_none{lhs == NONE}; + bool rhs_is_none{rhs == NONE}; + if (lhs_is_none || rhs_is_none) + return lhs_is_none && !rhs_is_none; + return lhs < rhs; + }); + return ret; +} + +} // namespace OpenGL \ No newline at end of file diff --git a/src/video_core/renderer_opengl/texture_filters/texture_filterer.h b/src/video_core/renderer_opengl/texture_filters/texture_filterer.h new file mode 100644 index 000000000..de3666356 --- /dev/null +++ b/src/video_core/renderer_opengl/texture_filters/texture_filterer.h @@ -0,0 +1,39 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include "common/common_types.h" +#include "common/math_util.h" +#include "video_core/renderer_opengl/gl_surface_params.h" +#include "video_core/renderer_opengl/texture_filters/texture_filter_base.h" + +namespace OpenGL { + +class TextureFilterer { +public: + static constexpr std::string_view NONE = "none"; + + explicit TextureFilterer(std::string_view filter_name, u16 scale_factor); + // returns true if the filter actually changed + bool Reset(std::string_view new_filter_name, u16 new_scale_factor); + // returns true if there is no active filter + bool IsNull() const; + // returns true if the texture was able to be filtered + bool Filter(GLuint src_tex, const Common::Rectangle& src_rect, GLuint dst_tex, + const Common::Rectangle& dst_rect, SurfaceParams::SurfaceType type, + GLuint read_fb_handle, GLuint draw_fb_handle); + + static std::vector GetFilterNames(); + +private: + std::string_view filter_name = NONE; + std::unique_ptr filter; +}; + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.cpp b/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.cpp index 5e7c34d1d..b1dcefc03 100644 --- a/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.cpp +++ b/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.cpp @@ -48,12 +48,11 @@ namespace OpenGL { -XbrzFreescale::XbrzFreescale(u16 scale_factor) : TextureFilterInterface(scale_factor) { +XbrzFreescale::XbrzFreescale(u16 scale_factor) : TextureFilterBase(scale_factor) { const OpenGLState cur_state = OpenGLState::GetCurState(); program.Create(xbrz_freescale_vert.data(), xbrz_freescale_frag.data()); vao.Create(); - draw_fbo.Create(); src_sampler.Create(); state.draw.shader_program = program.handle; @@ -68,31 +67,24 @@ XbrzFreescale::XbrzFreescale(u16 scale_factor) : TextureFilterInterface(scale_fa cur_state.Apply(); state.draw.vertex_array = vao.handle; state.draw.shader_program = program.handle; - state.draw.draw_framebuffer = draw_fbo.handle; state.texture_units[0].sampler = src_sampler.handle; } -void XbrzFreescale::scale(CachedSurface& surface, const Common::Rectangle& rect, - std::size_t buffer_offset) { +void XbrzFreescale::Filter(GLuint src_tex, const Common::Rectangle& src_rect, GLuint dst_tex, + const Common::Rectangle& dst_rect, GLuint read_fb_handle, + GLuint draw_fb_handle) { const OpenGLState cur_state = OpenGLState::GetCurState(); - OGLTexture src_tex; - src_tex.Create(); - state.texture_units[0].texture_2d = src_tex.handle; - - state.viewport = RectToViewport(rect); + state.texture_units[0].texture_2d = src_tex; + state.draw.draw_framebuffer = draw_fb_handle; + state.viewport = {static_cast(dst_rect.left), static_cast(dst_rect.bottom), + static_cast(dst_rect.GetWidth()), + static_cast(dst_rect.GetHeight())}; state.Apply(); - const FormatTuple tuple = GetFormatTuple(surface.pixel_format); - glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast(surface.stride)); - glActiveTexture(GL_TEXTURE0); - glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, rect.GetWidth(), rect.GetHeight(), 0, - tuple.format, tuple.type, &surface.gl_buffer[buffer_offset]); - - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - cur_state.texture_units[0].texture_2d, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); cur_state.Apply(); } diff --git a/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.h b/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.h index aad10f308..02c6d5d7e 100644 --- a/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.h +++ b/src/video_core/renderer_opengl/texture_filters/xbrz/xbrz_freescale.h @@ -6,28 +6,23 @@ #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_state.h" -#include "video_core/renderer_opengl/texture_filters/texture_filter_interface.h" +#include "video_core/renderer_opengl/texture_filters/texture_filter_base.h" namespace OpenGL { -class XbrzFreescale : public TextureFilterInterface { +class XbrzFreescale : public TextureFilterBase { public: - static TextureFilterInfo GetInfo() { - TextureFilterInfo info; - info.name = "xBRZ freescale"; - info.constructor = std::make_unique; - return info; - } + static constexpr std::string_view NAME = "xBRZ freescale"; - XbrzFreescale(u16 scale_factor); - void scale(CachedSurface& surface, const Common::Rectangle& rect, - std::size_t buffer_offset) override; + explicit XbrzFreescale(u16 scale_factor); + void Filter(GLuint src_tex, const Common::Rectangle& src_rect, GLuint dst_tex, + const Common::Rectangle& dst_rect, GLuint read_fb_handle, + GLuint draw_fb_handle) override; private: OpenGLState state{}; OGLProgram program{}; OGLVertexArray vao{}; - OGLFramebuffer draw_fbo{}; OGLSampler src_sampler{}; }; } // namespace OpenGL diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index a7ed5fb9e..1748efcc6 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -26,6 +26,7 @@ std::atomic g_use_disk_shader_cache; std::atomic g_renderer_bg_color_update_requested; std::atomic g_renderer_sampler_update_requested; std::atomic g_renderer_shader_update_requested; +std::atomic g_texture_filter_update_requested; // Screenshot std::atomic g_renderer_screenshot_requested; void* g_screenshot_bits; diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index f11b67839..9951cd9a7 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h @@ -35,6 +35,7 @@ extern std::atomic g_use_disk_shader_cache; extern std::atomic g_renderer_bg_color_update_requested; extern std::atomic g_renderer_sampler_update_requested; extern std::atomic g_renderer_shader_update_requested; +extern std::atomic g_texture_filter_update_requested; // Screenshot extern std::atomic g_renderer_screenshot_requested; extern void* g_screenshot_bits;