Texture_Cache: Initial Implementation of Resolution Scaling

This commit is contained in:
Fernando Sahmkow
2019-07-06 15:13:26 -04:00
committed by FernandoS27
parent b9f21e44ad
commit e1a86c2abc
7 changed files with 168 additions and 21 deletions

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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