rsx/gl: Implement resolution scaling

rsx: Revise wpos calculation to take resolution scale into account
This commit is contained in:
kd-11 2017-09-26 16:24:43 +03:00
parent 47202d5839
commit 12ab03b0b5
14 changed files with 202 additions and 98 deletions

View file

@ -731,9 +731,9 @@ struct area_base
{ {
return{ x1 * size.width, y1 * size.height, x2 * size.width, y2 * size.height }; return{ x1 * size.width, y1 * size.height, x2 * size.width, y2 * size.height };
} }
constexpr area_base operator * (const T& value) const constexpr area_base operator * (const f32& value) const
{ {
return{ x1 * value, y1 * value, x2 * value, y2 * value }; return{ (T)(x1 * value), (T)(y1 * value), (T)(x2 * value), (T)(y2 * value) };
} }
template<typename NT> template<typename NT>

View file

@ -338,6 +338,12 @@ namespace glsl
OS << "{\n"; OS << "{\n";
OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n"; OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n";
OS << "}\n\n"; OS << "}\n\n";
OS << "vec4 get_wpos()\n";
OS << "{\n";
OS << " float abs_scale = abs(wpos_scale);\n";
OS << " return (gl_FragCoord * vec4(abs_scale, wpos_scale, 1., 1.)) + vec4(0., wpos_bias, 0., 0.);\n";
OS << "}\n\n";
} }
static void insert_fog_declaration(std::ostream& OS) static void insert_fog_declaration(std::ostream& OS)

View file

@ -167,6 +167,9 @@ public:
f32 fp_value; f32 fp_value;
}; };
program_buffer_patch_entry()
{}
program_buffer_patch_entry(f32& key, f32& value) program_buffer_patch_entry(f32& key, f32& value)
{ {
fp_key = key; fp_key = key;
@ -178,25 +181,43 @@ public:
hex_key = key; hex_key = key;
hex_value = value; hex_value = value;
} }
bool test_and_set(f32 value, f32* dst) const
{
u32 hex = (u32&)value;
if ((hex & 0x7FFFFFFF) == (hex_key & 0x7FFFFFFF))
{
hex = (hex & ~0x7FFFFFF) | hex_value;
*dst = (f32&)hex;
return true;
}
return false;
}
}; };
struct struct
{ {
std::vector<program_buffer_patch_entry> keys; std::unordered_map<f32, program_buffer_patch_entry> db;
void add(program_buffer_patch_entry& e) void add(program_buffer_patch_entry& e)
{ {
keys.push_back(e); db[e.fp_key] = e;
}
void add(f32& key, f32& value)
{
db[key] = { key, value };
} }
void clear() void clear()
{ {
keys.resize(0); db.clear();
} }
bool is_empty() const bool is_empty() const
{ {
return keys.size() == 0; return db.size() == 0;
} }
} }
patch_table; patch_table;
@ -287,49 +308,43 @@ public:
verify(HERE), (dst_buffer.size_bytes() >= ::narrow<int>(I->second.FragmentConstantOffsetCache.size()) * 16); verify(HERE), (dst_buffer.size_bytes() >= ::narrow<int>(I->second.FragmentConstantOffsetCache.size()) * 16);
size_t offset = 0; f32* dst = dst_buffer.data();
if (patch_table.is_empty()) f32 tmp[4];
for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache)
{ {
for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache) void *data = (char*)fragment_program.addr + (u32)offset_in_fragment_program;
const __m128i &vector = _mm_loadu_si128((__m128i*)data);
const __m128i &shuffled_vector = _mm_shuffle_epi8(vector, mask);
if (!patch_table.is_empty())
{ {
void *data = (char*)fragment_program.addr + (u32)offset_in_fragment_program; _mm_storeu_ps(tmp, (__m128&)shuffled_vector);
const __m128i &vector = _mm_loadu_si128((__m128i*)data);
const __m128i &shuffled_vector = _mm_shuffle_epi8(vector, mask);
_mm_stream_si128((__m128i*)dst_buffer.subspan(offset, 4).data(), shuffled_vector);
offset += 4;
}
}
else
{
for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache)
{
void *data = (char*)fragment_program.addr + (u32)offset_in_fragment_program;
f32* src = (f32*)data;
f32* dst = dst_buffer.subspan(offset, 4).data();
bool patched; bool patched;
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
patched = false; patched = false;
for (auto& e : patch_table.keys) for (auto& e : patch_table.db)
{ {
//TODO: Use fp comparison with fabsf without hurting performance //TODO: Use fp comparison with fabsf without hurting performance
if (e.hex_key == (u32&)src[i]) if (patched = e.second.test_and_set(tmp[i], &dst[i]))
{ {
dst[i] = e.fp_value;
patched = true;
break; break;
} }
} }
if (!patched) if (!patched)
{ {
dst[i] = src[i]; dst[i] = tmp[i];
} }
} }
offset += 4;
} }
else
{
_mm_stream_si128((__m128i*)dst, shuffled_vector);
}
dst += 4;
} }
} }

View file

@ -856,13 +856,14 @@ namespace rsx
return rsc.surface->get_view(); return rsc.surface->get_view();
} }
else else return create_temporary_subresource_view(cmd, rsc.surface, format, rsx::apply_resolution_scale(rsc.x, false), rsx::apply_resolution_scale(rsc.y, false),
return create_temporary_subresource_view(cmd, rsc.surface, format, rsc.x, rsc.y, rsc.w, rsc.h); rsx::apply_resolution_scale(rsc.w, true), rsx::apply_resolution_scale(rsc.h, true));
} }
else else
{ {
LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr); LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr);
return create_temporary_subresource_view(cmd, rsc.surface, format, rsc.x, rsc.y, rsc.w, rsc.h); return create_temporary_subresource_view(cmd, rsc.surface, format, rsx::apply_resolution_scale(rsc.x, false), rsx::apply_resolution_scale(rsc.y, false),
rsx::apply_resolution_scale(rsc.w, true), rsx::apply_resolution_scale(rsc.h, true));
} }
} }
} }
@ -1198,6 +1199,13 @@ namespace rsx
default_remap_vector)->get_raw_texture(); default_remap_vector)->get_raw_texture();
} }
const f32 scale = rsx::get_resolution_scale();
if (src_is_render_target)
src_area = src_area * scale;
if (dst_is_render_target)
dst_area = dst_area * scale;
blitter.scale_image(vram_texture, dest_texture, src_area, dst_area, interpolate, is_depth_blit); blitter.scale_image(vram_texture, dest_texture, src_area, dst_area, interpolate, is_depth_blit);
return true; return true;
} }

View file

@ -46,8 +46,8 @@ void D3D12FragmentDecompiler::insertHeader(std::stringstream & OS)
OS << " float alpha_ref;\n"; OS << " float alpha_ref;\n";
OS << " uint alpha_func;\n"; OS << " uint alpha_func;\n";
OS << " uint fog_mode;\n"; OS << " uint fog_mode;\n";
OS << " uint window_origin;\n"; OS << " float wpos_scale;\n";
OS << " uint window_height;\n"; OS << " float wpos_bias;\n";
OS << " float4 texture_parameters[16];\n"; OS << " float4 texture_parameters[16];\n";
OS << "};\n"; OS << "};\n";
} }
@ -224,8 +224,10 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
} }
} }
//NOTE: Framebuffer scaling not actually supported. wpos_scale is used to reconstruct the true window height
OS << " float4 wpos = In.Position;\n"; OS << " float4 wpos = In.Position;\n";
OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n"; OS << " float4 res_scale = abs(1.f / wpos_scale);\n";
OS << " if (wpos_scale < 0) wpos.y = (wpos_bias * res_scale) - wpos.y;\n";
OS << " float4 ssa = is_front_face ? float4(1., 1., 1., 1.) : float4(-1., -1., -1., -1.);\n"; OS << " float4 ssa = is_front_face ? float4(1., 1., 1., 1.) : float4(-1., -1., -1., -1.);\n";
// Declare output // Declare output

View file

@ -154,8 +154,8 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
OS << " float alpha_ref;\n"; OS << " float alpha_ref;\n";
OS << " uint alpha_func;\n"; OS << " uint alpha_func;\n";
OS << " uint fog_mode;\n"; OS << " uint fog_mode;\n";
OS << " uint window_origin;\n"; OS << " float wpos_scale;\n";
OS << " uint window_height;\n"; OS << " float wpos_bias;\n";
OS << " vec4 texture_parameters[16];\n"; //sampling: x,y scaling and (unused) offsets data OS << " vec4 texture_parameters[16];\n"; //sampling: x,y scaling and (unused) offsets data
OS << "};\n"; OS << "};\n";
} }
@ -251,8 +251,7 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
} }
OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n"; OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n";
OS << " vec4 wpos = gl_FragCoord;\n"; OS << " vec4 wpos = get_wpos();\n";
OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n";
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
{ {

View file

@ -589,14 +589,14 @@ void GLGSRender::end()
void GLGSRender::set_viewport() void GLGSRender::set_viewport()
{ {
//NOTE: scale offset matrix already contains the viewport transformation //NOTE: scale offset matrix already contains the viewport transformation
const auto clip_width = rsx::method_registers.surface_clip_width(); const auto clip_width = rsx::apply_resolution_scale(rsx::method_registers.surface_clip_width(), true);
const auto clip_height = rsx::method_registers.surface_clip_height(); const auto clip_height = rsx::apply_resolution_scale(rsx::method_registers.surface_clip_height(), true);
glViewport(0, 0, clip_width, clip_height); glViewport(0, 0, clip_width, clip_height);
u16 scissor_x = rsx::method_registers.scissor_origin_x(); u16 scissor_x = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_x(), false);
u16 scissor_w = rsx::method_registers.scissor_width(); u16 scissor_w = rsx::apply_resolution_scale(rsx::method_registers.scissor_width(), true);
u16 scissor_y = rsx::method_registers.scissor_origin_y(); u16 scissor_y = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_y(), false);
u16 scissor_h = rsx::method_registers.scissor_height(); u16 scissor_h = rsx::apply_resolution_scale(rsx::method_registers.scissor_height(), true);
//Do not bother drawing anything if output is zero sized //Do not bother drawing anything if output is zero sized
//TODO: Clip scissor region //TODO: Clip scissor region

View file

@ -3,6 +3,7 @@
#include "GLHelpers.h" #include "GLHelpers.h"
#include "stdafx.h" #include "stdafx.h"
#include "../RSXThread.h" #include "../RSXThread.h"
#include "../rsx_utils.h"
struct color_swizzle struct color_swizzle
{ {
@ -52,12 +53,14 @@ namespace gl
{ {
bool is_cleared = false; bool is_cleared = false;
u32 rsx_pitch = 0; u32 rsx_pitch = 0;
u16 native_pitch = 0; u16 native_pitch = 0;
u16 surface_height = 0; u16 internal_width = 0;
u16 surface_width = 0; u16 internal_height = 0;
u16 surface_pixel_size = 0; u16 surface_height = 0;
u16 surface_width = 0;
u16 surface_pixel_size = 0;
texture::internal_format compatible_internal_format = texture::internal_format::rgba8; texture::internal_format compatible_internal_format = texture::internal_format::rgba8;
@ -130,8 +133,16 @@ namespace gl
void update_surface() void update_surface()
{ {
surface_width = width(); internal_width = width();
surface_height = height(); internal_height = height();
surface_width = rsx::apply_inverse_resolution_scale(internal_width, true);
surface_height = rsx::apply_inverse_resolution_scale(internal_height, true);
}
bool matches_dimensions(u16 _width, u16 _height) const
{
//Use foward scaling to account for rounding and clamping errors
return (rsx::apply_resolution_scale(_width, true) == internal_width) && (rsx::apply_resolution_scale(_height, true) == internal_height);
} }
}; };
} }
@ -162,7 +173,7 @@ struct gl_render_target_traits
result->set_compatible_format(internal_fmt); result->set_compatible_format(internal_fmt);
__glcheck result->config() __glcheck result->config()
.size({ (int)width, (int)height }) .size({ (int)rsx::apply_resolution_scale((u16)width, true), (int)rsx::apply_resolution_scale((u16)height, true) })
.type(format.type) .type(format.type)
.format(format.format) .format(format.format)
.internal_format(internal_fmt) .internal_format(internal_fmt)
@ -195,8 +206,10 @@ struct gl_render_target_traits
auto format = rsx::internals::surface_depth_format_to_gl(surface_depth_format); auto format = rsx::internals::surface_depth_format_to_gl(surface_depth_format);
result->recreate(gl::texture::target::texture2D); result->recreate(gl::texture::target::texture2D);
const auto scale = rsx::get_resolution_scale();
__glcheck result->config() __glcheck result->config()
.size({ (int)width, (int)height }) .size({ (int)rsx::apply_resolution_scale((u16)width, true), (int)rsx::apply_resolution_scale((u16)height, true) })
.type(format.type) .type(format.type)
.format(format.format) .format(format.format)
.internal_format(format.internal_format) .internal_format(format.internal_format)
@ -247,7 +260,7 @@ struct gl_render_target_traits
return false; return false;
auto internal_fmt = rsx::internals::sized_internal_format(format); auto internal_fmt = rsx::internals::sized_internal_format(format);
return rtt->get_compatible_internal_format() == internal_fmt && rtt->width() == width && rtt->height() == height; return rtt->get_compatible_internal_format() == internal_fmt && rtt->matches_dimensions((u16)width, (u16)height);
} }
static static
@ -257,7 +270,7 @@ struct gl_render_target_traits
return false; return false;
// TODO: check format // TODO: check format
return rtt->width() == width && rtt->height() == height; return rtt->matches_dimensions((u16)width, (u16)height);
} }
// Note : pbo breaks fbo here so use classic texture copy // Note : pbo breaks fbo here so use classic texture copy

View file

@ -230,7 +230,7 @@ struct RSXFragmentProgram
bool front_color_specular_output : 1; bool front_color_specular_output : 1;
u32 texture_dimensions; u32 texture_dimensions;
float texture_pitch_scale[16]; std::array<float, 2> texture_scale[16];
u8 textures_alpha_kill[16]; u8 textures_alpha_kill[16];
u8 textures_zfunc[16]; u8 textures_zfunc[16];

View file

@ -8,11 +8,13 @@
#include "Common/BufferUtils.h" #include "Common/BufferUtils.h"
#include "rsx_methods.h" #include "rsx_methods.h"
#include "rsx_utils.h"
#include "Utilities/GSL.h" #include "Utilities/GSL.h"
#include "Utilities/StrUtil.h" #include "Utilities/StrUtil.h"
#include <thread> #include <thread>
#include <fenv.h>
class GSRender; class GSRender;
@ -391,6 +393,9 @@ namespace rsx
// Raise priority above other threads // Raise priority above other threads
thread_ctrl::set_native_priority(1); thread_ctrl::set_native_priority(1);
// Round to nearest to deal with forward/reverse scaling
fesetround(FE_TONEAREST);
// Deferred calls are used to batch draws together // Deferred calls are used to batch draws together
u32 deferred_primitive_type = 0; u32 deferred_primitive_type = 0;
u32 deferred_call_size = 0; u32 deferred_call_size = 0;
@ -790,24 +795,33 @@ namespace rsx
void thread::fill_fragment_state_buffer(void *buffer, const RSXFragmentProgram &fragment_program) void thread::fill_fragment_state_buffer(void *buffer, const RSXFragmentProgram &fragment_program)
{ {
const u32 is_alpha_tested = rsx::method_registers.alpha_test_enabled(); const u32 is_alpha_tested = rsx::method_registers.alpha_test_enabled();
const float alpha_ref = rsx::method_registers.alpha_ref() / 255.f; const f32 alpha_ref = rsx::method_registers.alpha_ref() / 255.f;
const f32 fog0 = rsx::method_registers.fog_params_0(); const f32 fog0 = rsx::method_registers.fog_params_0();
const f32 fog1 = rsx::method_registers.fog_params_1(); const f32 fog1 = rsx::method_registers.fog_params_1();
const u32 alpha_func = static_cast<u32>(rsx::method_registers.alpha_func()); const u32 alpha_func = static_cast<u32>(rsx::method_registers.alpha_func());
const u32 fog_mode = static_cast<u32>(rsx::method_registers.fog_equation()); const u32 fog_mode = static_cast<u32>(rsx::method_registers.fog_equation());
const u32 window_origin = static_cast<u32>(rsx::method_registers.shader_window_origin());
// Generate wpos coeffecients
// wpos equation is now as follows:
// wpos.y = (frag_coord / resolution_scale) * ((window_origin!=top)?-1.: 1.) + ((window_origin!=top)? window_height : 0)
// wpos.x = (frag_coord / resolution_scale)
// wpos.zw = frag_coord.zw
const auto window_origin = rsx::method_registers.shader_window_origin();
const u32 window_height = rsx::method_registers.shader_window_height(); const u32 window_height = rsx::method_registers.shader_window_height();
const float one = 1.f; const f32 resolution_scale = rsx::get_resolution_scale();
const f32 wpos_scale = (window_origin == rsx::window_origin::top) ? (1.f / resolution_scale) : (-1.f / resolution_scale);
const f32 wpos_bias = (window_origin == rsx::window_origin::top) ? 0.f : window_height;
u32 *dst = static_cast<u32*>(buffer); u32 *dst = static_cast<u32*>(buffer);
stream_vector(dst, (u32&)fog0, (u32&)fog1, is_alpha_tested, (u32&)alpha_ref); stream_vector(dst, (u32&)fog0, (u32&)fog1, is_alpha_tested, (u32&)alpha_ref);
stream_vector(dst + 4, alpha_func, fog_mode, window_origin, window_height); stream_vector(dst + 4, alpha_func, fog_mode, (u32&)wpos_scale, (u32&)wpos_bias);
size_t offset = 8; size_t offset = 8;
for (int index = 0; index < 16; ++index) for (int index = 0; index < 16; ++index)
{ {
stream_vector(&dst[offset], (u32&)fragment_program.texture_pitch_scale[index], (u32&)one, 0U, 0U); stream_vector(&dst[offset], (u32&)fragment_program.texture_scale[index][0], (u32&)fragment_program.texture_scale[index][1], 0U, 0U);
offset += 4; offset += 4;
} }
} }
@ -1305,10 +1319,13 @@ namespace rsx
result.shadow_textures = 0; result.shadow_textures = 0;
std::array<texture_dimension_extended, 16> texture_dimensions; std::array<texture_dimension_extended, 16> texture_dimensions;
const auto resolution_scale = rsx::get_resolution_scale();
for (u32 i = 0; i < rsx::limits::fragment_textures_count; ++i) for (u32 i = 0; i < rsx::limits::fragment_textures_count; ++i)
{ {
auto &tex = rsx::method_registers.fragment_textures[i]; auto &tex = rsx::method_registers.fragment_textures[i];
result.texture_pitch_scale[i] = 1.f; result.texture_scale[i][0] = 1.f;
result.texture_scale[i][1] = 1.f;
result.textures_alpha_kill[i] = 0; result.textures_alpha_kill[i] = 0;
result.textures_zfunc[i] = 0; result.textures_zfunc[i] = 0;
@ -1345,14 +1362,23 @@ namespace rsx
if (surface_exists && surface_pitch) if (surface_exists && surface_pitch)
{ {
if (raw_format & CELL_GCM_TEXTURE_UN) if (raw_format & CELL_GCM_TEXTURE_UN)
result.texture_pitch_scale[i] = (float)surface_pitch / tex.pitch(); {
result.texture_scale[i][0] = (resolution_scale * (float)surface_pitch) / tex.pitch();
result.texture_scale[i][1] = resolution_scale;
}
} }
else else
{ {
std::tie(surface_exists, surface_pitch) = get_surface_info(texaddr, tex, true); std::tie(surface_exists, surface_pitch) = get_surface_info(texaddr, tex, true);
if (surface_exists) if (surface_exists)
{ {
u32 format = raw_format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); if (raw_format & CELL_GCM_TEXTURE_UN)
{
result.texture_scale[i][0] = (resolution_scale * (float)surface_pitch) / tex.pitch();
result.texture_scale[i][1] = resolution_scale;
}
const u32 format = raw_format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
switch (format) switch (format)
{ {
case CELL_GCM_TEXTURE_A8R8G8B8: case CELL_GCM_TEXTURE_A8R8G8B8:

View file

@ -166,8 +166,8 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
OS << " float alpha_ref;\n"; OS << " float alpha_ref;\n";
OS << " uint alpha_func;\n"; OS << " uint alpha_func;\n";
OS << " uint fog_mode;\n"; OS << " uint fog_mode;\n";
OS << " uint window_origin;\n"; OS << " float wpos_scale;\n";
OS << " uint window_height;\n"; OS << " float wpos_bias;\n";
OS << " vec4 texture_parameters[16];\n"; OS << " vec4 texture_parameters[16];\n";
OS << "};\n"; OS << "};\n";
@ -253,8 +253,7 @@ void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
} }
OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n"; OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n";
OS << " vec4 wpos = gl_FragCoord;\n"; OS << " vec4 wpos = get_wpos();\n";
OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n";
bool two_sided_enabled = m_prog.front_back_color_enabled && (m_prog.back_color_diffuse_output || m_prog.back_color_specular_output); bool two_sided_enabled = m_prog.front_back_color_enabled && (m_prog.back_color_diffuse_output || m_prog.back_color_specular_output);

View file

@ -1266,17 +1266,19 @@ void VKGSRender::end()
void VKGSRender::set_viewport() void VKGSRender::set_viewport()
{ {
u16 scissor_x = rsx::method_registers.scissor_origin_x(); const auto clip_width = rsx::apply_resolution_scale(rsx::method_registers.surface_clip_width(), true);
u16 scissor_w = rsx::method_registers.scissor_width(); const auto clip_height = rsx::apply_resolution_scale(rsx::method_registers.surface_clip_height(), true);
u16 scissor_y = rsx::method_registers.scissor_origin_y(); u16 scissor_x = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_x(), false);
u16 scissor_h = rsx::method_registers.scissor_height(); u16 scissor_w = rsx::apply_resolution_scale(rsx::method_registers.scissor_width(), true);
u16 scissor_y = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_y(), false);
u16 scissor_h = rsx::apply_resolution_scale(rsx::method_registers.scissor_height(), true);
//NOTE: The scale_offset matrix already has viewport matrix factored in //NOTE: The scale_offset matrix already has viewport matrix factored in
VkViewport viewport = {}; VkViewport viewport = {};
viewport.x = 0; viewport.x = 0;
viewport.y = 0; viewport.y = 0;
viewport.width = rsx::method_registers.surface_clip_width(); viewport.width = clip_width;
viewport.height = rsx::method_registers.surface_clip_height(); viewport.height = clip_height;
viewport.minDepth = 0.f; viewport.minDepth = 0.f;
viewport.maxDepth = 1.f; viewport.maxDepth = 1.f;
@ -1341,13 +1343,14 @@ void VKGSRender::clear_surface(u32 mask)
std::vector<VkClearAttachment> clear_descriptors; std::vector<VkClearAttachment> clear_descriptors;
VkClearValue depth_stencil_clear_values, color_clear_values; VkClearValue depth_stencil_clear_values, color_clear_values;
u16 scissor_x = rsx::method_registers.scissor_origin_x(); const auto scale = rsx::get_resolution_scale();
u16 scissor_w = rsx::method_registers.scissor_width(); u16 scissor_x = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_x(), false);
u16 scissor_y = rsx::method_registers.scissor_origin_y(); u16 scissor_w = rsx::apply_resolution_scale(rsx::method_registers.scissor_width(), true);
u16 scissor_h = rsx::method_registers.scissor_height(); u16 scissor_y = rsx::apply_resolution_scale(rsx::method_registers.scissor_origin_y(), false);
u16 scissor_h = rsx::apply_resolution_scale(rsx::method_registers.scissor_height(), true);
const u32 fb_width = m_draw_fbo->width(); const u16 fb_width = m_draw_fbo->width();
const u32 fb_height = m_draw_fbo->height(); const u16 fb_height = m_draw_fbo->height();
//clip region //clip region
std::tie(scissor_x, scissor_y, scissor_w, scissor_h) = rsx::clip_region<u16>(fb_width, fb_height, scissor_x, scissor_y, scissor_w, scissor_h, true); std::tie(scissor_x, scissor_y, scissor_w, scissor_h) = rsx::clip_region<u16>(fb_width, fb_height, scissor_x, scissor_y, scissor_w, scissor_h, true);
@ -2086,14 +2089,14 @@ void VKGSRender::prepare_rtts()
const u32 surface_pitchs[] = { rsx::method_registers.surface_a_pitch(), rsx::method_registers.surface_b_pitch(), const u32 surface_pitchs[] = { rsx::method_registers.surface_a_pitch(), rsx::method_registers.surface_b_pitch(),
rsx::method_registers.surface_c_pitch(), rsx::method_registers.surface_d_pitch() }; rsx::method_registers.surface_c_pitch(), rsx::method_registers.surface_d_pitch() };
const auto fbo_width = rsx::apply_resolution_scale(clip_width, true);
const auto fbo_height = rsx::apply_resolution_scale(clip_height, true);
if (m_draw_fbo) if (m_draw_fbo)
{ {
const u32 fb_width = m_draw_fbo->width();
const u32 fb_height = m_draw_fbo->height();
bool really_changed = false; bool really_changed = false;
if (fb_width == clip_width && fb_height == clip_height) if (m_draw_fbo->width() == fbo_width && m_draw_fbo->height() == clip_height)
{ {
for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i) for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i)
{ {
@ -2215,7 +2218,7 @@ void VKGSRender::prepare_rtts()
for (auto &fbo : m_framebuffers_to_clean) for (auto &fbo : m_framebuffers_to_clean)
{ {
if (fbo->matches(bound_images, clip_width, clip_height)) if (fbo->matches(bound_images, fbo_width, fbo_height))
{ {
m_draw_fbo.swap(fbo); m_draw_fbo.swap(fbo);
m_draw_fbo->reset_refs(); m_draw_fbo->reset_refs();
@ -2263,7 +2266,7 @@ void VKGSRender::prepare_rtts()
if (m_draw_fbo) if (m_draw_fbo)
m_framebuffers_to_clean.push_back(std::move(m_draw_fbo)); m_framebuffers_to_clean.push_back(std::move(m_draw_fbo));
m_draw_fbo.reset(new vk::framebuffer_holder(*m_device, current_render_pass, clip_width, clip_height, std::move(fbo_images))); m_draw_fbo.reset(new vk::framebuffer_holder(*m_device, current_render_pass, fbo_width, fbo_height, std::move(fbo_images)));
} }
} }

View file

@ -6,6 +6,7 @@
#include "../Common/surface_store.h" #include "../Common/surface_store.h"
#include "../Common/TextureUtils.h" #include "../Common/TextureUtils.h"
#include "VKFormats.h" #include "VKFormats.h"
#include "../rsx_utils.h"
struct ref_counted struct ref_counted
{ {
@ -59,12 +60,12 @@ namespace vk
u16 get_surface_width() const override u16 get_surface_width() const override
{ {
return width(); return rsx::apply_inverse_resolution_scale(width(), true);
} }
u16 get_surface_height() const override u16 get_surface_height() const override
{ {
return height(); return rsx::apply_inverse_resolution_scale(height(), true);
} }
u16 get_rsx_pitch() const override u16 get_rsx_pitch() const override
@ -76,6 +77,12 @@ namespace vk
{ {
return native_pitch; return native_pitch;
} }
bool matches_dimensions(u16 _width, u16 _height) const
{
//Use foward scaling to account for rounding and clamping errors
return (rsx::apply_resolution_scale(_width, true) == width()) && (rsx::apply_resolution_scale(_height, true) == height());
}
}; };
struct framebuffer_holder: public vk::framebuffer, public ref_counted struct framebuffer_holder: public vk::framebuffer, public ref_counted
@ -114,7 +121,7 @@ namespace rsx
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_2D,
requested_format, requested_format,
static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1, 1, 1, static_cast<uint32_t>(rsx::apply_resolution_scale((u16)width, true)), static_cast<uint32_t>(rsx::apply_resolution_scale((u16)height, true)), 1, 1, 1,
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_OPTIMAL,
@ -158,12 +165,14 @@ namespace rsx
if (requested_format != VK_FORMAT_D16_UNORM) if (requested_format != VK_FORMAT_D16_UNORM)
range.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; range.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
const auto scale = rsx::get_resolution_scale();
std::unique_ptr<vk::render_target> ds; std::unique_ptr<vk::render_target> ds;
ds.reset(new vk::render_target(device, mem_mapping.device_local, ds.reset(new vk::render_target(device, mem_mapping.device_local,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_2D,
requested_format, requested_format,
static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1, 1, 1, static_cast<uint32_t>(rsx::apply_resolution_scale((u16)width, true)), static_cast<uint32_t>(rsx::apply_resolution_scale((u16)height, true)), 1, 1, 1,
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_OPTIMAL,
@ -202,8 +211,8 @@ namespace rsx
{ {
info->rsx_pitch = surface->rsx_pitch; info->rsx_pitch = surface->rsx_pitch;
info->native_pitch = surface->native_pitch; info->native_pitch = surface->native_pitch;
info->surface_width = surface->info.extent.width; info->surface_width = surface->get_surface_width();
info->surface_height = surface->info.extent.height; info->surface_height = surface->get_surface_height();
info->bpp = static_cast<u8>(info->native_pitch / info->surface_width); info->bpp = static_cast<u8>(info->native_pitch / info->surface_width);
} }
@ -260,8 +269,7 @@ namespace rsx
VkFormat fmt = vk::get_compatible_surface_format(format).first; VkFormat fmt = vk::get_compatible_surface_format(format).first;
if (rtt->info.format == fmt && if (rtt->info.format == fmt &&
rtt->info.extent.width == width && rtt->matches_dimensions((u16)width, (u16)height))
rtt->info.extent.height == height)
return true; return true;
return false; return false;
@ -272,8 +280,7 @@ namespace rsx
if (check_refs && ds->deref_count == 0) //Surface may still have read refs from data 'copy' if (check_refs && ds->deref_count == 0) //Surface may still have read refs from data 'copy'
return false; return false;
if (ds->info.extent.width == width && if (ds->matches_dimensions((u16)width, (u16)height))
ds->info.extent.height == height)
{ {
//Check format //Check format
switch (ds->info.format) switch (ds->info.format)

View file

@ -207,4 +207,30 @@ namespace rsx
return std::make_tuple(x, y, width, height); return std::make_tuple(x, y, width, height);
} }
static inline f32 get_resolution_scale()
{
return g_cfg.video.strict_rendering_mode? 1.f : ((f32)g_cfg.video.resolution_scale_percent / 100.f);
}
static inline int get_resolution_scale_percent()
{
return g_cfg.video.strict_rendering_mode ? 100 : g_cfg.video.resolution_scale_percent;
}
static inline const u16 apply_resolution_scale(u16 value, bool clamp)
{
if (clamp)
return (u16)std::max((get_resolution_scale_percent() * value) / 100, 1);
else
return (get_resolution_scale_percent() * value) / 100;
}
static inline const u16 apply_inverse_resolution_scale(u16 value, bool clamp)
{
if (clamp)
return (u16)std::max((value * 100) / get_resolution_scale_percent(), 1);
else
return (value * 100) / get_resolution_scale_percent();
}
} }