Preserve TAA pipelines when GPU visibility switch fails
This commit is contained in:
+28
-2
@@ -4168,11 +4168,37 @@ void Renderer::set_visibility_mode(VisibilityMode mode) {
|
||||
return;
|
||||
if (mode != VisibilityMode::Direct && impl_->scene.available &&
|
||||
!impl_->scene.graphics_layout) {
|
||||
check(vkDeviceWaitIdle(impl_->device), "Wait visibility switch");
|
||||
try {
|
||||
impl_->make_scene_descriptors_and_pipelines();
|
||||
if (impl_->temporal.resolve_layout) {
|
||||
impl_->destroy_temporal_interfaces();
|
||||
impl_->make_temporal_interfaces_and_pipelines();
|
||||
auto& temporal = impl_->temporal;
|
||||
// Retain the active pipelines and descriptor interfaces until the
|
||||
// GPU variant is complete; a bad shader package must leave TAA usable.
|
||||
const std::array<VkPipeline*, 5> pipelines{
|
||||
&temporal.resolve_pipeline, &temporal.composite_pipeline,
|
||||
&temporal.direct_pipeline, &temporal.transparent_pipeline,
|
||||
&temporal.gpu_pipeline};
|
||||
std::array<VkPipeline, 5> previous{};
|
||||
const auto previous_layouts = temporal.shader_layouts;
|
||||
const auto previous_scene_layouts = temporal.scene_shader_layouts;
|
||||
for (std::size_t i = 0; i < pipelines.size(); ++i)
|
||||
previous[i] = std::exchange(*pipelines[i], VkPipeline{});
|
||||
try {
|
||||
impl_->make_temporal_interfaces_and_pipelines();
|
||||
} catch (...) {
|
||||
for (std::size_t i = 0; i < pipelines.size(); ++i) {
|
||||
if (*pipelines[i])
|
||||
vkDestroyPipeline(impl_->device, *pipelines[i], nullptr);
|
||||
*pipelines[i] = previous[i];
|
||||
}
|
||||
temporal.shader_layouts = previous_layouts;
|
||||
temporal.scene_shader_layouts = previous_scene_layouts;
|
||||
throw;
|
||||
}
|
||||
for (auto pipeline : previous)
|
||||
if (pipeline)
|
||||
vkDestroyPipeline(impl_->device, pipeline, nullptr);
|
||||
}
|
||||
} catch (...) {
|
||||
impl_->destroy_scene_interfaces();
|
||||
|
||||
@@ -130,6 +130,46 @@ int main() {
|
||||
opaque_cube.instance_key = "shader-reload-cube";
|
||||
opaque_cube.cast_shadow = false;
|
||||
opaque_scene.draws.push_back(opaque_cube);
|
||||
{
|
||||
// Starting in Direct+Off defers GPU scene pipelines. Enabling TAA later
|
||||
// leaves an active temporal direct pipeline during the GPU-mode switch.
|
||||
render::Renderer switching(configuration);
|
||||
render::Renderer reference(configuration);
|
||||
switching.set_temporal_mode(render::TemporalMode::TAA);
|
||||
reference.set_temporal_mode(render::TemporalMode::TAA);
|
||||
for (int frame = 0; frame < 2; ++frame) {
|
||||
switching.render(opaque_scene);
|
||||
reference.render(opaque_scene);
|
||||
}
|
||||
require(switching.stats().effective_temporal_mode == render::TemporalMode::TAA &&
|
||||
switching.stats().temporal_history_valid,
|
||||
"Visibility rollback fixture must have live TAA history");
|
||||
const auto temporal_spirv = read_text(bundle / "temporalResolveMain.spv");
|
||||
fs::remove(native_io_path(bundle / "temporalResolveMain.spv"));
|
||||
bool rejected_temporal_switch = false;
|
||||
try {
|
||||
switching.set_visibility_mode(render::VisibilityMode::GpuFrustum);
|
||||
} catch (const std::exception&) {
|
||||
rejected_temporal_switch = true;
|
||||
}
|
||||
atomic_write(bundle / "temporalResolveMain.spv", temporal_spirv);
|
||||
require(rejected_temporal_switch,
|
||||
"Incomplete temporal package must reject a GPU visibility switch");
|
||||
switching.render(opaque_scene);
|
||||
reference.render(opaque_scene);
|
||||
require(switching.visibility_mode() == render::VisibilityMode::Direct &&
|
||||
switching.stats().effective_temporal_mode == render::TemporalMode::TAA &&
|
||||
switching.stats().validation_errors == 0 &&
|
||||
switching.pixels() == reference.pixels(),
|
||||
"Rejected GPU visibility switch must preserve active TAA rendering");
|
||||
switching.set_visibility_mode(render::VisibilityMode::GpuFrustum);
|
||||
switching.render(opaque_scene);
|
||||
require(switching.stats().effective_visibility_mode ==
|
||||
render::VisibilityMode::GpuFrustum &&
|
||||
switching.stats().effective_temporal_mode == render::TemporalMode::TAA &&
|
||||
switching.stats().validation_errors == 0,
|
||||
"Restored temporal package must allow retrying GPU visibility with TAA");
|
||||
}
|
||||
auto temporal_configuration = configuration;
|
||||
temporal_configuration.temporal_mode = render::TemporalMode::TAA;
|
||||
render::Renderer temporal_renderer(temporal_configuration);
|
||||
|
||||
Reference in New Issue
Block a user