rsx/vk: Implement rendering using no attachments

This commit is contained in:
kd-11
2026-10-10 10:30:35 +03:00
committed by kd-11
parent 0be621eb62
commit e38d27157e
3 changed files with 54 additions and 12 deletions
+21 -4
View File
@@ -1477,7 +1477,8 @@ namespace rsx
layout.width = rsx::method_registers.surface_clip_width();
layout.height = rsx::method_registers.surface_clip_height();
m_graphics_state.clear(rsx::rtt_config_contested | rsx::rtt_config_valid | rsx::rtt_config_no_attachments);
// NOTE: rtt_config_no_attachments is intentionally not reset.
m_graphics_state.clear(rsx::rtt_config_contested | rsx::rtt_config_valid);
m_current_framebuffer_context = context;
if (layout.width == 0 || layout.height == 0)
@@ -1801,7 +1802,22 @@ namespace rsx
}
// Context must be draw now...
m_graphics_state.set(rsx::rtt_config_no_attachments);
}
if (framebufferless != m_graphics_state.test(rsx::rtt_config_no_attachments))
{
// Programmable blending reads back from the color attachments and is disabled when there are none.
// Force the blend configuration to be re-evaluated when moving in or out of this state.
if (framebufferless)
{
m_graphics_state.set(rsx::rtt_config_no_attachments);
}
else
{
m_graphics_state.clear(rsx::rtt_config_no_attachments);
}
m_graphics_state.set(rsx::pipeline_config_dirty);
}
// At least one attachment exists
@@ -2145,8 +2161,9 @@ namespace rsx
{
u32 expected_ctrl = 0;
// Programmable blending
if (backend_config.supports_programmable_blending)
// Programmable blending. Requires color attachments to read from.
if (backend_config.supports_programmable_blending &&
!m_graphics_state.test(rsx::rtt_config_no_attachments))
{
expected_ctrl = current_fragment_program.ctrl & RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING;
+4 -3
View File
@@ -219,7 +219,9 @@ void VKGSRender::update_draw_state()
const auto polygon_offset_scale = rsx::method_registers.poly_offset_scale();
auto polygon_offset_bias = rsx::method_registers.poly_offset_bias();
if (m_draw_fbo->depth_format() == VK_FORMAT_D24_UNORM_S8_UINT && is_NVIDIA(vk::get_chip_family()))
if (!m_draw_fbo->attachments.empty() &&
m_draw_fbo->depth_format() == VK_FORMAT_D24_UNORM_S8_UINT &&
is_NVIDIA(vk::get_chip_family()))
{
// Empirically derived to be 0.5 * (2^24 - 1) for fixed type on Pascal. The same seems to apply for other NVIDIA GPUs.
// RSX seems to be using 2^24 - 1 instead making the biases twice as large when using fixed type Z-buffer on NVIDIA.
@@ -1261,7 +1263,6 @@ void VKGSRender::begin()
rsx::thread::begin();
if (skip_current_frame ||
swapchain_unavailable ||
cond_render_ctrl.disable_rendering())
{
return;
@@ -1279,7 +1280,7 @@ void VKGSRender::begin()
void VKGSRender::end()
{
if (skip_current_frame || !m_graphics_state.test(rsx::rtt_config_valid) || swapchain_unavailable || cond_render_ctrl.disable_rendering())
if (should_skip_draw())
{
execute_nop_draw();
rsx::thread::end();
+29 -5
View File
@@ -677,6 +677,21 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
backend_config.supports_hw_a2one = m_device->get_alpha_to_one_support();
}
// Framebufferless rendering. Zero-attachment subpasses can only rasterize at the sample counts reported for them.
const VkSampleCountFlags required_sample_counts = (g_cfg.video.antialiasing_level == msaa_level::_auto)
? VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT
: VK_SAMPLE_COUNT_1_BIT;
if (const auto supported_sample_counts = m_device->gpu().get_limits().framebufferNoAttachmentsSampleCounts & required_sample_counts;
supported_sample_counts == required_sample_counts)
{
backend_config.supports_framebufferless_rendering = true;
}
else
{
rsx_log.warning("Framebufferless rendering is not supported with the current MSAA configuration. Some occlusion queries may return incorrect results.");
}
// NOTE: On NVIDIA cards going back decades (including the PS3) there is a slight normalization inaccuracy in compressed formats.
// Confirmed in BLES01916 (The Evil Within) which uses RGB565 for some virtual texturing data.
backend_config.supports_hw_renormalization = vk::is_NVIDIA(vk::get_driver_vendor());
@@ -1299,7 +1314,7 @@ void VKGSRender::on_exit()
void VKGSRender::clear_surface(u32 mask)
{
if (skip_current_frame || swapchain_unavailable) return;
if (skip_current_frame) return;
// If stencil write mask is disabled, remove clear_stencil bit
if (!rsx::method_registers.stencil_mask()) mask &= ~RSX_GCM_CLEAR_STENCIL_BIT;
@@ -2709,7 +2724,19 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
std::iota(input_attachments.begin(), input_attachments.end(), 0);
}
m_current_renderpass_key = vk::get_renderpass_key(m_fbo_images, input_attachments);
if (m_graphics_state.test(rsx::rtt_config_no_attachments))
{
// Framebufferless rendering. The raster sample count must match what real surfaces would have used.
ensure(m_fbo_images.empty() && input_attachments.empty());
const u8 raster_samples = (g_cfg.video.antialiasing_level == msaa_level::_auto) ? samples : 1;
m_current_renderpass_key = vk::get_renderpass_key_no_attachments(raster_samples);
}
else
{
m_current_renderpass_key = vk::get_renderpass_key(m_fbo_images, input_attachments);
}
m_cached_renderpass = vk::get_renderpass(*m_device, m_current_renderpass_key);
// Search old framebuffers for this same configuration
@@ -2749,9 +2776,6 @@ void VKGSRender::renderctl(u32 request_code, void* args)
bool VKGSRender::scaled_image_from_memory(const rsx::blit_src_info& src, const rsx::blit_dst_info& dst, bool interpolate)
{
if (swapchain_unavailable)
return false;
if (m_texture_cache.blit(src, dst, interpolate, m_rtts, *m_current_command_buffer))
{
m_samplers_dirty.store(true);