1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 03:02:53 +01:00

rsx: Fbo fixes 2

- Use AA mode to predict surface compression. Compression mode is useless without AA activated
- Rewrites most image subresource fetch routines to use the new heuristic
- Fix rsx:🧵:find_tile. FEED000(X) can be substituted for (X) in the code
-- Fixes alot of failures when looking for tiled regions

rsx: Fix antialiased unnormalized coords
- scaling factors are inverse to allow proper coordinates to be computed in fs
This commit is contained in:
kd-11 2017-11-01 01:36:39 +03:00
parent b95630d84a
commit bbcb6b6851
6 changed files with 168 additions and 69 deletions

View File

@ -47,6 +47,9 @@ namespace rsx
template <typename image_storage_type>
struct render_target_descriptor
{
GcmTileInfo *tile = nullptr;
rsx::surface_antialiasing aa_mode = rsx::surface_antialiasing::center_1_sample;
virtual image_storage_type get_surface() const = 0;
virtual u16 get_surface_width() const = 0;
virtual u16 get_surface_height() const = 0;
@ -584,7 +587,7 @@ namespace rsx
* address_is_bound - returns true if the surface at a given address is actively bound
* get_surface_subresource_if_available - returns a sectiion descriptor that allows to crop surfaces stored in memory
*/
bool surface_overlaps_address(surface_type surface, u32 surface_address, u32 texaddr, u16 *x, u16 *y, bool scale_to_fit, bool double_height)
bool surface_overlaps_address(surface_type surface, u32 surface_address, u32 texaddr, u16 *x, u16 *y)
{
bool is_subslice = false;
u16 x_offset = 0;
@ -605,24 +608,31 @@ namespace rsx
surface_format_info info;
Traits::get_surface_info(surface, &info);
bool doubled_x = false;
bool doubled_y = false;
switch (surface->aa_mode)
{
case rsx::surface_antialiasing::square_rotated_4_samples:
case rsx::surface_antialiasing::square_centered_4_samples:
doubled_y = true;
//fall through
case rsx::surface_antialiasing::diagonal_centered_2_samples:
doubled_x = true;
break;
}
u32 range = info.rsx_pitch * info.surface_height;
if (double_height) range <<= 1;
if (doubled_y) range <<= 1;
if (offset < range)
{
const u32 y = (offset / info.rsx_pitch);
u32 x = (offset % info.rsx_pitch) / info.bpp;
y_offset = (offset / info.rsx_pitch);
x_offset = (offset % info.rsx_pitch) / info.bpp;
if (scale_to_fit)
{
const f32 x_scale = (f32)info.rsx_pitch / info.native_pitch;
x = (u32)((f32)x / x_scale);
}
if (doubled_x) x_offset /= 2;
if (doubled_y) y_offset /= 2;
x_offset = x;
y_offset = y;
if (double_height) y_offset /= 2;
is_subslice = true;
}
}
@ -677,27 +687,34 @@ namespace rsx
}
surface_subresource get_surface_subresource_if_applicable(u32 texaddr, u16 requested_width, u16 requested_height, u16 requested_pitch,
bool scale_to_fit = false, bool crop = false, bool ignore_depth_formats = false, bool ignore_color_formats = false, bool double_height = false)
bool crop = false, bool ignore_depth_formats = false, bool ignore_color_formats = false)
{
auto test_surface = [&](surface_type surface, u32 this_address, u16 &x_offset, u16 &y_offset, u16 &w, u16 &h, bool &clipped)
{
if (surface_overlaps_address(surface, this_address, texaddr, &x_offset, &y_offset, scale_to_fit, double_height))
if (surface_overlaps_address(surface, this_address, texaddr, &x_offset, &y_offset))
{
surface_format_info info;
Traits::get_surface_info(surface, &info);
u16 real_width = requested_width;
u16 real_height = requested_height;
if (scale_to_fit)
switch (surface->aa_mode)
{
f32 pitch_scaling = (f32)requested_pitch / info.native_pitch;
real_width = (u16)((f32)requested_width / pitch_scaling);
case rsx::surface_antialiasing::diagonal_centered_2_samples:
real_width /= 2;
break;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
real_width /= 2;
real_height /= 2;
break;
}
if (region_fits(info.surface_width, info.surface_height, x_offset, y_offset, real_width, requested_height))
if (region_fits(info.surface_width, info.surface_height, x_offset, y_offset, real_width, real_height))
{
w = real_width;
h = requested_height;
h = real_height;
clipped = false;
return true;
@ -710,17 +727,17 @@ namespace rsx
u16 remaining_height = info.surface_height - y_offset;
w = std::min(real_width, remaining_width);
h = std::min(requested_height, remaining_height);
h = std::min(real_height, remaining_height);
clipped = true;
return true;
}
if (info.surface_width >= real_width && info.surface_height >= requested_height)
if (info.surface_width >= real_width && info.surface_height >= real_height)
{
LOG_WARNING(RSX, "Overlapping surface exceeds bounds; returning full surface region");
w = real_width;
h = requested_height;
h = real_height;
clipped = true;
return true;

View File

@ -30,7 +30,8 @@ namespace rsx
{
texture_upload_context upload_context = texture_upload_context::shader_read;
bool is_depth_texture = false;
f32 internal_scale = 1.f;
f32 scale_x = 1.f;
f32 scale_y = 1.f;
};
struct cached_texture_section : public rsx::buffered_section
@ -219,12 +220,13 @@ namespace rsx
sampled_image_descriptor()
{}
sampled_image_descriptor(image_view_type handle, const texture_upload_context ctx, const bool is_depth, const f32 scale)
sampled_image_descriptor(image_view_type handle, const texture_upload_context ctx, const bool is_depth, const f32 x_scale, const f32 y_scale)
{
image_handle = handle;
upload_context = ctx;
is_depth_texture = is_depth;
internal_scale = scale;
scale_x = x_scale;
scale_y = y_scale;
}
};
@ -447,7 +449,7 @@ namespace rsx
return {};
}
bool is_hw_blit_engine_compatible(const u32 format) const
inline bool is_hw_blit_engine_compatible(const u32 format) const
{
switch (format)
{
@ -461,6 +463,80 @@ namespace rsx
}
}
/**
* Scaling helpers
* - get_native_dimensions() returns w and h for the native texture given rsx dimensions
* on rsx a 512x512 texture with 4x AA is treated as a 1024x1024 texture for example
* - get_rsx_dimensions() inverse, return rsx w and h given a real texture w and h
* - get_internal_scaling_x/y() returns a scaling factor to be multiplied by 1/size
* when sampling with unnormalized coordinates. tcoords passed to rsx will be in rsx dimensions
*/
template <typename T, typename U>
inline void get_native_dimensions(T &width, T &height, T rsx_pitch, U surface)
{
switch (surface->aa_mode)
{
case rsx::surface_antialiasing::center_1_sample:
return;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
width /= 2;
return;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
width /= 2;
height /= 2;
return;
}
}
template <typename T, typename U>
inline void get_rsx_dimensions(T &width, T &height, T rsx_pitch, U surface)
{
switch (surface->aa_mode)
{
case rsx::surface_antialiasing::center_1_sample:
return;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
width *= 2;
return;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
width *= 2;
height *= 2;
return;
}
}
template <typename T>
inline f32 get_internal_scaling_x(T surface)
{
switch (surface->aa_mode)
{
default:
case rsx::surface_antialiasing::center_1_sample:
return 1.f;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
return 0.5f;
}
}
template <typename T>
inline f32 get_internal_scaling_y(T surface)
{
switch (surface->aa_mode)
{
default:
case rsx::surface_antialiasing::center_1_sample:
case rsx::surface_antialiasing::diagonal_centered_2_samples:
return 1.f;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
return 0.5f;
}
}
public:
texture_cache() {}
@ -894,10 +970,11 @@ namespace rsx
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d)
LOG_ERROR(RSX, "Texture resides in render target memory, but requested type is not 2D (%d)", (u32)extended_dimension);
const f32 internal_scale = (f32)texptr->get_native_pitch() / tex.pitch();
const u32 internal_width = tex_width * texptr->get_native_pitch() / tex.pitch();
u32 internal_width = tex_width;
u32 internal_height = tex_height;
get_native_dimensions(internal_width, internal_height, (u32)tex_pitch, texptr);
bool requires_processing = texptr->get_surface_width() != internal_width || texptr->get_surface_height() != tex_height;
bool requires_processing = texptr->get_surface_width() != internal_width || texptr->get_surface_height() != internal_height;
if (!requires_processing)
{
for (const auto& tex : m_rtts.m_bound_render_targets)
@ -923,11 +1000,12 @@ namespace rsx
if (requires_processing)
{
const auto w = rsx::apply_resolution_scale(internal_width, true);
const auto h = rsx::apply_resolution_scale(tex_height, true);
return{ create_temporary_subresource_view(cmd, texptr, format, 0, 0, w, h), texture_upload_context::framebuffer_storage, false, internal_scale };
const auto h = rsx::apply_resolution_scale(internal_height, true);
return{ create_temporary_subresource_view(cmd, texptr, format, 0, 0, w, h), texture_upload_context::framebuffer_storage,
false, get_internal_scaling_x(texptr), get_internal_scaling_y(texptr) };
}
return{ texptr->get_view(), texture_upload_context::framebuffer_storage, false, internal_scale };
return{ texptr->get_view(), texture_upload_context::framebuffer_storage, false, get_internal_scaling_x(texptr), get_internal_scaling_y(texptr) };
}
else
{
@ -943,10 +1021,11 @@ namespace rsx
if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d)
LOG_ERROR(RSX, "Texture resides in depth buffer memory, but requested type is not 2D (%d)", (u32)extended_dimension);
const f32 internal_scale = (f32)texptr->get_native_pitch() / tex.pitch();
const u32 internal_width = tex_width * texptr->get_native_pitch() / tex.pitch();
u32 internal_width = tex_width;
u32 internal_height = tex_height;
get_native_dimensions(internal_width, internal_height, (u32)tex_pitch, texptr);
bool requires_processing = texptr->get_surface_width() != internal_width || texptr->get_surface_height() != tex_height;
bool requires_processing = texptr->get_surface_width() != internal_width || texptr->get_surface_height() != internal_height;
if (!requires_processing && texaddr == std::get<0>(m_rtts.m_bound_depth_stencil))
{
if (g_cfg.video.strict_rendering_mode)
@ -964,11 +1043,12 @@ namespace rsx
if (requires_processing)
{
const auto w = rsx::apply_resolution_scale(internal_width, true);
const auto h = rsx::apply_resolution_scale(tex_height, true);
return{ create_temporary_subresource_view(cmd, texptr, format, 0, 0, w, h), texture_upload_context::framebuffer_storage, true, internal_scale };
const auto h = rsx::apply_resolution_scale(internal_height, true);
return{ create_temporary_subresource_view(cmd, texptr, format, 0, 0, w, h), texture_upload_context::framebuffer_storage,
true, get_internal_scaling_x(texptr), get_internal_scaling_y(texptr) };
}
return{ texptr->get_view(), texture_upload_context::framebuffer_storage, true, internal_scale };
return{ texptr->get_view(), texture_upload_context::framebuffer_storage, true, get_internal_scaling_x(texptr), get_internal_scaling_y(texptr) };
}
else
{
@ -1008,11 +1088,7 @@ namespace rsx
*/
//TODO: Take framebuffer Y compression into account
const u32 native_pitch = tex_width * get_format_block_size_in_bytes(format);
const f32 internal_scale = (f32)tex_pitch / native_pitch;
const u32 internal_width = (const u32)(tex_width * internal_scale);
const auto rsc = m_rtts.get_surface_subresource_if_applicable(texaddr, internal_width, tex_height, tex_pitch, true);
const auto rsc = m_rtts.get_surface_subresource_if_applicable(texaddr, tex_width, tex_height, tex_pitch);
if (rsc.surface)
{
//TODO: Check that this region is not cpu-dirty before doing a copy
@ -1038,16 +1114,18 @@ namespace rsx
insert_texture_barrier();
}
return{ rsc.surface->get_view(), texture_upload_context::framebuffer_storage, rsc.is_depth_surface, 1.f };
return{ rsc.surface->get_view(), texture_upload_context::framebuffer_storage, rsc.is_depth_surface, get_internal_scaling_x(rsc.surface), get_internal_scaling_y(rsc.surface) };
}
else 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)), texture_upload_context::framebuffer_storage, rsc.is_depth_surface, 1.f };
rsx::apply_resolution_scale(rsc.w, true), rsx::apply_resolution_scale(rsc.h, true)), texture_upload_context::framebuffer_storage,
rsc.is_depth_surface, get_internal_scaling_x(rsc.surface), get_internal_scaling_y(rsc.surface) };
}
else
{
LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr);
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)), texture_upload_context::framebuffer_storage, rsc.is_depth_surface, 1.f };
rsx::apply_resolution_scale(rsc.w, true), rsx::apply_resolution_scale(rsc.h, true)), texture_upload_context::framebuffer_storage,
rsc.is_depth_surface, get_internal_scaling_x(rsc.surface), get_internal_scaling_y(rsc.surface) };
}
}
}
@ -1060,7 +1138,7 @@ namespace rsx
auto cached_texture = find_texture_from_dimensions(texaddr, tex_width, tex_height, depth);
if (cached_texture)
{
return{ cached_texture->get_raw_view(), cached_texture->get_context(), cached_texture->is_depth_texture(), 1.f };
return{ cached_texture->get_raw_view(), cached_texture->get_context(), cached_texture->is_depth_texture(), 1.f, 1.f };
}
if ((!blit_engine_incompatibility_warning_raised && g_cfg.video.use_gpu_texture_scaling) || is_hw_blit_engine_compatible(format))
@ -1103,7 +1181,7 @@ namespace rsx
auto src_image = surface->get_raw_texture();
if (auto result = create_temporary_subresource_view(cmd, &src_image, format, offset_x, offset_y, tex_width, tex_height))
return{ result, texture_upload_context::blit_engine_dst, surface->is_depth_texture(), 1.f };
return{ result, texture_upload_context::blit_engine_dst, surface->is_depth_texture(), 1.f, 1.f };
}
}
}
@ -1123,7 +1201,7 @@ namespace rsx
m_texture_memory_in_use += (tex_pitch * tex_height);
return{ upload_image_from_cpu(cmd, texaddr, tex_width, tex_height, depth, tex.get_exact_mipmap_count(), tex_pitch, format,
texture_upload_context::shader_read, subresources_layout, extended_dimension, is_swizzled, remap_vector)->get_raw_view(),
texture_upload_context::shader_read, false, 1.f };
texture_upload_context::shader_read, false, 1.f, 1.f };
}
template <typename surface_store_type, typename blitter_type, typename ...Args>
@ -1148,13 +1226,6 @@ namespace rsx
float scale_x = dst.scale_x;
float scale_y = dst.scale_y;
//TODO: Investigate effects of compression in X axis
if (dst.compressed_y)
scale_y *= 0.5f;
if (src.compressed_y)
scale_y *= 2.f;
//Offset in x and y for src is 0 (it is already accounted for when getting pixels_src)
//Reproject final clip onto source...
const u16 src_w = (const u16)((f32)dst.clip_width / scale_x);
@ -1172,7 +1243,7 @@ namespace rsx
}
//Check if src/dst are parts of render targets
auto dst_subres = m_rtts.get_surface_subresource_if_applicable(dst_address, dst.width, dst.clip_height, dst.pitch, true, true, false, false, dst.compressed_y);
auto dst_subres = m_rtts.get_surface_subresource_if_applicable(dst_address, dst.width, dst.clip_height, dst.pitch, true, false, false);
dst_is_render_target = dst_subres.surface != nullptr;
if (dst_is_render_target && dst_subres.surface->get_native_pitch() != dst.pitch)
@ -1184,7 +1255,7 @@ namespace rsx
}
//TODO: Handle cases where src or dst can be a depth texture while the other is a color texture - requires a render pass to emulate
auto src_subres = m_rtts.get_surface_subresource_if_applicable(framebuffer_src_address, src_w, src_h, src.pitch, true, true, false, false, src.compressed_y);
auto src_subres = m_rtts.get_surface_subresource_if_applicable(framebuffer_src_address, src_w, src_h, src.pitch, true, false, false);
src_is_render_target = src_subres.surface != nullptr;
if (src_is_render_target && src_subres.surface->get_native_pitch() != src.pitch)
@ -1358,9 +1429,7 @@ namespace rsx
if (src_subres.w != dst.clip_width ||
src_subres.h != dst.clip_height)
{
f32 subres_scaling_x = (f32)src.pitch / src_subres.surface->get_native_pitch();
const int dst_width = (int)(src_subres.w * scale_x * subres_scaling_x);
const int dst_width = (int)(src_subres.w * scale_x);
const int dst_height = (int)(src_subres.h * scale_y);
dst_area.x2 = dst_area.x1 + dst_width;

View File

@ -202,6 +202,10 @@ void GLGSRender::init_buffers(bool skip_reading)
bool old_format_found = false;
gl::texture::format old_format;
const auto color_offsets = get_offsets();
const auto color_locations = get_locations();
const auto aa_mode = rsx::method_registers.surface_antialias();
for (int i = 0; i < rsx::limits::color_buffers_count; ++i)
{
if (surface_info[i].pitch && g_cfg.video.write_color_buffers)
@ -217,9 +221,10 @@ void GLGSRender::init_buffers(bool skip_reading)
if (std::get<0>(m_rtts.m_bound_render_targets[i]))
{
__glcheck draw_fbo.color[i] = *std::get<1>(m_rtts.m_bound_render_targets[i]);
auto rtt = std::get<1>(m_rtts.m_bound_render_targets[i]);
draw_fbo.color[i] = *rtt;
std::get<1>(m_rtts.m_bound_render_targets[i])->set_rsx_pitch(pitchs[i]);
rtt->set_rsx_pitch(pitchs[i]);
surface_info[i] = { surface_addresses[i], pitchs[i], false, surface_format, depth_format, clip_horizontal, clip_vertical };
//Verify pitch given is correct if pitch <= 64 (especially 64)
@ -237,6 +242,8 @@ void GLGSRender::init_buffers(bool skip_reading)
}
}
rtt->tile = find_tile(color_offsets[i], color_locations[i]);
rtt->aa_mode = aa_mode;
m_gl_texture_cache.tag_framebuffer(surface_addresses[i]);
}
else
@ -245,10 +252,11 @@ void GLGSRender::init_buffers(bool skip_reading)
if (std::get<0>(m_rtts.m_bound_depth_stencil))
{
auto ds = std::get<1>(m_rtts.m_bound_depth_stencil);
if (depth_format == rsx::surface_depth_format::z24s8)
__glcheck draw_fbo.depth_stencil = *std::get<1>(m_rtts.m_bound_depth_stencil);
draw_fbo.depth_stencil = *ds;
else
__glcheck draw_fbo.depth = *std::get<1>(m_rtts.m_bound_depth_stencil);
draw_fbo.depth = *ds;
const u32 depth_surface_pitch = rsx::method_registers.surface_z_pitch();
std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(rsx::method_registers.surface_z_pitch());
@ -269,6 +277,7 @@ void GLGSRender::init_buffers(bool skip_reading)
}
}
ds->aa_mode = aa_mode;
m_gl_texture_cache.tag_framebuffer(depth_address);
}
else

View File

@ -1387,8 +1387,8 @@ namespace rsx
{
if (raw_format & CELL_GCM_TEXTURE_UN)
{
result.texture_scale[i][0] = (resolution_scale * sampler_descriptors[i]->internal_scale);
result.texture_scale[i][1] = resolution_scale;
result.texture_scale[i][0] = (resolution_scale * sampler_descriptors[i]->scale_x);
result.texture_scale[i][1] = (resolution_scale * sampler_descriptors[i]->scale_y);
}
}
@ -1562,7 +1562,7 @@ namespace rsx
{
for (GcmTileInfo &tile : tiles)
{
if (!tile.binded || tile.location != location)
if (!tile.binded || (tile.location & 1) != (location & 1))
{
continue;
}

View File

@ -2320,6 +2320,7 @@ void VKGSRender::prepare_rtts()
const auto fbo_width = rsx::apply_resolution_scale(clip_width, true);
const auto fbo_height = rsx::apply_resolution_scale(clip_height, true);
const auto aa_mode = rsx::method_registers.surface_antialias();
if (m_draw_fbo)
{
@ -2404,6 +2405,7 @@ void VKGSRender::prepare_rtts()
m_surface_info[index].pitch = 0;
}
surface->aa_mode = aa_mode;
m_texture_cache.tag_framebuffer(surface_addresses[index]);
}
@ -2419,6 +2421,7 @@ void VKGSRender::prepare_rtts()
if (m_depth_surface_info.pitch <= 64 && clip_width > m_depth_surface_info.pitch)
m_depth_surface_info.pitch = 0;
ds->aa_mode = aa_mode;
m_texture_cache.tag_framebuffer(zeta_address);
}

View File

@ -268,6 +268,7 @@ namespace rsx
void notify_surface_invalidated(const std::unique_ptr<vk::render_target> &surface)
{
surface->frame_tag = vk::get_current_frame_id();
if (!surface->frame_tag) surface->frame_tag = 1;
}
static bool rtt_has_format_width_height(const std::unique_ptr<vk::render_target> &rtt, surface_color_format format, size_t width, size_t height, bool check_refs=false)