Skip to content

Commit 0500042

Browse files
committed
Fixed deadlock on graph objects. (I knew it was coming)
1 parent b328f08 commit 0500042

File tree

5 files changed

+33
-22
lines changed

5 files changed

+33
-22
lines changed

source/code/iceshard/engine/private/gfx/ice_gfx_graph.cxx

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,10 @@ namespace ice::gfx
214214

215215
IceshardGfxGraphRuntime::~IceshardGfxGraphRuntime() noexcept
216216
{
217-
// If there is still stages initializing we want to wait for them, so we don't end up with accessing
218-
// '_stages._ready' field after a free.
219-
ice::u32 in_progress = _stages._ready.load(std::memory_order_relaxed);
220-
while(in_progress > 0)
221-
{
222-
// Wait if we still have values in progress
223-
_stages._ready.wait(in_progress, std::memory_order_relaxed);
224-
// Get the new count to dobule check we are in the clear.
225-
in_progress = _stages._ready.load(std::memory_order_relaxed);
226-
}
217+
ICE_ASSERT(
218+
this->ready(),
219+
"Graphics Graph destroyed before all tasks finished executing! Possible read/write memory access errors!"
220+
);
227221

228222
render::RenderDevice& device = _context.device();
229223

@@ -244,18 +238,15 @@ namespace ice::gfx
244238
device.destroy_renderpass(_renderpass);
245239
}
246240

241+
bool IceshardGfxGraphRuntime::ready() const noexcept
242+
{
243+
return _stages._ready.load(std::memory_order_relaxed) == 0;
244+
}
245+
247246
auto initialize_stage(ice::Task<> init_task, std::atomic_uint32_t& ready_count) noexcept -> ice::Task<>
248247
{
249248
co_await init_task;
250-
251-
// If the last stage is finalized we want to send a notification. This is because the graph
252-
// could be waiting in the descrutor when a new graph want's to be initialized.
253-
// This may happen during manual resizing the window, so it's probably only an issues during dev-time
254-
// since users should only resize using a in-game menu option.
255-
if (ready_count.fetch_sub(1, std::memory_order_relaxed) == 1)
256-
{
257-
ready_count.notify_one();
258-
}
249+
ready_count.fetch_sub(1, std::memory_order_relaxed);
259250
}
260251

261252
bool IceshardGfxGraphRuntime::prepare(

source/code/iceshard/engine/private/gfx/ice_gfx_graph_runtime.hxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ namespace ice::gfx
8080
) noexcept;
8181
~IceshardGfxGraphRuntime() noexcept override;
8282

83+
bool ready() const noexcept override;
84+
8385
bool prepare(
8486
ice::gfx::GfxFrameStages& stages,
8587
ice::gfx::GfxStageRegistry const& stage_registry,

source/code/iceshard/engine/public/ice/gfx/gfx_graph_runtime.hxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ namespace ice::gfx
1717
{
1818
virtual ~GfxGraphRuntime() noexcept = default;
1919

20+
//! \brief Checks if the graph is ready and all preparation tasks finished executing.
21+
virtual bool ready() const noexcept = 0;
22+
2023
//! \brief Prepares the runtime for the next execution phase.
2124
//! \details The runtime will check and prepare the graph for execution if all necessary stages are available and everything was initialized.
2225
//! In the case where some stages are still not available, the execute will be skipped.

source/code/iceshard/iceshard/private/iceshard_gfx_runner.cxx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,15 @@ namespace ice::gfx
132132
}
133133
}
134134

135-
_rendergraph = ice::move(rendergraph);
135+
// If we are ready we can set the rendergraph immediately, if not we schedule it for later to be updated.
136+
if (_rendergraph == nullptr || _rendergraph->ready())
137+
{
138+
_rendergraph = ice::move(rendergraph);
139+
}
140+
else
141+
{
142+
_scheduled_rendergraph = ice::move(rendergraph);
143+
}
136144
}
137145

138146
auto IceshardGfxRunner::update_data(
@@ -209,7 +217,13 @@ namespace ice::gfx
209217
ice::execute_tasks(tasks);
210218
}
211219

212-
if (_rendergraph->prepare(gpu_stages, *_stages, _gfx_tasks))
220+
// Check if we have a scheduled render graph and if we can replace
221+
if (_scheduled_rendergraph != nullptr && _rendergraph->ready())
222+
{
223+
_rendergraph = ice::move(_scheduled_rendergraph);
224+
}
225+
226+
if (_scheduled_rendergraph == nullptr && _rendergraph->prepare(gpu_stages, *_stages, _gfx_tasks))
213227
{
214228
IPT_ZONE_SCOPED_NAMED("gfx_resume_prepare_tasks");
215229
// The tasks here might take more than a frame to finish. We should track them somewhere else.
@@ -255,7 +269,7 @@ namespace ice::gfx
255269
// Execute all stages (currently done simply going over the render graph)
256270
_present_fence->reset();
257271

258-
if (_rendergraph->execute(frame, *_present_fence))
272+
if (_scheduled_rendergraph == nullptr && _rendergraph->execute(frame, *_present_fence))
259273
{
260274
_rendergraph->present();
261275
}

source/code/iceshard/iceshard/private/iceshard_gfx_runner.hxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ namespace ice::gfx
8888
ice::gfx::IceshardGfxRunnerState _state;
8989
ice::HashMap<ice::gfx::IceshardGfxWorldState> _world_states;
9090
ice::UniquePtr<ice::gfx::GfxGraphRuntime> _rendergraph;
91+
ice::UniquePtr<ice::gfx::GfxGraphRuntime> _scheduled_rendergraph;
9192

9293
ice::ScopedTaskContainer _gfx_tasks;
9394

0 commit comments

Comments
 (0)