From bd55fe421d07aba0fa8940c0e8913fd4bed9d336 Mon Sep 17 00:00:00 2001 From: ExMix Date: Mon, 3 Feb 2014 13:08:04 +0300 Subject: [PATCH] [drape] batcher refactoring --- drape/batcher.cpp | 284 +++++++++++++++++++++++++++++++++++----------- drape/batcher.hpp | 5 +- 2 files changed, 220 insertions(+), 69 deletions(-) diff --git a/drape/batcher.cpp b/drape/batcher.cpp index ef8e5daa32..3647c22189 100644 --- a/drape/batcher.cpp +++ b/drape/batcher.cpp @@ -1,45 +1,42 @@ #include "batcher.hpp" +#include "cpu_buffer.hpp" + #include "../base/assert.hpp" #include "../std/utility.hpp" namespace { - struct BaseStrategy + const uint32_t AllocateIndexCount = 3000; + const uint32_t AllocateVertexCount = 3000; + + class IndexGenerator { public: - BaseStrategy() - : m_startIndex(0) + IndexGenerator(uint16_t startIndex) + : m_startIndex(startIndex) , m_counter(0) { } - void SetStartIndex(uint16_t startIndex) - { - m_startIndex = startIndex; - } - protected: uint16_t GetCounter() { return m_counter++; } - uint16_t m_startIndex; + const uint16_t m_startIndex; + + private: uint16_t m_counter; }; - struct TrianglesListStrategy : public BaseStrategy + class ListIndexGenerator : public IndexGenerator { public: - uint16_t GetIndexCount(uint16_t vertexCount) const + ListIndexGenerator(uint16_t startIndex) + : IndexGenerator(startIndex) { - return vertexCount; - } - - uint16_t GetVertexCount(uint16_t indexCount) const - { - return indexCount; } uint16_t operator()() @@ -48,17 +45,12 @@ namespace } }; - struct TrianglesStripStrategy : public BaseStrategy + class StripIndexGenerator : public IndexGenerator { public: - uint16_t GetIndexCount(uint16_t vertexCount) const + StripIndexGenerator(uint16_t startIndex) + : IndexGenerator(startIndex) { - return 3* (vertexCount - 2); - } - - uint16_t GetVertexCount(uint16_t indexCount) const - { - return (indexCount / 3) + 2; } uint16_t operator()() @@ -68,17 +60,12 @@ namespace } }; - struct TrianglesFanStrategy : public BaseStrategy + class FanIndexGenerator : public IndexGenerator { public: - uint16_t GetIndexCount(uint16_t vertexCount) const + FanIndexGenerator(uint16_t startIndex) + : IndexGenerator(startIndex) { - return 3* (vertexCount - 2); - } - - uint16_t GetVertexCount(uint16_t indexCount) const - { - return (indexCount / 3) + 2; } uint16_t operator()() @@ -89,6 +76,62 @@ namespace return m_startIndex + counter - 2 * (counter / 3); } }; + + class InsertHelper + { + public: + InsertHelper(RefPointer params, RefPointer buffer) + : m_params(params) + , m_buffer(buffer) + { + } + + void GetUploadStripFanParams(uint16_t & resultVertexCount, uint16_t & resultIndexCount) + { + uint16_t vertexCount = m_params->GetVertexCount(); + uint16_t indexCount = VertexToIndexCount(vertexCount); + resultVertexCount = vertexCount; + resultIndexCount = VertexToIndexCount(vertexCount); + + uint16_t availableVertexCount = m_buffer->GetAvailableVertexCount(); + uint16_t availableIndexCount = m_buffer->GetAvailableIndexCount(); + + if (vertexCount > availableVertexCount || indexCount > availableIndexCount) + { + uint32_t indexCountForAvailableVertexCount = VertexToIndexCount(availableVertexCount); + if (indexCountForAvailableVertexCount >= availableIndexCount) + { + resultVertexCount = availableVertexCount; + resultIndexCount = indexCountForAvailableVertexCount; + } + else + { + resultIndexCount = availableIndexCount - availableIndexCount % 3; + resultVertexCount = IndexToVertexCount(resultIndexCount); + } + } + } + + bool IsFullDataUploaded(uint16_t vertexCount) + { + return m_params->GetVertexCount() == vertexCount; + } + + private: + uint32_t VertexToIndexCount(uint32_t vertexCount) + { + return 3 * (vertexCount - 2); + } + + uint32_t IndexToVertexCount(uint32_t indexCount) + { + return indexCount / 3 + 2; + } + + private: + RefPointer m_params; + RefPointer m_buffer; + }; } Batcher::Batcher() @@ -102,67 +145,178 @@ Batcher::~Batcher() it->second.Destroy(); } -template -void Batcher::InsertTriangles(const GLState & state, strategy s, RefPointer params) +void Batcher::InsertTriangleList(const GLState & state, RefPointer params) { while (params->IsDataExists()) { uint16_t vertexCount = params->GetVertexCount(); - uint16_t indexCount = s.GetIndexCount(vertexCount); RefPointer buffer = GetBuffer(state); + ASSERT(!buffer->IsFilled(), ("Buffer must be filnalized on previous iteration")); + uint16_t availableVertexCount = buffer->GetAvailableVertexCount(); uint16_t availableIndexCount = buffer->GetAvailableIndexCount(); + vertexCount = min(vertexCount, availableVertexCount); + vertexCount = min(vertexCount, availableIndexCount); - ASSERT(availableIndexCount != 0, ("Buffer must be filnalized on previous iteration")); - ASSERT(availableVertexCount != 0, ("Buffer must be filnalized on previous iteration")); + ASSERT(vertexCount >= 3, ()); - if (vertexCount > availableVertexCount || indexCount > availableIndexCount) - { - if (s.GetIndexCount(availableVertexCount) <= availableIndexCount) - vertexCount = availableVertexCount; - else - vertexCount = s.GetVertexCount(availableIndexCount); + vertexCount -= vertexCount % 3; - indexCount = s.GetIndexCount(vertexCount); - } - - /// generate indexes - uint16_t startIndexValue = buffer->GetStartIndexValue(); - s.SetStartIndex(startIndexValue); vector indexes; - indexes.resize(indexCount); - std::generate(indexes.begin(), indexes.end(), s); - - buffer->UploadIndexes(&indexes[0], indexCount); + indexes.resize(vertexCount); + std::generate(indexes.begin(), indexes.end(), ListIndexGenerator(buffer->GetStartIndexValue())); + buffer->UploadIndexes(&indexes[0], vertexCount); /// upload data from params to GPU buffers for (size_t i = 0; i < params->GetStreamCount(); ++i) { - RefPointer streamBuffer = buffer->GetBuffer(params->GetBindingInfo(i)); + RefPointer streamBuffer = buffer->GetBuffer(params->GetBindingInfo(i)); streamBuffer->UploadData(params->GetRawPointer(i), vertexCount); } params->Advance(vertexCount); - if (!(buffer->GetAvailableIndexCount() > 3 && - buffer->GetAvailableVertexCount() > 3)) + if (buffer->IsFilled()) + { + buffer = RefPointer(); FinalizeBuffer(state); + } } } -void Batcher::InsertTriangleList(const GLState & state, RefPointer params) -{ - InsertTriangles(state, TrianglesListStrategy(), params); -} - void Batcher::InsertTriangleStrip(const GLState & state, RefPointer params) { - InsertTriangles(state, TrianglesStripStrategy(), params); + while (params->IsDataExists()) + { + RefPointer buffer = GetBuffer(state); + ASSERT(!buffer->IsFilled(), ("Buffer must be filnalized on previous iteration")); + + InsertHelper helper(params, buffer); + + uint16_t vertexCount, indexCount; + helper.GetUploadStripFanParams(vertexCount, indexCount); + + // generate indexes + vector indexes; + indexes.resize(indexCount); + generate(indexes.begin(), indexes.end(), StripIndexGenerator(buffer->GetStartIndexValue())); + buffer->UploadIndexes(&indexes[0], indexCount); + + for (size_t i = 0; i < params->GetStreamCount(); ++i) + { + RefPointer streamBuffer = buffer->GetBuffer(params->GetBindingInfo(i)); + streamBuffer->UploadData(params->GetRawPointer(i), vertexCount); + } + + if (helper.IsFullDataUploaded(vertexCount)) + params->Advance(vertexCount); + else + // uploadVertexCount - 2 for copy last 2 vertex into next VAO as this is TriangleStrip + params->Advance(vertexCount - 2); + + if (buffer->IsFilled()) + { + buffer = RefPointer(); + FinalizeBuffer(state); + } + } } void Batcher::InsertTriangleFan(const GLState & state, RefPointer params) { - InsertTriangles(state, TrianglesFanStrategy(), params); + vector cpuBuffers; + while (params->IsDataExists()) + { + RefPointer buffer = GetBuffer(state); + ASSERT(!buffer->IsFilled(), ("Buffer must be filnalized on previous iteration")); + + InsertHelper helper(params, buffer); + + uint16_t vertexCount, indexCount; + helper.GetUploadStripFanParams(vertexCount, indexCount); + + // generate indexes + vector indexes; + indexes.resize(indexCount); + generate(indexes.begin(), indexes.end(), FanIndexGenerator(buffer->GetStartIndexValue())); + buffer->UploadIndexes(&indexes[0], indexCount); + + if (!cpuBuffers.empty()) + { + // if m_cpuBuffer not empty than on previous interation we not pack all attributes on gpu + // and in m_cpuBuffers stored first vertex of fan. + // We need to copy next part of data into cpu buffer + // and than copy it into gpu memory with first vertex of fan + for (size_t i = 0; i < params->GetStreamCount(); ++i) + { + CPUBuffer & cpuBuffer = cpuBuffers[i]; + ASSERT(cpuBuffer.GetCurrentElementNumber() == 1, ()); + cpuBuffer.UploadData(params->GetRawPointer(i), vertexCount); + + RefPointer streamBuffer = buffer->GetBuffer(params->GetBindingInfo(i)); + // copy on gpu all vertexes that we copy into cpuBuffer on this iteration + // and first vertex of fan + streamBuffer->UploadData(cpuBuffer.GetBufferBegin(), vertexCount + 1); + + // Move cpu buffer cursor on second element of buffer. + // On next iteration first vertex of fan will be also available + cpuBuffer.Seek(1); + } + + if (helper.IsFullDataUploaded(vertexCount)) + { + // this means that we move all data on gpu + params->Advance(vertexCount); + } + else + { + // not all data was moved on gpu and last vertex of fan + // will need on second iteration + params->Advance(vertexCount - 1); + } + } + else // if m_cpuBuffer empty than it's first iteration + { + if (helper.IsFullDataUploaded(vertexCount)) + { + // We can upload all input data as one peace. For upload we need only one iteration + for (size_t i = 0; i < params->GetStreamCount(); ++i) + { + RefPointer streamBuffer = buffer->GetBuffer(params->GetBindingInfo(i)); + streamBuffer->UploadData(params->GetRawPointer(i), vertexCount); + } + params->Advance(vertexCount); + } + else + { + // for each stream we must create CPU buffer. + // Copy to it first vertex of fan + // than we need upload first part of data on gpu + cpuBuffers.reserve(params->GetStreamCount()); + for (size_t i = 0; i < params->GetStreamCount(); ++i) + { + const BindingInfo & binding = params->GetBindingInfo(i); + const void * rawDataPointer = params->GetRawPointer(i); + RefPointer streamBuffer = buffer->GetBuffer(binding); + streamBuffer->UploadData(rawDataPointer, vertexCount); + + cpuBuffers.push_back(CPUBuffer(binding.GetElementSize(), vertexCount)); + CPUBuffer & cpuBuffer = cpuBuffers.back(); + cpuBuffer.UploadData(rawDataPointer, 1); + } + + // advance on uploadVertexCount - 1 to copy last vertex also into next VAO with + // first vertex of data from CPUBuffers + params->Advance(vertexCount - 1); + } + } + + if (buffer->IsFilled()) + { + buffer = RefPointer(); + FinalizeBuffer(state); + } + } } void Batcher::StartSession(const flush_fn & flusher) @@ -182,7 +336,7 @@ RefPointer Batcher::GetBuffer(const GLState & state) if (it != m_buckets.end()) return it->second.GetRefPointer(); - MasterPointer buffer(new VertexArrayBuffer(768, 512)); + MasterPointer buffer(new VertexArrayBuffer(AllocateIndexCount, AllocateVertexCount)); m_buckets.insert(make_pair(state, buffer)); return buffer.GetRefPointer(); } diff --git a/drape/batcher.hpp b/drape/batcher.hpp index bbfb1797a3..b93b83c25a 100644 --- a/drape/batcher.hpp +++ b/drape/batcher.hpp @@ -23,12 +23,9 @@ public: void EndSession(); private: - template - void InsertTriangles(const GLState & state, strategy s, RefPointer params); - RefPointer GetBuffer(const GLState & state); /// return true if GLBuffer is finished - bool UploadBufferData(RefPointer vertexBuffer, RefPointer params); + bool UploadBufferData(RefPointer vertexBuffer, RefPointer params); void FinalizeBuffer(const GLState & state); void Flush();