Texture_Cache: Initial Implementation of Resolution Scaling
This commit is contained in:
committed by
FernandoS27
parent
b9f21e44ad
commit
e1a86c2abc
@@ -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<size_t>(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<s32> 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<size_t>(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<u8>& 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<u8>& 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<CachedSurface>(gpu_addr, params);
|
||||
Surface new_surface = std::make_shared<CachedSurface>(gpu_addr, params);
|
||||
SignalCreatedSurface(new_surface);
|
||||
new_surface->Init();
|
||||
return new_surface;
|
||||
}
|
||||
|
||||
void TextureCacheOpenGL::ImageCopy(Surface& src_surface, Surface& dst_surface,
|
||||
|
||||
@@ -39,6 +39,8 @@ public:
|
||||
explicit CachedSurface(GPUVAddr gpu_addr, const SurfaceParams& params);
|
||||
~CachedSurface();
|
||||
|
||||
void Init();
|
||||
|
||||
void UploadTexture(const std::vector<u8>& staging_buffer) override;
|
||||
void DownloadTexture(std::vector<u8>& staging_buffer) override;
|
||||
|
||||
|
||||
68
src/video_core/texture_cache/resolution_scaling/database.h
Normal file
68
src/video_core/texture_cache/resolution_scaling/database.h
Normal file
@@ -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 <unordered_set>
|
||||
#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<std::size_t>(format) << 44;
|
||||
const std::size_t comp2 = static_cast<std::size_t>(height) << 24;
|
||||
const std::size_t comp3 = static_cast<std::size_t>(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<VideoCommon::Resolution::ResolutionKey> {
|
||||
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<ResolutionKey> database;
|
||||
};
|
||||
|
||||
} // namespace VideoCommon::Resolution
|
||||
@@ -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{};
|
||||
};
|
||||
|
||||
@@ -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<std::size_t>(format)];
|
||||
}
|
||||
@@ -972,6 +1020,8 @@ private:
|
||||
|
||||
StagingCache staging_cache;
|
||||
std::recursive_mutex mutex;
|
||||
|
||||
Resolution::ScalingDatabase scaling_database;
|
||||
};
|
||||
|
||||
} // namespace VideoCommon
|
||||
|
||||
Reference in New Issue
Block a user