Part 2 of enabling Atom to use TaskGraph
Enable Atom CullingScene to use TaskGraph Enable Atom PNG save to use TaskGraph for red/blue color channel swap on save out. Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com>
This commit is contained in:
@@ -363,7 +363,11 @@ namespace AZ
|
||||
{
|
||||
++m_graphsRemaining;
|
||||
|
||||
event->m_executor = this; // Used to validate event is not waited for inside a job
|
||||
if (event)
|
||||
{
|
||||
event->IncWaitCount();
|
||||
event->m_executor = this; // Used to validate event is not waited for inside a job
|
||||
}
|
||||
|
||||
// Submit all tasks that have no inbound edges
|
||||
for (Internal::Task& task : graph.Tasks())
|
||||
|
||||
@@ -20,6 +20,46 @@ namespace AZ
|
||||
m_semaphore.acquire();
|
||||
}
|
||||
|
||||
void TaskGraphEvent::IncWaitCount()
|
||||
{
|
||||
// guess zero to optimize for single task graph using an event, if multiple are using it then this will take 2+ comp_exch calls
|
||||
int expectedValue = 0;
|
||||
while(!m_waitCount.compare_exchange_weak(expectedValue, expectedValue + 1))
|
||||
{
|
||||
// value will be negative once event is ready to signal or has been signaled. Shouldn't happen.
|
||||
AZ_Assert(expectedValue >= 0, "Called TaskGraphEvent::IncWaitCount on a signalled event");
|
||||
if (expectedValue < 0) // event already signaled, skip
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void TaskGraphEvent::Signal()
|
||||
{
|
||||
// guess one to optimize for single task graph using an event, if multiple are using it then this will take 2+ comp_exch calls
|
||||
int expectedValue = 1;
|
||||
while(!m_waitCount.compare_exchange_weak(expectedValue, expectedValue - 1))
|
||||
{
|
||||
// It's an error for Signal to be called if no one is waiting, or the event has already been signaled
|
||||
AZ_Assert(expectedValue > 0, "Called TaskGraphEvent::Signal when event is either signaled or unused");
|
||||
if (expectedValue < 0) // return if already signaled
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if (expectedValue == 1) // This call to Signal decremented the value to 0.
|
||||
{
|
||||
expectedValue = 0;
|
||||
// validate no one incremented the wait count and mark signalling state
|
||||
if (m_waitCount.compare_exchange_strong(expectedValue, -1))
|
||||
{
|
||||
m_semaphore.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TaskToken::PrecedesInternal(TaskToken& comesAfter)
|
||||
{
|
||||
AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted.");
|
||||
|
||||
@@ -61,14 +61,14 @@ namespace AZ
|
||||
uint32_t m_index;
|
||||
};
|
||||
|
||||
// A TaskGraphEvent may be used to block until a task graph has finished executing. Usage
|
||||
// A TaskGraphEvent may be used to block until one or more task graphs has finished executing. Usage
|
||||
// is NOT recommended for the majority of tasks (prefer to simply containing expanding/contracting
|
||||
// the graph without synchronization over the course of the frame). However, the event
|
||||
// is useful for the edges of the computation graph.
|
||||
//
|
||||
// You are responsible for ensuring the event object lifetime exceeds the task graph lifetime.
|
||||
//
|
||||
// After the TaskGraphEvent is signaled, you are allowed to reuse the same TaskGraphEvent
|
||||
// After the TaskGraphEvent is signaled, you are NOT allowed to reuse the same TaskGraphEvent
|
||||
// for a future submission.
|
||||
class TaskGraphEvent
|
||||
{
|
||||
@@ -81,10 +81,12 @@ namespace AZ
|
||||
friend class TaskGraph;
|
||||
friend class TaskExecutor;
|
||||
|
||||
void IncWaitCount();
|
||||
void Signal();
|
||||
|
||||
AZStd::binary_semaphore m_semaphore;
|
||||
TaskExecutor* m_executor = nullptr;
|
||||
AZStd::atomic_int m_waitCount = 0;
|
||||
TaskExecutor* m_executor = nullptr;
|
||||
};
|
||||
|
||||
// The TaskGraph encapsulates a set of tasks and their interdependencies. After adding
|
||||
|
||||
@@ -33,11 +33,6 @@ namespace AZ
|
||||
return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 });
|
||||
}
|
||||
|
||||
inline void TaskGraphEvent::Signal()
|
||||
{
|
||||
m_semaphore.release();
|
||||
}
|
||||
|
||||
template<typename Lambda>
|
||||
TaskToken TaskGraph::AddTask(TaskDescriptor const& desc, Lambda&& lambda)
|
||||
{
|
||||
|
||||
@@ -610,15 +610,16 @@ namespace UnitTest
|
||||
g.Follows(e, f);
|
||||
g.Precedes(d);
|
||||
|
||||
TaskGraphEvent ev;
|
||||
graph.SubmitOnExecutor(*m_executor, &ev);
|
||||
ev.Wait();
|
||||
TaskGraphEvent ev1;
|
||||
graph.SubmitOnExecutor(*m_executor, &ev1);
|
||||
ev1.Wait();
|
||||
|
||||
EXPECT_EQ(3 | 0b100000, x);
|
||||
x = 0;
|
||||
|
||||
graph.SubmitOnExecutor(*m_executor, &ev);
|
||||
ev.Wait();
|
||||
TaskGraphEvent ev2;
|
||||
graph.SubmitOnExecutor(*m_executor, &ev2);
|
||||
ev2.Wait();
|
||||
|
||||
EXPECT_EQ(3 | 0b100000, x);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user