1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2025-01-31 12:31:45 +01:00

vk/gl: Improve memory tag sync and test

- Properly pass parameters such as rsx-pitch to the surface store
- Do not crash if a surface fails verification in flip, use fall-back instead
This commit is contained in:
kd-11 2019-03-15 18:00:12 +03:00 committed by kd-11
parent 1a44446250
commit 74eeacd091
8 changed files with 111 additions and 49 deletions

View File

@ -112,6 +112,9 @@ namespace rsx
// Tags are tested in an X pattern
for (const auto &tag : memory_tag_samples)
{
if (!tag.first)
break;
if (tag.second != *reinterpret_cast<u64*>(vm::g_sudo_addr + tag.first))
return false;
}
@ -119,22 +122,59 @@ namespace rsx
return true;
}
template<typename T>
void set_old_contents(T* other)
{
if (!other || other->get_rsx_pitch() != this->get_rsx_pitch())
{
old_contents = nullptr;
return;
}
old_contents = other;
}
void queue_tag(u32 address)
{
const u32 pitch = get_native_pitch();
const u32 memory_length = pitch * get_surface_height();
for (int i = 0; i < memory_tag_samples.size(); ++i)
{
if (LIKELY(i))
memory_tag_samples[i].first = 0;
else
memory_tag_samples[i].first = address; // Top left
}
memory_tag_samples[0].first = address; // Top left
memory_tag_samples[1].first = address + memory_length - 4; // Bottom right
memory_tag_samples[2].first = address + pitch; // Top right
memory_tag_samples[3].first = address + (memory_length / 2); // Center
memory_tag_samples[4].first = address + memory_length - pitch; // Bottom left
const u32 pitch = get_native_pitch();
if (UNLIKELY(pitch < 16))
{
// Not enough area to gather samples if pitch is too small
return;
}
// Top right corner
memory_tag_samples[1].first = address + pitch - 8;
if (const u32 h = get_surface_height(); h > 1)
{
// Last row
const u32 pitch2 = get_rsx_pitch();
const u32 last_row_offset = pitch2 * (h - 1);
memory_tag_samples[2].first = address + last_row_offset; // Bottom left corner
memory_tag_samples[3].first = address + last_row_offset + pitch - 8; // Bottom right corner
// Centroid
const u32 center_row_offset = pitch2 * (h / 2);
memory_tag_samples[4].first = address + center_row_offset + pitch / 2;
}
}
void sync_tag()
{
for (auto &tag : memory_tag_samples)
{
if (!tag.first)
break;
tag.second = *reinterpret_cast<u64*>(vm::g_sudo_addr + tag.first);
}
}
@ -364,7 +404,11 @@ namespace rsx
surface_storage_type &rtt = It->second;
if (Traits::rtt_has_format_width_height(rtt, color_format, width, height))
{
Traits::notify_surface_persist(rtt);
if (Traits::surface_is_pitch_compatible(rtt, pitch))
Traits::notify_surface_persist(rtt);
else
Traits::invalidate_surface_contents(command_list, Traits::get(rtt), nullptr, address, pitch);
Traits::prepare_rtt_for_drawing(command_list, Traits::get(rtt));
return Traits::get(rtt);
}
@ -401,7 +445,7 @@ namespace rsx
invalidated_resources.erase(It);
new_surface = Traits::get(new_surface_storage);
Traits::invalidate_surface_contents(address, command_list, new_surface, contents_to_copy);
Traits::invalidate_surface_contents(command_list, new_surface, contents_to_copy, address, pitch);
Traits::prepare_rtt_for_drawing(command_list, new_surface);
break;
}
@ -421,7 +465,7 @@ namespace rsx
return new_surface;
}
m_render_targets_storage[address] = Traits::create_new_surface(address, color_format, width, height, contents_to_copy, std::forward<Args>(extra_params)...);
m_render_targets_storage[address] = Traits::create_new_surface(address, color_format, width, height, pitch, contents_to_copy, std::forward<Args>(extra_params)...);
return Traits::get(m_render_targets_storage[address]);
}
@ -456,7 +500,11 @@ namespace rsx
surface_storage_type &ds = It->second;
if (Traits::ds_has_format_width_height(ds, depth_format, width, height))
{
Traits::notify_surface_persist(ds);
if (Traits::surface_is_pitch_compatible(ds, pitch))
Traits::notify_surface_persist(ds);
else
Traits::invalidate_surface_contents(command_list, Traits::get(ds), nullptr, address, pitch);
Traits::prepare_ds_for_drawing(command_list, Traits::get(ds));
return Traits::get(ds);
}
@ -493,7 +541,7 @@ namespace rsx
new_surface = Traits::get(new_surface_storage);
Traits::prepare_ds_for_drawing(command_list, new_surface);
Traits::invalidate_surface_contents(address, command_list, new_surface, contents_to_copy);
Traits::invalidate_surface_contents(command_list, new_surface, contents_to_copy, address, pitch);
break;
}
}
@ -512,7 +560,7 @@ namespace rsx
return new_surface;
}
m_depth_stencil_storage[address] = Traits::create_new_surface(address, depth_format, width, height, contents_to_copy, std::forward<Args>(extra_params)...);
m_depth_stencil_storage[address] = Traits::create_new_surface(address, depth_format, width, height, pitch, contents_to_copy, std::forward<Args>(extra_params)...);
return Traits::get(m_depth_stencil_storage[address]);
}
public:

View File

@ -278,7 +278,7 @@ namespace rsx
if (_v > max_y) max_y = _v;
if (const auto _w = max_x - min_x, _h = max_y - min_y;
(_w * _h) >= target_area)
u32(_w * _h) >= target_area)
{
// Target area mostly covered, return success
return true;

View File

@ -24,7 +24,7 @@ struct render_target_traits
static
ComPtr<ID3D12Resource> create_new_surface(
u32 address,
surface_color_format color_format, size_t width, size_t height,
surface_color_format color_format, size_t width, size_t height, size_t /*pitch*/,
ID3D12Resource* /*old*/,
ID3D12Device* device, const std::array<float, 4> &clear_color, float, u8)
{
@ -85,7 +85,7 @@ struct render_target_traits
static
ComPtr<ID3D12Resource> create_new_surface(
u32 address,
surface_depth_format surfaceDepthFormat, size_t width, size_t height,
surface_depth_format surfaceDepthFormat, size_t width, size_t height, size_t /*pitch*/,
ID3D12Resource* /*old*/,
ID3D12Device* device, const std::array<float, 4>& , float clear_depth, u8 clear_stencil)
{
@ -130,9 +130,9 @@ struct render_target_traits
static
void invalidate_surface_contents(
u32,
ID3D12GraphicsCommandList*,
ID3D12Resource*, ID3D12Resource*)
ID3D12Resource*, ID3D12Resource*,
u32, size_t)
{}
static
@ -143,6 +143,12 @@ struct render_target_traits
void notify_surface_persist(const ComPtr<ID3D12Resource>&)
{}
static
bool surface_is_pitch_compatible(const ComPtr<ID3D12Resource>&, size_t)
{
return true;
}
static
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_color_format surface_color_format, size_t width, size_t height, bool=false)
{

View File

@ -1646,9 +1646,8 @@ void GLGSRender::flip(int buffer)
{
gl::command_context cmd = { gl_state };
const auto overlap_info = m_rtts.get_merged_texture_memory_region(cmd, absolute_address, buffer_width, buffer_height, buffer_pitch);
verify(HERE), !overlap_info.empty();
if (overlap_info.back().surface == render_target_texture)
if (!overlap_info.empty() && overlap_info.back().surface == render_target_texture)
{
// Confirmed to be the newest data source in that range
image = render_target_texture->raw_handle();

View File

@ -256,7 +256,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
auto rtt = std::get<1>(m_rtts.m_bound_render_targets[i]);
color_targets[i] = rtt->id();
rtt->set_rsx_pitch(layout.actual_color_pitch[i]);
verify("Pitch mismatch!" HERE), rtt->get_rsx_pitch() == layout.actual_color_pitch[i];
m_surface_info[i] = { layout.color_addresses[i], layout.actual_color_pitch[i], false, layout.color_format, layout.depth_format, layout.width, layout.height, color_bpp };
rtt->tile = find_tile(color_offsets[i], color_locations[i]);
@ -285,7 +285,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
auto ds = std::get<1>(m_rtts.m_bound_depth_stencil);
depth_stencil_target = ds->id();
std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(layout.actual_zeta_pitch);
verify("Pitch mismatch!" HERE), std::get<1>(m_rtts.m_bound_depth_stencil)->get_rsx_pitch() == layout.actual_zeta_pitch;
m_depth_surface_info = { layout.zeta_address, layout.actual_zeta_pitch, true, layout.color_format, layout.depth_format, layout.width, layout.height, depth_bpp };
ds->write_aa_mode = layout.aa_mode;

View File

@ -166,8 +166,7 @@ struct gl_render_target_traits
std::unique_ptr<gl::render_target> create_new_surface(
u32 address,
rsx::surface_color_format surface_color_format,
size_t width,
size_t height,
size_t width, size_t height, size_t pitch,
gl::render_target* old_surface
)
{
@ -177,10 +176,11 @@ struct gl_render_target_traits
std::unique_ptr<gl::render_target> result(new gl::render_target(rsx::apply_resolution_scale((u16)width, true),
rsx::apply_resolution_scale((u16)height, true), (GLenum)internal_fmt));
result->set_native_pitch((u16)width * format.channel_count * format.channel_size);
result->set_rsx_pitch((u16)pitch);
std::array<GLenum, 4> native_layout = { (GLenum)format.swizzle.a, (GLenum)format.swizzle.r, (GLenum)format.swizzle.g, (GLenum)format.swizzle.b };
result->set_native_component_layout(native_layout);
result->old_contents = old_surface;
result->set_old_contents(old_surface);
result->set_cleared(false);
result->update_surface();
@ -192,8 +192,7 @@ struct gl_render_target_traits
std::unique_ptr<gl::render_target> create_new_surface(
u32 address,
rsx::surface_depth_format surface_depth_format,
size_t width,
size_t height,
size_t width, size_t height, size_t pitch,
gl::render_target* old_surface
)
{
@ -207,8 +206,9 @@ struct gl_render_target_traits
std::array<GLenum, 4> native_layout = { GL_RED, GL_RED, GL_RED, GL_RED };
result->set_native_pitch(native_pitch);
result->set_rsx_pitch((u16)pitch);
result->set_native_component_layout(native_layout);
result->old_contents = old_surface;
result->set_old_contents(old_surface);
result->set_cleared(false);
result->update_surface();
@ -233,9 +233,16 @@ struct gl_render_target_traits
static void prepare_ds_for_sampling(void *, gl::render_target*) {}
static
void invalidate_surface_contents(u32 address, void *, gl::render_target *surface, gl::render_target* old_surface)
bool surface_is_pitch_compatible(const std::unique_ptr<gl::render_target> &surface, size_t pitch)
{
surface->old_contents = old_surface;
return surface->get_rsx_pitch() == pitch;
}
static
void invalidate_surface_contents(void *, gl::render_target *surface, gl::render_target* old_surface, u32 address, size_t pitch)
{
surface->set_rsx_pitch((u16)pitch);
surface->set_old_contents(old_surface);
surface->reset_aa_mode();
surface->queue_tag(address);
surface->set_cleared(false);

View File

@ -2923,7 +2923,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_surface_info[index].address = layout.color_addresses[index];
m_surface_info[index].pitch = layout.actual_color_pitch[index];
surface->rsx_pitch = layout.actual_color_pitch[index];
verify("Pitch mismatch!" HERE), surface->rsx_pitch == layout.actual_color_pitch[index];
surface->write_aa_mode = layout.aa_mode;
m_texture_cache.notify_surface_changed(layout.color_addresses[index]);
@ -2938,7 +2938,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_depth_surface_info.address = layout.zeta_address;
m_depth_surface_info.pitch = layout.actual_zeta_pitch;
ds->rsx_pitch = layout.actual_zeta_pitch;
verify("Pitch mismatch!" HERE), ds->rsx_pitch == layout.actual_zeta_pitch;
ds->write_aa_mode = layout.aa_mode;
m_texture_cache.notify_surface_changed(layout.zeta_address);
@ -3284,9 +3284,7 @@ void VKGSRender::flip(int buffer)
else
{
const auto overlap_info = m_rtts.get_merged_texture_memory_region(*m_current_command_buffer, absolute_address, buffer_width, buffer_height, buffer_pitch);
verify(HERE), !overlap_info.empty();
if (overlap_info.back().surface == render_target_texture)
if (!overlap_info.empty() && overlap_info.back().surface == render_target_texture)
{
// Confirmed to be the newest data source in that range
image_to_flip = render_target_texture;
@ -3324,7 +3322,7 @@ void VKGSRender::flip(int buffer)
// Read from cell
const auto range = utils::address_range::start_length(absolute_address, buffer_pitch * buffer_height);
const u32 lookup_mask = rsx::texture_upload_context::blit_engine_dst | rsx::texture_upload_context::framebuffer_storage;
const auto overlap = m_texture_cache.find_texture_from_range(range, 0, lookup_mask);
const auto overlap = m_texture_cache.find_texture_from_range<true>(range, 0, lookup_mask);
bool flush_queue = false;
for (const auto & section : overlap)

View File

@ -175,7 +175,7 @@ namespace rsx
static std::unique_ptr<vk::render_target> create_new_surface(
u32 address,
surface_color_format format,
size_t width, size_t height,
size_t width, size_t height, size_t pitch,
vk::render_target* old_surface,
vk::render_device &device, vk::command_buffer *cmd)
{
@ -197,10 +197,11 @@ namespace rsx
change_image_layout(*cmd, rtt.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
rtt->native_component_map = fmt.second;
rtt->rsx_pitch = (u16)pitch;
rtt->native_pitch = (u16)width * get_format_block_size_in_bytes(format);
rtt->surface_width = (u16)width;
rtt->surface_height = (u16)height;
rtt->old_contents = old_surface;
rtt->set_old_contents(old_surface);
rtt->queue_tag(address);
rtt->dirty = true;
@ -210,7 +211,7 @@ namespace rsx
static std::unique_ptr<vk::render_target> create_new_surface(
u32 address,
surface_depth_format format,
size_t width, size_t height,
size_t width, size_t height, size_t pitch,
vk::render_target* old_surface,
vk::render_device &device, vk::command_buffer *cmd)
{
@ -242,17 +243,17 @@ namespace rsx
ds->native_pitch *= 2;
ds->attachment_aspect_flag = range.aspectMask;
ds->rsx_pitch = (u16)pitch;
ds->surface_width = (u16)width;
ds->surface_height = (u16)height;
ds->old_contents = old_surface;
ds->set_old_contents(old_surface);
ds->queue_tag(address);
ds->dirty = true;
return ds;
}
static
void get_surface_info(vk::render_target *surface, rsx::surface_format_info *info)
static void get_surface_info(vk::render_target *surface, rsx::surface_format_info *info)
{
info->rsx_pitch = surface->rsx_pitch;
info->native_pitch = surface->native_pitch;
@ -293,24 +294,27 @@ namespace rsx
change_image_layout(*pcmd, surface, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range);
}
static
void invalidate_surface_contents(u32 address, vk::command_buffer* /*pcmd*/, vk::render_target *surface, vk::render_target *old_surface)
static bool surface_is_pitch_compatible(const std::unique_ptr<vk::render_target> &surface, size_t pitch)
{
surface->old_contents = old_surface;
return surface->rsx_pitch == pitch;
}
static void invalidate_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *surface, vk::render_target *old_surface, u32 address, size_t pitch)
{
surface->rsx_pitch = (u16)pitch;
surface->set_old_contents(old_surface);
surface->reset_aa_mode();
surface->queue_tag(address);
surface->dirty = true;
}
static
void notify_surface_invalidated(const std::unique_ptr<vk::render_target> &surface)
static 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
void notify_surface_persist(const std::unique_ptr<vk::render_target> &surface)
static void notify_surface_persist(const std::unique_ptr<vk::render_target> &surface)
{
surface->save_aa_mode();
}