Buffer pool intrinsic garbage collection

This commit is contained in:
Jack Andersen 2016-12-10 20:17:49 -10:00
parent 0384119bd4
commit db542135df
6 changed files with 168 additions and 98 deletions

View File

@ -54,6 +54,8 @@ private:
friend class MultiLineTextView; friend class MultiLineTextView;
static int DoKern(FT_Pos val, const FontAtlas& atlas); static int DoKern(FT_Pos val, const FontAtlas& atlas);
void _commitResources(size_t capacity);
public: public:
class Resources class Resources
{ {

View File

@ -56,21 +56,38 @@ class UniformBufferPool
{ {
boo::IGraphicsBufferD* buffer; boo::IGraphicsBufferD* buffer;
uint8_t* cpuBuffer = nullptr; uint8_t* cpuBuffer = nullptr;
size_t useCount = 0;
bool dirty = false; bool dirty = false;
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) = default;
Bucket& operator=(Bucket&& other) = default; Bucket& operator=(Bucket&& other) = default;
Bucket(UniformBufferPool& pool)
{
buffer = pool.m_token.newPoolBuffer(boo::BufferUse::Uniform, pool.m_stride, pool.m_countPerBucket);
}
void updateBuffer() void updateBuffer()
{ {
buffer->unmap(); buffer->unmap();
cpuBuffer = nullptr; cpuBuffer = nullptr;
dirty = false; dirty = false;
} }
void increment(UniformBufferPool& pool)
{
if (!useCount)
buffer = pool.m_token.newPoolBuffer(boo::BufferUse::Uniform,
pool.m_stride, pool.m_countPerBucket);
++useCount;
}
void decrement(UniformBufferPool& pool)
{
--useCount;
if (!useCount)
{
pool.m_token.deletePoolBuffer(buffer);
buffer = nullptr;
}
}
}; };
std::vector<Bucket> m_buckets; std::vector<Bucket> m_buckets;
@ -90,7 +107,7 @@ public:
int idx = freeSpaces.find_first(); int idx = freeSpaces.find_first();
if (idx == -1) if (idx == -1)
{ {
buckets.emplace_back(pool); buckets.emplace_back();
m_index = freeSpaces.size(); m_index = freeSpaces.size();
freeSpaces.resize(freeSpaces.size() + pool.m_countPerBucket, true); freeSpaces.resize(freeSpaces.size() + pool.m_countPerBucket, true);
} }
@ -100,6 +117,9 @@ 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.increment(m_pool);
} }
public: public:
@ -116,7 +136,11 @@ public:
~Token() ~Token()
{ {
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.decrement(m_pool);
}
} }
UniformStruct& access() UniformStruct& access()

View File

@ -56,21 +56,38 @@ class VertexBufferPool
{ {
boo::IGraphicsBufferD* buffer; boo::IGraphicsBufferD* buffer;
uint8_t* cpuBuffer = nullptr; uint8_t* cpuBuffer = nullptr;
size_t useCount = 0;
bool dirty = false; bool dirty = false;
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) = default;
Bucket& operator=(Bucket&& other) = default; Bucket& operator=(Bucket&& other) = default;
Bucket(VertexBufferPool& pool)
{
buffer = pool.m_token.newPoolBuffer(boo::BufferUse::Vertex, pool.m_stride, pool.m_countPerBucket);
}
void updateBuffer() void updateBuffer()
{ {
buffer->unmap(); buffer->unmap();
cpuBuffer = nullptr; cpuBuffer = nullptr;
dirty = false; dirty = false;
} }
void increment(VertexBufferPool& pool)
{
if (!useCount)
buffer = pool.m_token.newPoolBuffer(boo::BufferUse::Vertex,
pool.m_stride, pool.m_countPerBucket);
++useCount;
}
void decrement(VertexBufferPool& pool)
{
--useCount;
if (!useCount)
{
pool.m_token.deletePoolBuffer(buffer);
buffer = nullptr;
}
}
}; };
std::vector<Bucket> m_buckets; std::vector<Bucket> m_buckets;
@ -92,7 +109,7 @@ public:
int idx = freeSpaces.find_first_contiguous(count); int idx = freeSpaces.find_first_contiguous(count);
if (idx == -1) if (idx == -1)
{ {
buckets.emplace_back(pool); buckets.emplace_back();
m_index = freeSpaces.size(); m_index = freeSpaces.size();
freeSpaces.resize(freeSpaces.size() + pool.m_countPerBucket, true); freeSpaces.resize(freeSpaces.size() + pool.m_countPerBucket, true);
} }
@ -102,6 +119,9 @@ 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.increment(pool);
} }
public: public:
Token(const Token& other) = delete; Token(const Token& other) = delete;
@ -117,7 +137,11 @@ public:
~Token() ~Token()
{ {
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.decrement(m_pool);
}
} }
VertStruct* access() VertStruct* access()

View File

@ -221,6 +221,7 @@ public:
protected: protected:
View(ViewResources& res, View& parentView); View(ViewResources& res, View& parentView);
void buildResources(boo::IGraphicsDataFactory::Context& ctx, ViewResources& res); void buildResources(boo::IGraphicsDataFactory::Context& ctx, ViewResources& res);
void _commitResources(ViewResources& res, const boo::FactoryCommitFunc& commitFunc);
void commitResources(ViewResources& res, const boo::FactoryCommitFunc& commitFunc); void commitResources(ViewResources& res, const boo::FactoryCommitFunc& commitFunc);
public: public:

View File

@ -1,3 +1,4 @@
#include "specter/RootView.hpp"
#include "specter/TextView.hpp" #include "specter/TextView.hpp"
#include "specter/ViewResources.hpp" #include "specter/ViewResources.hpp"
#include "utf8proc.h" #include "utf8proc.h"
@ -296,27 +297,19 @@ void TextView::Resources::init(boo::VulkanDataFactory::Context& ctx, FontCache*
#endif #endif
TextView::TextView(ViewResources& res, void TextView::_commitResources(size_t capacity)
View& parentView, const FontAtlas& font,
Alignment align, size_t capacity)
: View(res, parentView),
m_capacity(capacity),
m_fontAtlas(font),
m_align(align)
{ {
if (size_t(VertexBufferPool<RenderGlyph>::bucketCapacity()) < capacity) auto& res = rootView().viewRes();
Log.report(logvisor::Fatal, "bucket overflow [%" PRISize "/%" PRISize "]", View::_commitResources(res, [&](boo::IGraphicsDataFactory::Context& ctx) -> bool
capacity, VertexBufferPool<RenderGlyph>::bucketCapacity());
m_glyphs.reserve(capacity);
commitResources(res, [&](boo::IGraphicsDataFactory::Context& ctx) -> bool
{ {
buildResources(ctx, res); buildResources(ctx, res);
if (capacity)
{
m_glyphBuf.emplace(res.m_textRes.m_glyphPool.allocateBlock(res.m_factory, capacity)); m_glyphBuf.emplace(res.m_textRes.m_glyphPool.allocateBlock(res.m_factory, capacity));
boo::IShaderPipeline* shader; boo::IShaderPipeline* shader;
if (font.subpixel()) if (m_fontAtlas.subpixel())
shader = res.m_textRes.m_subpixel; shader = res.m_textRes.m_subpixel;
else else
shader = res.m_textRes.m_regular; shader = res.m_textRes.m_regular;
@ -359,10 +352,26 @@ TextView::TextView(ViewResources& res,
uBufs, nullptr, uBufOffs, uBufSizes, uBufs, nullptr, uBufOffs, uBufSizes,
1, texs, 0, vBufInfo.second); 1, texs, 0, vBufInfo.second);
} }
}
return true; return true;
}); });
} }
TextView::TextView(ViewResources& res,
View& parentView, const FontAtlas& font,
Alignment align, size_t capacity)
: View(res, parentView),
m_capacity(capacity),
m_fontAtlas(font),
m_align(align)
{
if (size_t(VertexBufferPool<RenderGlyph>::bucketCapacity()) < capacity)
Log.report(logvisor::Fatal, "bucket overflow [%" PRISize "/%" PRISize "]",
capacity, VertexBufferPool<RenderGlyph>::bucketCapacity());
_commitResources(0);
}
TextView::TextView(ViewResources& res, View& parentView, FontTag font, Alignment align, size_t capacity) TextView::TextView(ViewResources& res, View& parentView, FontTag font, Alignment align, size_t capacity)
: TextView(res, parentView, res.m_textRes.m_fcache->lookupAtlas(font), align, capacity) {} : TextView(res, parentView, res.m_textRes.m_fcache->lookupAtlas(font), align, capacity) {}
@ -398,31 +407,33 @@ int TextView::DoKern(FT_Pos val, const FontAtlas& atlas)
void TextView::typesetGlyphs(const std::string& str, const zeus::CColor& defaultColor) void TextView::typesetGlyphs(const std::string& str, const zeus::CColor& defaultColor)
{ {
size_t rem = str.size(); UTF8Iterator it(str.begin());
const utf8proc_uint8_t* it = reinterpret_cast<const utf8proc_uint8_t*>(str.data()); size_t charLen = str.size() ? std::min(it.countTo(str.end()), size_t(1024)) : 0;
_commitResources(charLen);
uint32_t lCh = -1; uint32_t lCh = -1;
m_glyphs.clear(); m_glyphs.clear();
m_glyphs.reserve(str.size()); m_glyphs.reserve(charLen);
m_glyphInfo.clear(); m_glyphInfo.clear();
m_glyphInfo.reserve(str.size()); m_glyphInfo.reserve(charLen);
int adv = 0; int adv = 0;
while (rem) if (charLen)
{ {
utf8proc_int32_t ch; for (; it.iter() < str.end() ; ++it)
utf8proc_ssize_t sz = utf8proc_iterate(it, -1, &ch); {
if (sz < 0) utf8proc_int32_t ch = *it;
Log.report(logvisor::Fatal, "invalid UTF-8 char"); if (ch == -1)
if (ch == '\n') {
Log.report(logvisor::Warning, "invalid UTF-8 char");
break;
}
if (ch == '\n' || ch == '\0')
break; break;
const FontAtlas::Glyph* glyph = m_fontAtlas.lookupGlyph(ch); const FontAtlas::Glyph* glyph = m_fontAtlas.lookupGlyph(ch);
if (!glyph) if (!glyph)
{
rem -= sz;
it += sz;
continue; continue;
}
if (lCh != -1) if (lCh != -1)
adv += DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas); adv += DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas);
@ -430,12 +441,11 @@ void TextView::typesetGlyphs(const std::string& str, const zeus::CColor& default
m_glyphInfo.emplace_back(ch, glyph->m_width, glyph->m_height, adv); m_glyphInfo.emplace_back(ch, glyph->m_width, glyph->m_height, adv);
lCh = glyph->m_glyphIdx; lCh = glyph->m_glyphIdx;
rem -= sz;
it += sz;
if (m_glyphs.size() == m_capacity) if (m_glyphs.size() == m_capacity)
break; break;
} }
}
if (m_align == Alignment::Right) if (m_align == Alignment::Right)
{ {
@ -467,6 +477,8 @@ void TextView::typesetGlyphs(const std::string& str, const zeus::CColor& default
void TextView::typesetGlyphs(const std::wstring& str, const zeus::CColor& defaultColor) void TextView::typesetGlyphs(const std::wstring& str, const zeus::CColor& defaultColor)
{ {
_commitResources(str.size());
uint32_t lCh = -1; uint32_t lCh = -1;
m_glyphs.clear(); m_glyphs.clear();
m_glyphs.reserve(str.size()); m_glyphs.reserve(str.size());
@ -534,12 +546,15 @@ void TextView::colorGlyphsTypeOn(const zeus::CColor& newColor, float startInterv
} }
void TextView::invalidateGlyphs() void TextView::invalidateGlyphs()
{
if (m_glyphBuf)
{ {
RenderGlyph* out = m_glyphBuf->access(); RenderGlyph* out = m_glyphBuf->access();
size_t i = 0; size_t i = 0;
for (RenderGlyph& glyph : m_glyphs) for (RenderGlyph& glyph : m_glyphs)
out[i++] = glyph; out[i++] = glyph;
} }
}
void TextView::think() void TextView::think()
{ {

View File

@ -373,14 +373,18 @@ void View::draw(boo::IGraphicsCommandQueue* gfxQ)
} }
} }
void View::_commitResources(ViewResources& res, const boo::FactoryCommitFunc& commitFunc)
{
m_gfxData = res.m_factory->commitTransaction(commitFunc);
}
void View::commitResources(ViewResources& res, const boo::FactoryCommitFunc& commitFunc) void View::commitResources(ViewResources& res, const boo::FactoryCommitFunc& commitFunc)
{ {
if (m_gfxData) if (m_gfxData)
Log.report(logvisor::Fatal, "multiple resource commits not allowed"); Log.report(logvisor::Fatal, "multiple resource commits not allowed");
m_gfxData = res.m_factory->commitTransaction(commitFunc); _commitResources(res, commitFunc);
} }
void View::VertexBufferBindingSolid::init(boo::IGraphicsDataFactory::Context& ctx, void View::VertexBufferBindingSolid::init(boo::IGraphicsDataFactory::Context& ctx,
ViewResources& res, size_t count, ViewResources& res, size_t count,
const UniformBufferPool<ViewBlock>::Token& viewBlockBuf) const UniformBufferPool<ViewBlock>::Token& viewBlockBuf)