#pragma once
#include <mutex>
+#include <algorithm>
+#include <atomic>
+#include "core/utils.h"
class DefaultAllocator
{
}
};
-template<typename T = DefaultAllocator>
+template<typename MutexT = std::mutex, typename T = DefaultAllocator>
class TArena
{
public:
}
static const size_t ArenaBlockSize = 1024 * 1024;
- size_t blockSize = std::max(m_size + ArenaBlockSize, std::max(size, ArenaBlockSize));
+ size_t blockSize = std::max<size_t>(m_size + ArenaBlockSize, std::max(size, ArenaBlockSize));
// Add in one BLOCK_ALIGN unit to store ArenaBlock in.
blockSize = AlignUp(blockSize + BLOCK_ALIGN, BLOCK_ALIGN);
{
void* pAlloc = nullptr;
- std::unique_lock<std::mutex> l(m_mutex);
+ m_mutex.lock();
pAlloc = AllocAligned(size, align);
+ m_mutex.unlock();
return pAlloc;
}
{
void* pAlloc = nullptr;
- std::unique_lock<std::mutex> l(m_mutex);
+ m_mutex.lock();
pAlloc = Alloc(size);
+ m_mutex.unlock();
return pAlloc;
}
size_t m_size = 0;
/// @note Mutex is only used by sync allocation functions.
- std::mutex m_mutex;
+ MutexT m_mutex;
};
typedef TArena<> Arena;
+
+struct NullMutex
+{
+ void lock() {}
+ void unlock() {}
+};
+
+// Ref counted Arena for ArenaAllocator
+// NOT THREAD SAFE!!
+struct RefArena : TArena<NullMutex>
+{
+ uint32_t AddRef() { return ++m_refCount; }
+ uint32_t Release() { if (--m_refCount) { return m_refCount; } delete this; return 0; }
+
+ void* allocate(std::size_t n)
+ {
+ ++m_numAllocations;
+ return Alloc(n);
+ }
+
+ void deallocate(void* p) { --m_numAllocations; }
+ void clear() { SWR_ASSERT(0 == m_numAllocations); Reset(); }
+
+private:
+ uint32_t m_refCount = 0;
+ uint32_t m_numAllocations = 0;
+};
+
+#if 0 // THIS DOESN'T WORK!!!
+// Arena based replacement for std::allocator
+template <typename T>
+struct ArenaAllocator
+{
+ typedef T value_type;
+ ArenaAllocator()
+ {
+ m_pArena = new RefArena();
+ m_pArena->AddRef();
+ }
+ ~ArenaAllocator()
+ {
+ m_pArena->Release(); m_pArena = nullptr;
+ }
+ ArenaAllocator(const ArenaAllocator& copy)
+ {
+ m_pArena = const_cast<RefArena*>(copy.m_pArena); m_pArena->AddRef();
+ }
+
+
+ template <class U> ArenaAllocator(const ArenaAllocator<U>& copy)
+ {
+ m_pArena = const_cast<RefArena*>(copy.m_pArena); m_pArena->AddRef();
+ }
+ T* allocate(std::size_t n)
+ {
+#if defined(_DEBUG)
+ char buf[32];
+ sprintf_s(buf, "Alloc: %lld\n", n);
+ OutputDebugStringA(buf);
+#endif
+ void* p = m_pArena->allocate(n * sizeof(T));
+ return static_cast<T*>(p);
+ }
+ void deallocate(T* p, std::size_t n)
+ {
+#if defined(_DEBUG)
+ char buf[32];
+ sprintf_s(buf, "Dealloc: %lld\n", n);
+ OutputDebugStringA(buf);
+#endif
+ m_pArena->deallocate(p);
+ }
+ void clear() { m_pArena->clear(); }
+
+ RefArena* m_pArena = nullptr;
+};
+
+template <class T, class U>
+bool operator== (const ArenaAllocator<T>&, const ArenaAllocator<U>&)
+{
+ return true;
+}
+
+template <class T, class U>
+bool operator!= (const ArenaAllocator<T>&, const ArenaAllocator<U>&)
+{
+ return false;
+}
+#endif
#include <stdio.h>
#include <thread>
#include <algorithm>
-#include <unordered_set>
#include <float.h>
#include <vector>
#include <utility>
SWR_CONTEXT *pContext,
uint32_t workerId,
uint64_t &curDrawBE,
- std::unordered_set<uint32_t>& lockedTiles)
+ TileSet& lockedTiles)
{
// Find the first incomplete draw that has pending work. If no such draw is found then
// return. FindFirstIncompleteDraw is responsible for incrementing the curDrawBE.
// Track tiles locked by other threads. If we try to lock a macrotile and find its already
// locked then we'll add it to this list so that we don't try and lock it again.
- std::unordered_set<uint32_t> lockedTiles;
+ TileSet lockedTiles;
// each worker has the ability to work on any of the queued draws as long as certain
// conditions are met. the data associated
THREAD_DATA *pThreadData;
};
+typedef std::unordered_set<uint32_t> TileSet;
+
void CreateThreadPool(SWR_CONTEXT *pContext, THREAD_POOL *pPool);
void DestroyThreadPool(SWR_CONTEXT *pContext, THREAD_POOL *pPool);
// Expose FE and BE worker functions to the API thread if single threaded
void WorkOnFifoFE(SWR_CONTEXT *pContext, uint32_t workerId, uint64_t &curDrawFE, int numaNode);
-void WorkOnFifoBE(SWR_CONTEXT *pContext, uint32_t workerId, uint64_t &curDrawBE, std::unordered_set<uint32_t> &usedTiles);
+void WorkOnFifoBE(SWR_CONTEXT *pContext, uint32_t workerId, uint64_t &curDrawBE, TileSet &usedTiles);
void WorkOnCompute(SWR_CONTEXT *pContext, uint32_t workerId, uint64_t &curDrawBE);