mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 11:36:13 +00:00
rsx: Add more validation to framebuffer setups. Game devs sometimes do crazy things
This commit is contained in:
parent
0aaae000b3
commit
8646f51fa3
3 changed files with 83 additions and 114 deletions
|
@ -176,10 +176,21 @@ void GLGSRender::init_buffers(bool skip_reading)
|
|||
return;
|
||||
}
|
||||
|
||||
const auto surface_addresses = get_color_surface_addresses();
|
||||
const auto depth_address = get_zeta_surface_address();
|
||||
auto surface_addresses = get_color_surface_addresses();
|
||||
auto depth_address = get_zeta_surface_address();
|
||||
|
||||
for (const auto &addr: surface_addresses)
|
||||
const auto pitchs = get_pitchs();
|
||||
const auto zeta_pitch = rsx::method_registers.surface_z_pitch();
|
||||
const auto surface_format = rsx::method_registers.surface_color();
|
||||
const auto depth_format = rsx::method_registers.surface_depth_fmt();
|
||||
|
||||
const auto required_color_pitch = rsx::utility::get_packed_pitch(surface_format, clip_horizontal);
|
||||
const auto required_z_pitch = depth_format == rsx::surface_depth_format::z16 ? clip_horizontal * 2 : clip_horizontal * 4;
|
||||
|
||||
if (depth_address && zeta_pitch < required_z_pitch)
|
||||
depth_address = 0;
|
||||
|
||||
for (const auto &addr : surface_addresses)
|
||||
{
|
||||
if (addr)
|
||||
{
|
||||
|
@ -188,13 +199,23 @@ void GLGSRender::init_buffers(bool skip_reading)
|
|||
}
|
||||
}
|
||||
|
||||
for (const auto &index : rsx::utility::get_rtt_indexes(rsx::method_registers.surface_color_target()))
|
||||
{
|
||||
if (pitchs[index] < 64)
|
||||
surface_addresses[index] = 0;
|
||||
|
||||
if (surface_addresses[index] == depth_address &&
|
||||
zeta_pitch >= required_z_pitch)
|
||||
{
|
||||
LOG_ERROR(RSX, "Some game dev set up the MRT to write to the same address as depth and color attachment. Not sure how to deal with that so the draw is discarded.");
|
||||
framebuffer_status_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!framebuffer_status_valid && !depth_address)
|
||||
return;
|
||||
|
||||
const auto pitchs = get_pitchs();
|
||||
const auto surface_format = rsx::method_registers.surface_color();
|
||||
const auto depth_format = rsx::method_registers.surface_depth_fmt();
|
||||
|
||||
m_rtts.prepare_render_target(nullptr, surface_format, depth_format, clip_horizontal, clip_vertical,
|
||||
rsx::method_registers.surface_color_target(),
|
||||
surface_addresses, depth_address);
|
||||
|
@ -230,28 +251,12 @@ void GLGSRender::init_buffers(bool skip_reading)
|
|||
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)
|
||||
if (pitchs[i] <= 64)
|
||||
{
|
||||
const u16 native_pitch = std::get<1>(m_rtts.m_bound_render_targets[i])->get_native_pitch();
|
||||
if (native_pitch > pitchs[i])
|
||||
{
|
||||
LOG_TRACE(RSX, "Bad color surface pitch given: surface_width=%d, format=%d, pitch=%d, native_pitch=%d",
|
||||
clip_horizontal, (u32)surface_format, pitchs[i], native_pitch);
|
||||
|
||||
//Will not transfer this surface between cell and rsx due to misalignment
|
||||
//TODO: Verify correct behaviour
|
||||
surface_info[i].pitch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rtt->tile = find_tile(color_offsets[i], color_locations[i]);
|
||||
rtt->aa_mode = aa_mode;
|
||||
rtt->set_raster_offset(clip_x, clip_y, bpp);
|
||||
m_gl_texture_cache.notify_surface_changed(surface_addresses[i]);
|
||||
|
||||
if (surface_info[i].pitch)
|
||||
m_gl_texture_cache.tag_framebuffer(surface_addresses[i] + rtt->raster_address_offset);
|
||||
m_gl_texture_cache.tag_framebuffer(surface_addresses[i] + rtt->raster_address_offset);
|
||||
}
|
||||
else
|
||||
surface_info[i] = {};
|
||||
|
@ -274,27 +279,11 @@ void GLGSRender::init_buffers(bool skip_reading)
|
|||
std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(rsx::method_registers.surface_z_pitch());
|
||||
depth_surface_info = { depth_address, depth_surface_pitch, true, surface_format, depth_format, clip_horizontal, clip_vertical };
|
||||
|
||||
//Verify pitch given is correct if pitch <= 64 (especially 64)
|
||||
if (depth_surface_pitch <= 64)
|
||||
{
|
||||
const u16 native_pitch = std::get<1>(m_rtts.m_bound_depth_stencil)->get_native_pitch();
|
||||
if (native_pitch > depth_surface_pitch)
|
||||
{
|
||||
LOG_TRACE(RSX, "Bad depth surface pitch given: surface_width=%d, format=%d, pitch=%d, native_pitch=%d",
|
||||
clip_horizontal, (u32)depth_format, depth_surface_pitch, native_pitch);
|
||||
|
||||
//Will not transfer this surface between cell and rsx due to misalignment
|
||||
//TODO: Verify correct behaviour
|
||||
depth_surface_info.pitch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ds->aa_mode = aa_mode;
|
||||
ds->set_raster_offset(clip_x, clip_y, texel_size);
|
||||
m_gl_texture_cache.notify_surface_changed(depth_address);
|
||||
|
||||
if (depth_surface_info.pitch)
|
||||
m_gl_texture_cache.tag_framebuffer(depth_address + ds->raster_address_offset);
|
||||
m_gl_texture_cache.tag_framebuffer(depth_address + ds->raster_address_offset);
|
||||
}
|
||||
else
|
||||
depth_surface_info = {};
|
||||
|
|
|
@ -200,28 +200,6 @@ namespace vk
|
|||
return color_count + 5 * depth_format_idx + 5 * 3 * color_format_idx;
|
||||
}
|
||||
|
||||
std::vector<u8> get_draw_buffers(rsx::surface_target fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case rsx::surface_target::none:
|
||||
return{};
|
||||
case rsx::surface_target::surface_a:
|
||||
return{ 0 };
|
||||
case rsx::surface_target::surface_b:
|
||||
return{ 1 };
|
||||
case rsx::surface_target::surfaces_a_b:
|
||||
return{ 0, 1 };
|
||||
case rsx::surface_target::surfaces_a_b_c:
|
||||
return{ 0, 1, 2 };
|
||||
case rsx::surface_target::surfaces_a_b_c_d:
|
||||
return{ 0, 1, 2, 3 };
|
||||
default:
|
||||
LOG_ERROR(RSX, "Bad surface color target: %d", (u32)fmt);
|
||||
return{};
|
||||
}
|
||||
}
|
||||
|
||||
VkLogicOp get_logic_op(rsx::logic_op op)
|
||||
{
|
||||
switch (op)
|
||||
|
@ -1072,15 +1050,9 @@ void VKGSRender::begin_render_pass()
|
|||
if (render_pass_open)
|
||||
return;
|
||||
|
||||
size_t idx = vk::get_render_pass_location(
|
||||
vk::get_compatible_surface_format(rsx::method_registers.surface_color()).first,
|
||||
vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, rsx::method_registers.surface_depth_fmt()),
|
||||
(u8)m_draw_buffers_count);
|
||||
VkRenderPass current_render_pass = m_render_passes[idx];
|
||||
|
||||
VkRenderPassBeginInfo rp_begin = {};
|
||||
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
rp_begin.renderPass = current_render_pass;
|
||||
rp_begin.renderPass = m_draw_fbo->info.renderPass;
|
||||
rp_begin.framebuffer = m_draw_fbo->value;
|
||||
rp_begin.renderArea.offset.x = 0;
|
||||
rp_begin.renderArea.offset.y = 0;
|
||||
|
@ -1401,7 +1373,7 @@ void VKGSRender::end()
|
|||
//Clear any 'dirty' surfaces - possible is a recycled cache surface is used
|
||||
std::vector<VkClearAttachment> buffers_to_clear;
|
||||
buffers_to_clear.reserve(4);
|
||||
const auto targets = vk::get_draw_buffers(rsx::method_registers.surface_color_target());
|
||||
const auto targets = rsx::utility::get_rtt_indexes(rsx::method_registers.surface_color_target());
|
||||
|
||||
if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil))
|
||||
{
|
||||
|
@ -1603,7 +1575,7 @@ void VKGSRender::clear_surface(u32 mask)
|
|||
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);
|
||||
VkClearRect region = { { { scissor_x, scissor_y },{ scissor_w, scissor_h } }, 0, 1 };
|
||||
|
||||
auto targets = vk::get_draw_buffers(rsx::method_registers.surface_color_target());
|
||||
auto targets = rsx::utility::get_rtt_indexes(rsx::method_registers.surface_color_target());
|
||||
auto surface_depth_format = rsx::method_registers.surface_depth_fmt();
|
||||
|
||||
if (mask & 0x1)
|
||||
|
@ -2192,13 +2164,8 @@ void VKGSRender::load_program(u32 vertex_count, u32 vertex_base)
|
|||
|
||||
properties.rs.frontFace = vk::get_front_face(rsx::method_registers.front_face_mode());
|
||||
|
||||
size_t idx = vk::get_render_pass_location(
|
||||
vk::get_compatible_surface_format(rsx::method_registers.surface_color()).first,
|
||||
vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, rsx::method_registers.surface_depth_fmt()),
|
||||
(u8)m_draw_buffers_count);
|
||||
|
||||
properties.render_pass = m_render_passes[idx];
|
||||
properties.render_pass_location = (int)idx;
|
||||
properties.render_pass = m_render_passes[m_current_renderpass_id];
|
||||
properties.render_pass_location = (int)m_current_renderpass_id;
|
||||
|
||||
properties.num_targets = m_draw_buffers_count;
|
||||
|
||||
|
@ -2358,6 +2325,18 @@ void VKGSRender::prepare_rtts()
|
|||
auto surface_addresses = get_color_surface_addresses();
|
||||
auto zeta_address = get_zeta_surface_address();
|
||||
|
||||
const auto zeta_pitch = rsx::method_registers.surface_z_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() };
|
||||
|
||||
const auto color_fmt = rsx::method_registers.surface_color();
|
||||
const auto depth_fmt = rsx::method_registers.surface_depth_fmt();
|
||||
|
||||
const auto required_z_pitch = depth_fmt == rsx::surface_depth_format::z16 ? clip_width * 2 : clip_width * 4;
|
||||
|
||||
if (zeta_address && zeta_pitch < required_z_pitch)
|
||||
zeta_address = 0;
|
||||
|
||||
for (const auto &addr: surface_addresses)
|
||||
{
|
||||
if (addr)
|
||||
|
@ -2367,14 +2346,25 @@ void VKGSRender::prepare_rtts()
|
|||
}
|
||||
}
|
||||
|
||||
for (const auto &index : rsx::utility::get_rtt_indexes(rsx::method_registers.surface_color_target()))
|
||||
{
|
||||
if (surface_pitchs[index] < 64)
|
||||
surface_addresses[index] = 0;
|
||||
|
||||
if (surface_addresses[index] == zeta_address &&
|
||||
zeta_pitch >= required_z_pitch)
|
||||
{
|
||||
LOG_ERROR(RSX, "Some game dev set up the MRT to write to the same address as depth and color attachment. Not sure how to deal with that so the draw is discarded.");
|
||||
framebuffer_status_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!framebuffer_status_valid && !zeta_address)
|
||||
return;
|
||||
|
||||
//At least one attachment exists
|
||||
framebuffer_status_valid = true;
|
||||
|
||||
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() };
|
||||
|
||||
const auto fbo_width = rsx::apply_resolution_scale(clip_width, true);
|
||||
const auto fbo_height = rsx::apply_resolution_scale(clip_height, true);
|
||||
|
@ -2406,9 +2396,6 @@ void VKGSRender::prepare_rtts()
|
|||
}
|
||||
}
|
||||
|
||||
const auto color_fmt = rsx::method_registers.surface_color();
|
||||
const auto depth_fmt = rsx::method_registers.surface_depth_fmt();
|
||||
|
||||
m_rtts.prepare_render_target(&*m_current_command_buffer,
|
||||
color_fmt, depth_fmt,
|
||||
clip_width, clip_height,
|
||||
|
@ -2442,10 +2429,8 @@ void VKGSRender::prepare_rtts()
|
|||
m_depth_surface_info.depth_format = depth_fmt;
|
||||
|
||||
//Bind created rtts as current fbo...
|
||||
std::vector<u8> draw_buffers = vk::get_draw_buffers(rsx::method_registers.surface_color_target());
|
||||
|
||||
//Search old framebuffers for this same configuration
|
||||
bool framebuffer_found = false;
|
||||
std::vector<u8> draw_buffers = rsx::utility::get_rtt_indexes(rsx::method_registers.surface_color_target());
|
||||
m_draw_buffers_count = 0;
|
||||
|
||||
std::vector<vk::image*> bound_images;
|
||||
bound_images.reserve(5);
|
||||
|
@ -2454,26 +2439,21 @@ void VKGSRender::prepare_rtts()
|
|||
|
||||
for (u8 index : draw_buffers)
|
||||
{
|
||||
auto surface = std::get<1>(m_rtts.m_bound_render_targets[index]);
|
||||
bound_images.push_back(surface);
|
||||
|
||||
m_surface_info[index].address = surface_addresses[index];
|
||||
m_surface_info[index].pitch = surface_pitchs[index];
|
||||
surface->rsx_pitch = surface_pitchs[index];
|
||||
|
||||
if (surface_pitchs[index] <= 64)
|
||||
if (auto surface = std::get<1>(m_rtts.m_bound_render_targets[index]))
|
||||
{
|
||||
if (clip_width > surface_pitchs[index])
|
||||
//Ignore this buffer (usually set to 64)
|
||||
m_surface_info[index].pitch = 0;
|
||||
}
|
||||
bound_images.push_back(surface);
|
||||
|
||||
surface->aa_mode = aa_mode;
|
||||
surface->set_raster_offset(clip_x, clip_y, bpp);
|
||||
m_texture_cache.notify_surface_changed(surface_addresses[index]);
|
||||
m_surface_info[index].address = surface_addresses[index];
|
||||
m_surface_info[index].pitch = surface_pitchs[index];
|
||||
surface->rsx_pitch = surface_pitchs[index];
|
||||
|
||||
surface->aa_mode = aa_mode;
|
||||
surface->set_raster_offset(clip_x, clip_y, bpp);
|
||||
m_texture_cache.notify_surface_changed(surface_addresses[index]);
|
||||
|
||||
if (m_surface_info[index].pitch)
|
||||
m_texture_cache.tag_framebuffer(surface_addresses[index] + surface->raster_address_offset);
|
||||
m_draw_buffers_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (std::get<0>(m_rtts.m_bound_depth_stencil) != 0)
|
||||
|
@ -2485,19 +2465,13 @@ void VKGSRender::prepare_rtts()
|
|||
m_depth_surface_info.pitch = rsx::method_registers.surface_z_pitch();
|
||||
ds->rsx_pitch = m_depth_surface_info.pitch;
|
||||
|
||||
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;
|
||||
ds->set_raster_offset(clip_x, clip_y, get_pixel_size(rsx::method_registers.surface_depth_fmt()));
|
||||
m_texture_cache.notify_surface_changed(zeta_address);
|
||||
|
||||
if (m_depth_surface_info.pitch)
|
||||
m_texture_cache.tag_framebuffer(zeta_address + ds->raster_address_offset);
|
||||
m_texture_cache.tag_framebuffer(zeta_address + ds->raster_address_offset);
|
||||
}
|
||||
|
||||
m_draw_buffers_count = static_cast<u32>(draw_buffers.size());
|
||||
|
||||
if (g_cfg.video.write_color_buffers)
|
||||
{
|
||||
const auto color_fmt_info = vk::get_compatible_gcm_format(color_fmt);
|
||||
|
@ -2530,6 +2504,12 @@ void VKGSRender::prepare_rtts()
|
|||
}
|
||||
}
|
||||
|
||||
auto vk_depth_format = (zeta_address == 0) ? VK_FORMAT_UNDEFINED : vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, depth_fmt);
|
||||
m_current_renderpass_id = vk::get_render_pass_location(vk::get_compatible_surface_format(color_fmt).first, vk_depth_format, m_draw_buffers_count);
|
||||
|
||||
//Search old framebuffers for this same configuration
|
||||
bool framebuffer_found = false;
|
||||
|
||||
for (auto &fbo : m_framebuffers_to_clean)
|
||||
{
|
||||
if (fbo->matches(bound_images, fbo_width, fbo_height))
|
||||
|
@ -2574,8 +2554,7 @@ void VKGSRender::prepare_rtts()
|
|||
fbo_images.push_back(std::make_unique<vk::image_view>(*m_device, raw->value, VK_IMAGE_VIEW_TYPE_2D, raw->info.format, vk::default_component_map(), subres));
|
||||
}
|
||||
|
||||
size_t idx = vk::get_render_pass_location(vk::get_compatible_surface_format(color_fmt).first, vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, rsx::method_registers.surface_depth_fmt()), (u8)draw_buffers.size());
|
||||
VkRenderPass current_render_pass = m_render_passes[idx];
|
||||
VkRenderPass current_render_pass = m_render_passes[m_current_renderpass_id];
|
||||
|
||||
if (m_draw_fbo)
|
||||
m_framebuffers_to_clean.push_back(std::move(m_draw_fbo));
|
||||
|
|
|
@ -277,6 +277,7 @@ private:
|
|||
std::atomic<u64> m_last_sync_event = { 0 };
|
||||
|
||||
bool render_pass_open = false;
|
||||
size_t m_current_renderpass_id = 0;
|
||||
|
||||
//Vertex layout
|
||||
rsx::vertex_input_layout m_vertex_layout;
|
||||
|
|
Loading…
Add table
Reference in a new issue