Implement Native Resolution Rescaling #2860
Conversation
2752580
to
77742bf
| @@ -772,6 +768,11 @@ void RasterizerOpenGL::DrawArrays() { | |||
| gpu.dirty.ResetVertexArrays(); | |||
| } | |||
|
|
|||
| bool res_scaling = texture_cache.IsResolutionScalingEnabled(); | |||
ReinUsesLisp
Sep 18, 2019
Contributor
const
const
| 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; |
ReinUsesLisp
Sep 18, 2019
Contributor
const and 1.0f
resolution_factor should be changed to be an integer, since we don't plan to support downscaling.
const and 1.0f
resolution_factor should be changed to be an integer, since we don't plan to support downscaling.
| 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; |
ReinUsesLisp
Sep 18, 2019
Contributor
Ditto.
Ditto.
| dst.y = src.min_y; | ||
| dst.width = width; | ||
| dst.height = height; | ||
| dst.x = src.min_x * factor; |
ReinUsesLisp
Sep 18, 2019
Contributor
If resolution_factor type is not changed, this will signal warnings about implicitly converting float to T, enclose with a static_cast<u32>(...)
If resolution_factor type is not changed, this will signal warnings about implicitly converting float to T, enclose with a static_cast<u32>(...)
| @@ -156,7 +156,7 @@ class RasterizerOpenGL : public VideoCore::RasterizerInterface { | |||
| 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); | |||
ReinUsesLisp
Sep 18, 2019
Contributor
Don't use an optional parameter here, it is be dangerous not to keep in mind that rescaling is enabled.
Don't use an optional parameter here, it is be dangerous not to keep in mind that rescaling is enabled.
| std::unordered_set<ResolutionKey> database; | ||
| std::unordered_set<ResolutionKey> blacklist; | ||
| bool initialized{}; | ||
| u64 title_id; |
ReinUsesLisp
Sep 18, 2019
Contributor
Zero initialize this with {}.
Zero initialize this with {}.
| for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||
| SetEmptyColorBuffer(i); | ||
| } | ||
|
|
||
| enable_resolution_scaling = | ||
| Settings::values.resolution_factor != 1.0 && !Settings::values.use_resolution_scanner; |
ReinUsesLisp
Sep 18, 2019
Contributor
Change 1.0 to 1 if resolution_factor type is changed, otherwise use 1.0f instead.
Change 1.0 to 1 if resolution_factor type is changed, otherwise use 1.0f instead.
| // Must be called by child's create surface | ||
| void SignalCreatedSurface(TSurface& new_surface) { | ||
| if (EnabledRescaling()) { | ||
| if (IsInRSDatabase(new_surface)) { |
ReinUsesLisp
Sep 18, 2019
Contributor
Use && with the previous ìf
Use && with the previous ìf
| @@ -567,6 +567,10 @@ void Config::ReadRendererValues() { | |||
| ReadSetting(QStringLiteral("use_accurate_gpu_emulation"), false).toBool(); | |||
| Settings::values.use_asynchronous_gpu_emulation = | |||
| ReadSetting(QStringLiteral("use_asynchronous_gpu_emulation"), false).toBool(); | |||
| Settings::values.use_resolution_scanner = | |||
| ReadSetting(QStringLiteral("use_resolution_scanner"), false).toBool(); | |||
| Settings::values.use_resolution_scanner = | |||
ReinUsesLisp
Sep 18, 2019
Contributor
Rebase typo? This is being set twice.
Rebase typo? This is being set twice.
| // OS we just open the transferable shader cache folder without preselecting the transferable | ||
| // shader cache file for the selected game. | ||
| #if defined(Q_OS_WIN) | ||
| const QString explorer = QStringLiteral("explorer"); |
ReinUsesLisp
Sep 18, 2019
Contributor
We should have a function for doing this. This code is copied and pasted from somewhere else.
We should have a function for doing this. This code is copied and pasted from somewhere else.
|
I dislike using uniform constants, but it's the sanest solution we have. |
| std::unordered_set<ResolutionKey> database; | ||
| std::unordered_set<ResolutionKey> blacklist; | ||
| std::unordered_set<ResolutionKey> database{}; | ||
| std::unordered_set<ResolutionKey> blacklist{}; |
ReinUsesLisp
Sep 19, 2019
Contributor
These {} are not needed. std::unordered_set has a constructor.
These {} are not needed. std::unordered_set has a constructor.
| using Tegra::Engines::Maxwell3D; | ||
| using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
|
|
||
| enum ProgramLocations : u32 { |
lioncash
Sep 19, 2019
Contributor
This can be relocated into UpdateConstants to keep their scope to their only usage area.
This can be relocated into UpdateConstants to keep their scope to their only usage area.
| const GLfloat rescale_factor = rescaling ? Settings::values.resolution_factor : 1.0f; | ||
|
|
||
| for (const auto stage : | ||
| std::array{current_state.vertex, current_state.geometry, current_state.fragment}) { |
lioncash
Sep 19, 2019
Contributor
You should be able to do this with a normal initializer list like:
Suggested change
std::array{current_state.vertex, current_state.geometry, current_state.fragment}) {
for (const auto stage : {current_state.vertex, current_state.geometry, current_state.fragment}) {
You should be able to do this with a normal initializer list like:
| std::array{current_state.vertex, current_state.geometry, current_state.fragment}) { | |
| for (const auto stage : {current_state.vertex, current_state.geometry, current_state.fragment}) { |
| struct { | ||
| GLuint instance_id; | ||
| GLuint flip_stage; | ||
| GLfloat y_direction; |
lioncash
Sep 19, 2019
Contributor
It's undefined behavior to access this and the rescaling factor if any of the other fields are accessed, since they don't have a common type.
It's undefined behavior to access this and the rescaling factor if any of the other fields are accessed, since they don't have a common type.
| return FileUtil::GetUserPath(FileUtil::UserPath::RescalingDir); | ||
| } | ||
|
|
||
| ScalingDatabase::ScalingDatabase(Core::System& system) : database{}, blacklist{}, system{system} { |
lioncash
Sep 19, 2019
Contributor
Suggested change
ScalingDatabase::ScalingDatabase(Core::System& system) : database{}, blacklist{}, system{system} {
ScalingDatabase::ScalingDatabase(Core::System& system) : system{system} {
These types already have a constructor
| ScalingDatabase::ScalingDatabase(Core::System& system) : database{}, blacklist{}, system{system} { | |
| ScalingDatabase::ScalingDatabase(Core::System& system) : system{system} { |
These types already have a constructor
| } | ||
|
|
||
| ScalingDatabase::ScalingDatabase(Core::System& system) : database{}, blacklist{}, system{system} { | ||
| title_id = 0; |
lioncash
Sep 19, 2019
Contributor
This is already initialized within the class declaration itself, so it can be removed.
This is already initialized within the class declaration itself, so it can be removed.
| void Init(); | ||
|
|
||
| bool IsInDatabase(const PixelFormat format, const u32 width, const u32 height) { | ||
| ResolutionKey key{format, width, height}; |
lioncash
Sep 19, 2019
Contributor
This can be a const member function.
This can be a const member function.
| return database.count(key) > 0; | ||
| } | ||
|
|
||
| bool IsBlacklisted(const PixelFormat format, const u32 width, const u32 height) { |
lioncash
Sep 19, 2019
Contributor
Ditto
Ditto
| return enable_resolution_scaling; | ||
| } | ||
|
|
||
| bool IsResScannerEnabled() const { |
lioncash
Sep 19, 2019
Contributor
Suggested change
bool IsResScannerEnabled() const {
bool IsResolutionScannerEnabled() const {
Res is easily confused with other names (e.g. Resource), It's also inconsistent with naming elsewhere in the codebase (IsResolutionScalingEnabled, etc)
| bool IsResScannerEnabled() const { | |
| bool IsResolutionScannerEnabled() const { |
Res is easily confused with other names (e.g. Resource), It's also inconsistent with naming elsewhere in the codebase (IsResolutionScalingEnabled, etc)
| scaling_database.Register(params.pixel_format, params.width, params.height); | ||
| } | ||
|
|
||
| bool IsRSBlacklisted(const TSurface& surface) { |
lioncash
Sep 19, 2019
Contributor
This can be a const member function
This can be a const member function
| return scaling_database.IsBlacklisted(params.pixel_format, params.width, params.height); | ||
| } | ||
|
|
||
| bool IsInRSDatabase(const TSurface& surface) { |
lioncash
Sep 19, 2019
Contributor
Ditto
Ditto
|
Reminder to address issues @FernandoS27 |
8afd738
to
552f4a8
|
@ogniK5377 Done, a few things weren't possible due to the lack of flexibility in json API. |
552f4a8
to
f510aba
95116e5
to
e6ab6eb
e6ab6eb
to
8cf23ad
…s scaling on imasge blit, image copy and buffer copy
Explicit locations break Intel and AMD's proprietary drivers. Use glGetUniformLocation and implicit locations instead.
8cf23ad
to
4096dc7
|
Wondering why this was never merged? |
Read the PSA here: https://yuzu-emu.org/help/feature/resolution-rescaler/ |
Native Resolution Rescaling in Emulators used to be an almost trivial process for old console GPUs where only 1 render target existed, memory wasn't unified (in the GPU sense, not on SoC sense) and textures weren't anywhere as complex as they are now. Native Resolution Rescaling for a modern GPU as Maxwell 2nd Gen is quite a challenge due to many factors: More complex texture types can be partially or entirely rendered onto: Cube textures, Array Textures, 3d Textures, etc; 8 different render targets with shared viewports and scissor tests, unified memories with uncalled readbacks and hardcoded shaders created for fixed resolutions (glFragCoord & TexelFetch). This PR introduces a set of heuristics and mechanisms to detect possible candidate render targets for rescaling based on a simple evolutive AI algorithm and performs render target rescaling based on a generated database of rescalable rendertargets (rescale profile) plus its corrections on state and shader code.