// pbrt is Copyright(c) 1998-2020 Matt Pharr, Wenzel Jakob, and Greg Humphreys. // The pbrt source code is licensed under the Apache License, Version 2.0. // SPDX: Apache-2.0 #ifndef PBRT_GPU_WORKQUEUE_H #define PBRT_GPU_WORKQUEUE_H #include #include #include #include #ifdef PBRT_IS_WINDOWS #if (__CUDA_ARCH__ >= 700) #define PBRT_HAVE_CUDA_ATOMICS #endif #else #if (__CUDA_ARCH__ >= 600) #define PBRT_HAVE_CUDA_ATOMICS #endif #endif // PBRT_IS_WINDOWS #ifdef PBRT_HAVE_CUDA_ATOMICS #include #endif // PBRT_HAVE_CUDA_ATOMICS namespace pbrt { // WorkQueue Definition template class WorkQueue : public SOA { public: // WorkQueue Public Methods WorkQueue(int n, Allocator alloc) : SOA(n, alloc) {} PBRT_CPU_GPU int Size() const { #ifdef PBRT_HAVE_CUDA_ATOMICS namespace std = cuda::std; return size.load(std::memory_order_relaxed); #else return size; #endif } PBRT_CPU_GPU void Reset() { #ifdef PBRT_HAVE_CUDA_ATOMICS namespace std = cuda::std; size.store(0, std::memory_order_relaxed); #else size = 0; #endif } PBRT_CPU_GPU int Push(WorkItem w) { int index = AllocateEntry(); (*this)[index] = w; return index; } protected: // WorkQueue Protected Methods PBRT_CPU_GPU int AllocateEntry() { #ifdef PBRT_HAVE_CUDA_ATOMICS namespace std = cuda::std; return size.fetch_add(1, std::memory_order_relaxed); #else #ifdef PBRT_IS_GPU_CODE return atomicAdd(&size, 1); #else assert(!"this shouldn't be called"); return 0; #endif #endif } private: // WorkQueue Private Members #ifdef PBRT_HAVE_CUDA_ATOMICS using GPUAtomicInt = cuda::atomic; GPUAtomicInt size{0}; #else int size = 0; #endif }; // WorkQueue Inline Functions template void ForAllQueued(const char *desc, WorkQueue *q, int maxQueued, F func) { GPUParallelFor(desc, maxQueued, [=] PBRT_GPU(int index) mutable { if (index >= q->Size()) return; func((*q)[index], index); }); } // MultiWorkQueue Definition template class MultiWorkQueue; template <> class MultiWorkQueue> { public: MultiWorkQueue(int n, Allocator alloc, pstd::span haveType) {} }; template class MultiWorkQueue> : public MultiWorkQueue> { public: // MultiWorkQueue Public Methods MultiWorkQueue(int n, Allocator alloc, pstd::span haveType) : MultiWorkQueue>(n, alloc, haveType.subspan(1, haveType.size())), q(haveType.front() ? n : 1, alloc) {} template PBRT_CPU_GPU int Size() const { if constexpr (std::is_same_v) return q.Size(); else return MultiWorkQueue>::template Size(); } PBRT_CPU_GPU void Reset() { q.Reset(); if constexpr (sizeof...(Ts) > 0) MultiWorkQueue>::Reset(); } template PBRT_CPU_GPU WorkQueue *Get() { if constexpr (std::is_same_v) return &q; else return MultiWorkQueue>::template Get(); } template PBRT_CPU_GPU int Push(Tq item) { if constexpr (std::is_same_v) return q.Push(item); else return MultiWorkQueue>::template Push(item); } private: // MultiWorkQueue Private Members WorkQueue q; }; } // namespace pbrt #endif // PBRT_GPU_WORKQUEUE_H