158 return m_jobData[jobHandle.id()];
161 return m_jobData[jobHandle.id()];
170 auto handle = m_jobData.
alloc(&ctx);
171 auto& j = m_jobData[handle.id()];
174 GAIA_ASSERT(j.state == 0 || j.state == JobState::Released);
177 j.prio = ctx.priority;
189 auto& jobData = m_jobData.
free(jobHandle);
190 GAIA_ASSERT(done(jobData));
191 jobData.state.store(JobState::Released);
202 if (jobData.
func.operator
bool())
210 const auto state = jobData.
state.fetch_sub(1) - 1;
213 const auto s = state & JobState::STATE_BITS_MASK;
214 if (s != JobState::Submitted)
218 const auto deps = state & JobState::DEP_BITS_MASK;
222 static void free_edges(JobContainer& jobData) {
224 if (jobData.edges.depCnt <= 1)
227 mem::AllocHelper::free(jobData.edges.pDeps);
247 GAIA_ASSERT(!jobsFirst.empty());
251 auto& secondData = data(jobSecond);
253#if GAIA_ASSERT_ENABLED
254 GAIA_ASSERT(!busy(
const_cast<const JobContainer&
>(secondData)));
255 for (
auto jobFirst: jobsFirst) {
256 const auto& firstData = data(jobFirst);
257 GAIA_ASSERT(!busy(firstData));
261 for (
auto jobFirst: jobsFirst)
262 dep_internal(jobFirst, jobSecond);
266 const uint32_t cnt = (uint32_t)jobsFirst.size();
267 [[maybe_unused]]
const uint32_t statePrev = secondData.state.fetch_add(cnt);
268 GAIA_ASSERT((statePrev & JobState::DEP_BITS_MASK) < DEP_BITS_MASK - 1);
278 GAIA_ASSERT(!jobsFirst.empty());
282 auto& secondData = data(jobSecond);
284#if GAIA_ASSERT_ENABLED
285 GAIA_ASSERT(!busy(
const_cast<const JobContainer&
>(secondData)));
286 for (
auto jobFirst: jobsFirst) {
287 const auto& firstData = data(jobFirst);
288 GAIA_ASSERT(!busy(firstData));
291 for (
auto jobFirst: jobsFirst)
292 dep_refresh_internal(jobFirst, jobSecond);
297 const uint32_t cnt = (uint32_t)jobsFirst.size();
298 [[maybe_unused]]
const uint32_t statePrev = secondData.state.fetch_add(cnt);
299 GAIA_ASSERT((statePrev & JobState::DEP_BITS_MASK) < DEP_BITS_MASK - 1);
303 [[maybe_unused]]
const auto state = jobData.
state.load() & JobState::STATE_BITS_MASK;
304 GAIA_ASSERT(state < JobState::Submitted);
305 const auto val = jobData.
state.fetch_add(JobState::Submitted) + (uint32_t)JobState::Submitted;
306#if GAIA_LOG_JOB_STATES
307 GAIA_LOG_N(
"JobHandle %u.%u - SUBMITTED", jobData.
idx, jobData.gen);
312 static void processing(JobContainer& jobData) {
313 GAIA_ASSERT(submitted(
const_cast<const JobContainer&
>(jobData)));
314 jobData.state.store(JobState::Processing);
315#if GAIA_LOG_JOB_STATES
316 GAIA_LOG_N(
"JobHandle %u.%u - PROCESSING", jobData.idx, jobData.gen);
320 static void executing(JobContainer& jobData, uint32_t workerIdx) {
321 GAIA_ASSERT(processing(
const_cast<const JobContainer&
>(jobData)));
322 jobData.state.store(JobState::Executing | workerIdx);
323#if GAIA_LOG_JOB_STATES
324 GAIA_LOG_N(
"JobHandle %u.%u - EXECUTING", jobData.idx, jobData.gen);
328 static void finalize(JobContainer& jobData) {
329 jobData.state.store(JobState::Done);
330#if GAIA_LOG_JOB_STATES
331 GAIA_LOG_N(
"JobHandle %u.%u - DONE", jobData.idx, jobData.gen);
335 static void reset_state(JobContainer& jobData) {
336 [[maybe_unused]]
const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
338 GAIA_ASSERT(state == 0 || state == JobState::Done);
339 jobData.state.store(0);
340#if GAIA_LOG_JOB_STATES
341 GAIA_LOG_N(
"JobHandle %u.%u - RESET_STATE", jobData.idx, jobData.gen);
345 GAIA_NODISCARD
bool is_clear(JobHandle jobHandle)
const {
346 const auto& jobData = data(jobHandle);
347 const auto state = jobData.state.load();
351 GAIA_NODISCARD
static bool is_clear(JobContainer& jobData) {
352 const auto state = jobData.state.load();
356 GAIA_NODISCARD
static bool submitted(
const JobContainer& jobData) {
357 const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
358 return state == JobState::Submitted;
361 GAIA_NODISCARD
static bool processing(
const JobContainer& jobData) {
362 const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
363 return state == JobState::Processing;
366 GAIA_NODISCARD
static bool busy(
const JobContainer& jobData) {
367 const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
368 return state == JobState::Executing || state == JobState::Processing;
371 GAIA_NODISCARD
static bool done(
const JobContainer& jobData) {
372 const auto state = jobData.state.load() & JobState::STATE_BITS_MASK;
373 return state == JobState::Done;
377 void dep_internal(JobHandle jobFirst, JobHandle jobSecond) {
378 GAIA_ASSERT(jobFirst != (JobHandle)JobNull_t{});
379 GAIA_ASSERT(jobSecond != (JobHandle)JobNull_t{});
381 auto& firstData = data(jobFirst);
382 const auto depCnt0 = firstData.edges.depCnt;
383 const auto depCnt1 = ++firstData.edges.depCnt;
385#if GAIA_LOG_JOB_STATES
387 "DEP %u.%u, %u -> %u.%u", jobFirst.id(), jobFirst.gen(), firstData.edges.depCnt, jobSecond.id(),
392 firstData.edges.dep = jobSecond;
393 }
else if (depCnt1 == 2) {
394 auto prev = firstData.edges.dep;
396 firstData.edges.pDeps = mem::AllocHelper::alloc<JobHandle>(depCnt1);
397 firstData.edges.pDeps[0] = prev;
398 firstData.edges.pDeps[1] = jobSecond;
401 const bool isPow2 = core::is_pow2(depCnt0);
403 const auto nextPow2 = depCnt0 << 1;
404 auto* pPrev = firstData.edges.pDeps;
406 firstData.edges.pDeps = mem::AllocHelper::alloc<JobHandle>(nextPow2);
407 if (pPrev !=
nullptr) {
408 GAIA_FOR(depCnt0) firstData.edges.pDeps[i] = pPrev[i];
409 mem::AllocHelper::free(pPrev);
414 firstData.edges.pDeps[depCnt0] = jobSecond;
418#if GAIA_ASSERT_ENABLED
419 void dep_refresh_internal(JobHandle jobFirst, JobHandle jobSecond)
const {
420 GAIA_ASSERT(jobFirst != (JobHandle)JobNull_t{});
421 GAIA_ASSERT(jobSecond != (JobHandle)JobNull_t{});
423 const auto& firstData = data(jobFirst);
424 const auto depCnt = firstData.edges.depCnt;
427 GAIA_ASSERT(firstData.edges.dep == jobSecond);
429 GAIA_ASSERT(firstData.edges.pDeps !=
nullptr);
431 GAIA_FOR(firstData.edges.depCnt) {
432 if (firstData.edges.pDeps[i] == jobSecond) {