153 return m_jobData[jobHandle.id()];
156 return m_jobData[jobHandle.id()];
165 auto handle = m_jobData.
alloc(&ctx);
166 auto& j = m_jobData[handle.id()];
169 GAIA_ASSERT(j.state == 0 || j.state == JobState::Released);
172 j.prio = ctx.priority;
184 auto& jobData = m_jobData.
free(jobHandle);
185 GAIA_ASSERT(done(jobData));
186 jobData.state.store(JobState::Released);
197 if (jobData.
func.operator
bool())
205 const auto state = jobData.
state.fetch_sub(1) - 1;
208 const auto s = state & JobState::STATE_BITS_MASK;
209 if (s != JobState::Submitted)
213 const auto deps = state & JobState::DEP_BITS_MASK;
217 static void free_edges(JobContainer& jobData) {
219 if (jobData.edges.depCnt <= 1)
222 mem::AllocHelper::free(jobData.edges.pDeps);
242 GAIA_ASSERT(!jobsFirst.empty());
246 auto& secondData = data(jobSecond);
248#if GAIA_ASSERT_ENABLED
249 GAIA_ASSERT(!busy(
const_cast<const JobContainer&
>(secondData)));
250 for (
auto jobFirst: jobsFirst) {
251 const auto& firstData = data(jobFirst);
252 GAIA_ASSERT(!busy(firstData));
256 for (
auto jobFirst: jobsFirst)
257 dep_internal(jobFirst, jobSecond);
261 const uint32_t cnt = (uint32_t)jobsFirst.size();
262 [[maybe_unused]]
const uint32_t statePrev = secondData.state.fetch_add(cnt);
263 GAIA_ASSERT((statePrev & JobState::DEP_BITS_MASK) < DEP_BITS_MASK - 1);
273 GAIA_ASSERT(!jobsFirst.empty());
277 auto& secondData = data(jobSecond);
279#if GAIA_ASSERT_ENABLED
280 GAIA_ASSERT(!busy(
const_cast<const JobContainer&
>(secondData)));
281 for (
auto jobFirst: jobsFirst) {
282 const auto& firstData = data(jobFirst);
283 GAIA_ASSERT(!busy(firstData));
286 for (
auto jobFirst: jobsFirst)
287 dep_refresh_internal(jobFirst, jobSecond);
292 const uint32_t cnt = (uint32_t)jobsFirst.size();
293 [[maybe_unused]]
const uint32_t statePrev = secondData.state.fetch_add(cnt);
294 GAIA_ASSERT((statePrev & JobState::DEP_BITS_MASK) < DEP_BITS_MASK - 1);
298 [[maybe_unused]]
const auto state = jobData.
state.load() & JobState::STATE_BITS_MASK;
299 GAIA_ASSERT(state < JobState::Submitted);
300 const auto val = jobData.
state.fetch_add(JobState::Submitted) + (uint32_t)JobState::Submitted;
301#if GAIA_LOG_JOB_STATES
302 GAIA_LOG_N(
"JobHandle %u.%u - SUBMITTED", jobData.
idx, jobData.gen);
307 static void processing(JobContainer& jobData) {
308 GAIA_ASSERT(submitted(
const_cast<const JobContainer&
>(jobData)));
309 jobData.state.store(JobState::Processing);
310#if GAIA_LOG_JOB_STATES
311 GAIA_LOG_N(
"JobHandle %u.%u - PROCESSING", jobData.idx, jobData.gen);
315 static void executing(JobContainer& jobData, uint32_t workerIdx) {
316 GAIA_ASSERT(processing(
const_cast<const JobContainer&
>(jobData)));
317 jobData.state.store(JobState::Executing | workerIdx);
318#if GAIA_LOG_JOB_STATES
319 GAIA_LOG_N(
"JobHandle %u.%u - EXECUTING", jobData.idx, jobData.gen);
323 static void finalize(JobContainer& jobData) {
324 jobData.state.store(JobState::Done);
325#if GAIA_LOG_JOB_STATES
326 GAIA_LOG_N(
"JobHandle %u.%u - DONE", jobData.idx, jobData.gen);
330 static void reset_state(JobContainer& jobData) {
331 [[maybe_unused]]
const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
333 GAIA_ASSERT(state == 0 || state == JobState::Done);
334 jobData.state.store(0);
335#if GAIA_LOG_JOB_STATES
336 GAIA_LOG_N(
"JobHandle %u.%u - RESET_STATE", jobData.idx, jobData.gen);
340 GAIA_NODISCARD
bool is_clear(JobHandle jobHandle)
const {
341 const auto& jobData = data(jobHandle);
342 const auto state = jobData.state.load();
346 GAIA_NODISCARD
static bool is_clear(JobContainer& jobData) {
347 const auto state = jobData.state.load();
351 GAIA_NODISCARD
static bool submitted(
const JobContainer& jobData) {
352 const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
353 return state == JobState::Submitted;
356 GAIA_NODISCARD
static bool processing(
const JobContainer& jobData) {
357 const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
358 return state == JobState::Processing;
361 GAIA_NODISCARD
static bool busy(
const JobContainer& jobData) {
362 const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
363 return state == JobState::Executing || state == JobState::Processing;
366 GAIA_NODISCARD
static bool done(
const JobContainer& jobData) {
367 const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
368 return state == JobState::Done;
372 void dep_internal(JobHandle jobFirst, JobHandle jobSecond) {
373 GAIA_ASSERT(jobFirst != (JobHandle)JobNull_t{});
374 GAIA_ASSERT(jobSecond != (JobHandle)JobNull_t{});
376 auto& firstData = data(jobFirst);
377 const auto depCnt0 = firstData.edges.depCnt;
378 const auto depCnt1 = ++firstData.edges.depCnt;
380#if GAIA_LOG_JOB_STATES
382 "DEP %u.%u, %u -> %u.%u", jobFirst.id(), jobFirst.gen(), firstData.edges.depCnt, jobSecond.id(),
387 firstData.edges.dep = jobSecond;
388 }
else if (depCnt1 == 2) {
389 auto prev = firstData.edges.dep;
391 firstData.edges.pDeps = mem::AllocHelper::alloc<JobHandle>(depCnt1);
392 firstData.edges.pDeps[0] = prev;
393 firstData.edges.pDeps[1] = jobSecond;
396 const bool isPow2 = core::is_pow2(depCnt0);
398 const auto nextPow2 = depCnt0 << 1;
399 auto* pPrev = firstData.edges.pDeps;
401 firstData.edges.pDeps = mem::AllocHelper::alloc<JobHandle>(nextPow2);
402 if (pPrev !=
nullptr) {
403 GAIA_FOR(depCnt0) firstData.edges.pDeps[i] = pPrev[i];
404 mem::AllocHelper::free(pPrev);
409 firstData.edges.pDeps[depCnt0] = jobSecond;
413#if GAIA_ASSERT_ENABLED
414 void dep_refresh_internal(JobHandle jobFirst, JobHandle jobSecond)
const {
415 GAIA_ASSERT(jobFirst != (JobHandle)JobNull_t{});
416 GAIA_ASSERT(jobSecond != (JobHandle)JobNull_t{});
418 const auto& firstData = data(jobFirst);
419 const auto depCnt = firstData.edges.depCnt;
422 GAIA_ASSERT(firstData.edges.dep == jobSecond);
424 GAIA_ASSERT(firstData.edges.pDeps !=
nullptr);
426 GAIA_FOR(firstData.edges.depCnt) {
427 if (firstData.edges.pDeps[i] == jobSecond) {