diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index ef4a745b57..c05518216b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -421,7 +421,6 @@ void RasterizerOpenGL::ConfigureFramebuffers() { texture_cache.GuardRenderTargets(false); state.draw.draw_framebuffer = framebuffer_cache.GetFramebuffer(fbkey); - SyncViewport(state); } void RasterizerOpenGL::ConfigureClearFramebuffer(OpenGLState& current_state, bool using_color_fb, @@ -547,9 +546,11 @@ void RasterizerOpenGL::Clear() { ConfigureClearFramebuffer(clear_state, use_color, use_depth, use_stencil); - SyncViewport(clear_state); + bool res_scaling = texture_cache.IsResolutionScalingEnabled(); + + SyncViewport(clear_state, res_scaling); if (regs.clear_flags.scissor) { - SyncScissorTest(clear_state); + SyncScissorTest(clear_state, res_scaling); } if (regs.clear_flags.viewport) { @@ -584,7 +585,6 @@ void RasterizerOpenGL::DrawPrelude() { SyncLogicOpState(); SyncCullMode(); SyncPrimitiveRestart(); - SyncScissorTest(state); SyncTransformFeedback(); SyncPointState(); SyncPolygonOffset(); @@ -641,6 +641,10 @@ void RasterizerOpenGL::DrawPrelude() { gpu.dirty.ResetVertexArrays(); } + bool res_scaling = texture_cache.IsResolutionScalingEnabled(); + SyncViewport(state, res_scaling); + SyncScissorTest(state, res_scaling); + shader_program_manager->SetConstants(gpu); shader_program_manager->ApplyTo(state); state.Apply(); @@ -1063,20 +1067,21 @@ void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& t state.images[binding] = view->GetTexture(); } -void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { +void RasterizerOpenGL::SyncViewport(OpenGLState& current_state, bool rescaling) { const auto& regs = system.GPU().Maxwell3D().regs; const bool geometry_shaders_enabled = regs.IsShaderConfigEnabled(static_cast(Maxwell::ShaderProgram::Geometry)); const std::size_t viewport_count = geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; + float factor = rescaling ? Settings::values.resolution_factor : 1.0; for (std::size_t i = 0; i < viewport_count; i++) { auto& viewport = current_state.viewports[i]; const auto& src = regs.viewports[i]; const Common::Rectangle viewport_rect{regs.viewport_transform[i].GetRect()}; - viewport.x = viewport_rect.left; - viewport.y = viewport_rect.bottom; - viewport.width = viewport_rect.GetWidth(); - viewport.height = viewport_rect.GetHeight(); + viewport.x = viewport_rect.left * factor; + viewport.y = viewport_rect.bottom * factor; + viewport.width = viewport_rect.GetWidth() * factor; + viewport.height = viewport_rect.GetHeight() * factor; viewport.depth_range_far = src.depth_range_far; viewport.depth_range_near = src.depth_range_near; } @@ -1287,12 +1292,13 @@ void RasterizerOpenGL::SyncLogicOpState() { state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); } -void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { +void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state, bool rescaling) { const auto& regs = system.GPU().Maxwell3D().regs; const bool geometry_shaders_enabled = regs.IsShaderConfigEnabled(static_cast(Maxwell::ShaderProgram::Geometry)); const std::size_t viewport_count = geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; + float factor = rescaling ? Settings::values.resolution_factor : 1.0; for (std::size_t i = 0; i < viewport_count; i++) { const auto& src = regs.scissor_test[i]; auto& dst = current_state.viewports[i].scissor; @@ -1302,10 +1308,10 @@ void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { } const u32 width = src.max_x - src.min_x; const u32 height = src.max_y - src.min_y; - dst.x = src.min_x; - dst.y = src.min_y; - dst.width = width; - dst.height = height; + dst.x = src.min_x * factor; + dst.y = src.min_y * factor; + dst.width = width * factor; + dst.height = height * factor; } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 9c10ebda36..0ca7833e14 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -128,7 +128,7 @@ private: const GLShader::ImageEntry& entry); /// Syncs the viewport and depth range to match the guest state - void SyncViewport(OpenGLState& current_state); + void SyncViewport(OpenGLState& current_state, bool rescaling = false); /// Syncs the clip enabled status to match the guest state void SyncClipEnabled( @@ -162,7 +162,7 @@ private: void SyncMultiSampleState(); /// Syncs the scissor test state to match the guest state - void SyncScissorTest(OpenGLState& current_state); + void SyncScissorTest(OpenGLState& current_state, bool rescaling = false); /// Syncs the transform feedback state to match the guest state void SyncTransformFeedback(); diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 173b76c4ed..5f56fa86ad 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -199,7 +199,7 @@ void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { } OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum internal_format, - OGLBuffer& texture_buffer) { + OGLBuffer& texture_buffer, float resolution_factor) { OGLTexture texture; texture.Create(target); @@ -214,6 +214,9 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte glTextureBuffer(texture.handle, internal_format, texture_buffer.handle); break; case SurfaceTarget::Texture2D: + glTextureStorage2D(texture.handle, params.emulated_levels, internal_format, + params.width * resolution_factor, params.height * resolution_factor); + break; case SurfaceTarget::TextureCubemap: glTextureStorage2D(texture.handle, params.emulated_levels, internal_format, params.width, params.height); @@ -242,8 +245,12 @@ CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& param format = tuple.format; type = tuple.type; is_compressed = tuple.compressed; +} + +void CachedSurface::Init() { target = GetTextureTarget(params.target); - texture = CreateTexture(params, target, internal_format, texture_buffer); + float resolution_factor = IsRescaled() ? Settings::values.resolution_factor : 1.0; + texture = CreateTexture(params, target, internal_format, texture_buffer, resolution_factor); DecorateSurfaceName(); main_view = CreateViewInner( ViewParams(params.target, 0, params.is_layered ? params.depth : 1, 0, params.num_levels), @@ -325,6 +332,7 @@ void CachedSurface::UploadTextureMipmap(u32 level, const std::vector& stagin UNREACHABLE(); } } else { + float resolution_factor = IsRescaled() ? Settings::values.resolution_factor : 1.0; switch (params.target) { case SurfaceTarget::Texture1D: glTextureSubImage1D(texture.handle, level, 0, params.GetMipWidth(level), format, type, @@ -337,8 +345,9 @@ void CachedSurface::UploadTextureMipmap(u32 level, const std::vector& stagin break; case SurfaceTarget::Texture1DArray: case SurfaceTarget::Texture2D: - glTextureSubImage2D(texture.handle, level, 0, 0, params.GetMipWidth(level), - params.GetMipHeight(level), format, type, buffer); + glTextureSubImage2D( + texture.handle, level, 0, 0, params.GetMipWidth(level) * resolution_factor, + params.GetMipHeight(level) * resolution_factor, format, type, buffer); break; case SurfaceTarget::Texture3D: case SurfaceTarget::Texture2DArray: @@ -461,7 +470,10 @@ TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, TextureCacheOpenGL::~TextureCacheOpenGL() = default; Surface TextureCacheOpenGL::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { - return std::make_shared(gpu_addr, params); + Surface new_surface = std::make_shared(gpu_addr, params); + SignalCreatedSurface(new_surface); + new_surface->Init(); + return new_surface; } void TextureCacheOpenGL::ImageCopy(Surface& src_surface, Surface& dst_surface, diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 8e13ab38bb..138e8b88c0 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -39,6 +39,8 @@ public: explicit CachedSurface(GPUVAddr gpu_addr, const SurfaceParams& params); ~CachedSurface(); + void Init(); + void UploadTexture(const std::vector& staging_buffer) override; void DownloadTexture(std::vector& staging_buffer) override; diff --git a/src/video_core/texture_cache/resolution_scaling/database.h b/src/video_core/texture_cache/resolution_scaling/database.h new file mode 100644 index 0000000000..0d8c81844e --- /dev/null +++ b/src/video_core/texture_cache/resolution_scaling/database.h @@ -0,0 +1,68 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "video_core/surface.h" + +namespace VideoCommon::Resolution { + +using VideoCore::Surface::PixelFormat; + +struct ResolutionKey { + PixelFormat format; + u32 width; + u32 height; + std::size_t Hash() const { + const std::size_t comp1 = static_cast(format) << 44; + const std::size_t comp2 = static_cast(height) << 24; + const std::size_t comp3 = static_cast(width); + return comp1 | comp2 | comp3; + } + + bool operator==(const ResolutionKey& ks) const { + return std::tie(format, width, height) == std::tie(ks.format, ks.width, ks.height); + } +}; + +} // namespace VideoCommon::Resolution + +namespace std { + +template <> +struct hash { + std::size_t operator()(const VideoCommon::Resolution::ResolutionKey& k) const { + return k.Hash(); + } +}; + +} // namespace std + +namespace VideoCommon::Resolution { + +class ScalingDatabase { +public: + explicit ScalingDatabase() : database{} {} + + bool IsInDatabase(const PixelFormat format, const u32 width, const u32 height) { + ResolutionKey key{format, width, height}; + return database.count(key) > 0; + } + + void Register(const PixelFormat format, const u32 width, const u32 height) { + ResolutionKey key{format, width, height}; + database.insert(key); + } + + void Unregister(const PixelFormat format, const u32 width, const u32 height) { + ResolutionKey key{format, width, height}; + database.erase(key); + } + +private: + std::unordered_set database; +}; + +} // namespace VideoCommon::Resolution diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 5e497e49f8..d7fcc9de5f 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -205,6 +205,10 @@ public: index = index_; } + void MarkAsRescaled(const bool is_rescaled) { + this->is_rescaled = is_rescaled; + } + void MarkAsPicked(bool is_picked_) { is_picked = is_picked_; } @@ -226,6 +230,10 @@ public: return index; } + bool IsRescaled() const { + return is_rescaled; + } + bool IsRegistered() const { return is_registered; } @@ -318,6 +326,7 @@ private: bool is_target{}; bool is_registered{}; bool is_picked{}; + bool is_rescaled{}; u32 index{NO_RT}; u64 modification_tick{}; }; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index ca2da8f97b..fcd2ffe7fc 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -29,6 +29,7 @@ #include "video_core/rasterizer_interface.h" #include "video_core/surface.h" #include "video_core/texture_cache/copy_params.h" +#include "video_core/texture_cache/resolution_scaling/database.h" #include "video_core/texture_cache/surface_base.h" #include "video_core/texture_cache/surface_params.h" #include "video_core/texture_cache/surface_view.h" @@ -254,6 +255,39 @@ public: return ++ticks; } + bool IsResolutionScalingEnabled() const { + if (!EnabledRescaling()) { + return false; + } + u32 enabled_targets = 0; + u32 rescaled_targets = 0; + bool rescaling = false; + for (const auto& target : render_targets) { + if (target.target) { + enabled_targets++; + if (target.target->IsRescaled()) { + rescaling = true; + rescaled_targets++; + } + } + } + if (depth_buffer.target) { + enabled_targets++; + if (depth_buffer.target->IsRescaled()) { + rescaling = true; + rescaled_targets++; + } + } + if (rescaling) { + if (rescaled_targets != enabled_targets) { + LOG_CRITICAL(HW_GPU, "Rescaling Database is incorrectly set! Redo the database."); + return false; + } + return true; + } + return false; + } + protected: TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer) : system{system}, rasterizer{rasterizer} { @@ -353,6 +387,16 @@ protected: return GetSurface(gpu_addr, params, true, false); } + // Must be called by child's create surface + void SignalCreatedSurface(TSurface& new_surface) { + const auto& params = new_surface->GetSurfaceParams(); + if (guard_render_targets && EnabledRescaling()) { + if (scaling_database.IsInDatabase(params.pixel_format, params.width, params.height)) { + new_surface->MarkAsRescaled(true); + } + } + } + Core::System& system; private: @@ -924,6 +968,10 @@ private: return {}; } + bool EnabledRescaling() const { + return Settings::values.resolution_factor != 1.0; //|| Settings::values.res_scanning + } + constexpr PixelFormat GetSiblingFormat(PixelFormat format) const { return siblings_table[static_cast(format)]; } @@ -972,6 +1020,8 @@ private: StagingCache staging_cache; std::recursive_mutex mutex; + + Resolution::ScalingDatabase scaling_database; }; } // namespace VideoCommon