Use atomics for pool buffer ref-counts

This commit is contained in:
Jack Andersen 2016-12-14 12:56:32 -10:00
parent b269d4a445
commit 121f566848
2 changed files with 28 additions and 32 deletions

View File

@ -4,6 +4,7 @@
#include <boo/boo.hpp> #include <boo/boo.hpp>
#include <vector> #include <vector>
#include <cstdlib> #include <cstdlib>
#include <atomic>
#include "BitVector.hpp" #include "BitVector.hpp"
namespace hecl namespace hecl
@ -56,7 +57,7 @@ class UniformBufferPool
{ {
boo::IGraphicsBufferD* buffer; boo::IGraphicsBufferD* buffer;
uint8_t* cpuBuffer = nullptr; uint8_t* cpuBuffer = nullptr;
size_t useCount = 0; std::atomic_size_t useCount = {};
bool dirty = false; bool dirty = false;
Bucket() = default; Bucket() = default;
Bucket(const Bucket& other) = delete; Bucket(const Bucket& other) = delete;
@ -74,23 +75,21 @@ class UniformBufferPool
void increment(UniformBufferPool& pool) void increment(UniformBufferPool& pool)
{ {
if (!useCount) if (useCount.fetch_add(1) == 0)
buffer = pool.m_token.newPoolBuffer(boo::BufferUse::Uniform, buffer = pool.m_token.newPoolBuffer(boo::BufferUse::Uniform,
pool.m_stride, pool.m_countPerBucket); pool.m_stride, pool.m_countPerBucket);
++useCount;
} }
void decrement(UniformBufferPool& pool) void decrement(UniformBufferPool& pool)
{ {
--useCount; if (useCount.fetch_sub(1) == 1)
if (!useCount)
{ {
pool.m_token.deletePoolBuffer(buffer); pool.m_token.deletePoolBuffer(buffer);
buffer = nullptr; buffer = nullptr;
} }
} }
}; };
std::vector<Bucket> m_buckets; std::vector<std::unique_ptr<Bucket>> m_buckets;
public: public:
/** User block-owning token */ /** User block-owning token */
@ -104,11 +103,10 @@ public:
: m_pool(pool) : m_pool(pool)
{ {
auto& freeSpaces = pool.m_freeBlocks; auto& freeSpaces = pool.m_freeBlocks;
auto& buckets = pool.m_buckets;
int idx = freeSpaces.find_first(); int idx = freeSpaces.find_first();
if (idx == -1) if (idx == -1)
{ {
buckets.emplace_back(); pool.m_buckets.push_back(std::make_unique<Bucket>());
m_index = freeSpaces.size(); m_index = freeSpaces.size();
freeSpaces.resize(freeSpaces.size() + pool.m_countPerBucket, true); freeSpaces.resize(freeSpaces.size() + pool.m_countPerBucket, true);
} }
@ -119,7 +117,7 @@ public:
freeSpaces.reset(m_index); freeSpaces.reset(m_index);
m_div = pool.getBucketDiv(m_index); m_div = pool.getBucketDiv(m_index);
Bucket& bucket = m_pool.m_buckets[m_div.quot]; Bucket& bucket = *m_pool.m_buckets[m_div.quot];
bucket.increment(m_pool); bucket.increment(m_pool);
} }
@ -139,14 +137,14 @@ public:
if (m_index != -1) if (m_index != -1)
{ {
m_pool.m_freeBlocks.set(m_index); m_pool.m_freeBlocks.set(m_index);
Bucket& bucket = m_pool.m_buckets[m_div.quot]; Bucket& bucket = *m_pool.m_buckets[m_div.quot];
bucket.decrement(m_pool); bucket.decrement(m_pool);
} }
} }
UniformStruct& access() UniformStruct& access()
{ {
Bucket& bucket = m_pool.m_buckets[m_div.quot]; Bucket& bucket = *m_pool.m_buckets[m_div.quot];
if (!bucket.cpuBuffer) if (!bucket.cpuBuffer)
bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket)); bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket));
bucket.dirty = true; bucket.dirty = true;
@ -155,7 +153,7 @@ public:
std::pair<boo::IGraphicsBufferD*, IndexTp> getBufferInfo() const std::pair<boo::IGraphicsBufferD*, IndexTp> getBufferInfo() const
{ {
Bucket& bucket = m_pool.m_buckets[m_div.quot]; Bucket& bucket = *m_pool.m_buckets[m_div.quot];
return {bucket.buffer, m_div.rem * m_pool.m_stride}; return {bucket.buffer, m_div.rem * m_pool.m_stride};
} }
}; };
@ -167,9 +165,9 @@ public:
/** Load dirty buffer data into GPU */ /** Load dirty buffer data into GPU */
void updateBuffers() void updateBuffers()
{ {
for (Bucket& bucket : m_buckets) for (auto& bucket : m_buckets)
if (bucket.dirty) if (bucket->dirty)
bucket.updateBuffer(); bucket->updateBuffer();
} }
/** Allocate free block into client-owned Token */ /** Allocate free block into client-owned Token */

View File

@ -4,6 +4,7 @@
#include <boo/boo.hpp> #include <boo/boo.hpp>
#include <vector> #include <vector>
#include <cstdlib> #include <cstdlib>
#include <atomic>
#include "BitVector.hpp" #include "BitVector.hpp"
namespace hecl namespace hecl
@ -56,13 +57,13 @@ class VertexBufferPool
{ {
boo::IGraphicsBufferD* buffer; boo::IGraphicsBufferD* buffer;
uint8_t* cpuBuffer = nullptr; uint8_t* cpuBuffer = nullptr;
size_t useCount = 0; std::atomic_size_t useCount = {};
bool dirty = false; bool dirty = false;
Bucket() = default; Bucket() = default;
Bucket(const Bucket& other) = delete; Bucket(const Bucket& other) = delete;
Bucket& operator=(const Bucket& other) = delete; Bucket& operator=(const Bucket& other) = delete;
Bucket(Bucket&& other) = default; Bucket(Bucket&& other) = delete;
Bucket& operator=(Bucket&& other) = default; Bucket& operator=(Bucket&& other) = delete;
void updateBuffer() void updateBuffer()
{ {
@ -74,23 +75,21 @@ class VertexBufferPool
void increment(VertexBufferPool& pool) void increment(VertexBufferPool& pool)
{ {
if (!useCount) if (useCount.fetch_add(1) == 0)
buffer = pool.m_token.newPoolBuffer(boo::BufferUse::Vertex, buffer = pool.m_token.newPoolBuffer(boo::BufferUse::Vertex,
pool.m_stride, pool.m_countPerBucket); pool.m_stride, pool.m_countPerBucket);
++useCount;
} }
void decrement(VertexBufferPool& pool) void decrement(VertexBufferPool& pool)
{ {
--useCount; if (useCount.fetch_sub(1) == 1)
if (!useCount)
{ {
pool.m_token.deletePoolBuffer(buffer); pool.m_token.deletePoolBuffer(buffer);
buffer = nullptr; buffer = nullptr;
} }
} }
}; };
std::vector<Bucket> m_buckets; std::vector<std::unique_ptr<Bucket>> m_buckets;
public: public:
/** User element-owning token */ /** User element-owning token */
@ -106,11 +105,10 @@ public:
{ {
assert(count <= pool.m_countPerBucket && "unable to fit in bucket"); assert(count <= pool.m_countPerBucket && "unable to fit in bucket");
auto& freeSpaces = pool.m_freeElements; auto& freeSpaces = pool.m_freeElements;
auto& buckets = pool.m_buckets;
int idx = freeSpaces.find_first_contiguous(count, pool.m_countPerBucket); int idx = freeSpaces.find_first_contiguous(count, pool.m_countPerBucket);
if (idx == -1) if (idx == -1)
{ {
buckets.emplace_back(); pool.m_buckets.push_back(std::make_unique<Bucket>());
m_index = freeSpaces.size(); m_index = freeSpaces.size();
freeSpaces.resize(freeSpaces.size() + pool.m_countPerBucket, true); freeSpaces.resize(freeSpaces.size() + pool.m_countPerBucket, true);
} }
@ -121,7 +119,7 @@ public:
freeSpaces.reset(m_index, m_index + count); freeSpaces.reset(m_index, m_index + count);
m_div = pool.getBucketDiv(m_index); m_div = pool.getBucketDiv(m_index);
Bucket& bucket = m_pool.m_buckets[m_div.quot]; Bucket& bucket = *m_pool.m_buckets[m_div.quot];
bucket.increment(pool); bucket.increment(pool);
} }
public: public:
@ -140,14 +138,14 @@ public:
if (m_index != -1) if (m_index != -1)
{ {
m_pool.m_freeElements.set(m_index, m_index + m_count); m_pool.m_freeElements.set(m_index, m_index + m_count);
Bucket& bucket = m_pool.m_buckets[m_div.quot]; Bucket& bucket = *m_pool.m_buckets[m_div.quot];
bucket.decrement(m_pool); bucket.decrement(m_pool);
} }
} }
VertStruct* access() VertStruct* access()
{ {
Bucket& bucket = m_pool.m_buckets[m_div.quot]; Bucket& bucket = *m_pool.m_buckets[m_div.quot];
if (!bucket.cpuBuffer) if (!bucket.cpuBuffer)
bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket)); bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket));
bucket.dirty = true; bucket.dirty = true;
@ -156,7 +154,7 @@ public:
std::pair<boo::IGraphicsBufferD*, IndexTp> getBufferInfo() const std::pair<boo::IGraphicsBufferD*, IndexTp> getBufferInfo() const
{ {
Bucket& bucket = m_pool.m_buckets[m_div.quot]; Bucket& bucket = *m_pool.m_buckets[m_div.quot];
return {bucket.buffer, m_div.rem}; return {bucket.buffer, m_div.rem};
} }
}; };
@ -168,9 +166,9 @@ public:
/** Load dirty buffer data into GPU */ /** Load dirty buffer data into GPU */
void updateBuffers() void updateBuffers()
{ {
for (Bucket& bucket : m_buckets) for (auto& bucket : m_buckets)
if (bucket.dirty) if (bucket->dirty)
bucket.updateBuffer(); bucket->updateBuffer();
} }
/** Allocate free block into client-owned Token */ /** Allocate free block into client-owned Token */