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:
parent
1a44446250
commit
74eeacd091
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user