#include "drape/batcher.hpp" #include "drape/cpu_buffer.hpp" #include "drape/batcher_helpers.hpp" #include "drape/vertex_array_buffer.hpp" #include "base/assert.hpp" #include "std/bind.hpp" namespace dp { class Batcher::CallbacksWrapper { public: CallbacksWrapper(GLState const & state, RefPointer overlay) : m_state(state) , m_overlay(overlay) { } void SetVAO(RefPointer buffer) { m_buffer = buffer; } bool IsVAOFilled() const { return m_buffer->IsFilled(); } void FlushData(BindingInfo const & info, void const * data, uint16_t count) { if (!m_overlay.IsNull() && info.IsDynamic()) { uint16_t offset = m_buffer->GetDynamicBufferOffset(info); m_overlay->AddDynamicAttribute(info, offset, count); } m_buffer->UploadData(info, data, count); } uint16_t * GetIndexStorage(uint16_t size, uint16_t & startIndex) { startIndex = m_buffer->GetStartIndexValue(); if (m_overlay.IsNull()) { m_indexStorage.resize(size); return &m_indexStorage[0]; } else return m_overlay->IndexStorage(size); } void SubmitIndexes() { if (m_overlay.IsNull()) m_buffer->UploadIndexes(&m_indexStorage[0], m_indexStorage.size()); } uint16_t GetAvailableVertexCount() const { return m_buffer->GetAvailableVertexCount(); } uint16_t GetAvailableIndexCount() const { return m_buffer->GetAvailableIndexCount(); } GLState const & GetState() const { return m_state; } private: GLState const & m_state; RefPointer m_buffer; RefPointer m_overlay; vector m_indexStorage; }; //////////////////////////////////////////////////////////////// Batcher::Batcher(uint32_t indexBufferSize, uint32_t vertexBufferSize) : m_indexBufferSize(indexBufferSize) , m_vertexBufferSize(vertexBufferSize) { } Batcher::~Batcher() { buckets_t::iterator it = m_buckets.begin(); for (; it != m_buckets.end(); ++it) it->second.Destroy(); } void Batcher::InsertTriangleList(GLState const & state, RefPointer params) { InsertTriangleList(state, params, MovePointer(NULL)); } void Batcher::InsertTriangleList(GLState const & state, RefPointer params, TransferPointer handle) { InsertTriangles(state, params, handle); } void Batcher::InsertTriangleStrip(GLState const & state, RefPointer params) { InsertTriangleStrip(state, params, MovePointer(NULL)); } void Batcher::InsertTriangleStrip(GLState const & state, RefPointer params, TransferPointer handle) { InsertTriangles(state, params, handle); } void Batcher::InsertTriangleFan(GLState const & state, RefPointer params) { InsertTriangleFan(state, params, MovePointer(NULL)); } void Batcher::InsertTriangleFan(GLState const & state, RefPointer params, TransferPointer handle) { InsertTriangles(state, params, handle); } void Batcher::InsertListOfStrip(GLState const & state, RefPointer params, uint8_t vertexStride) { InsertListOfStrip(state, params, MovePointer(NULL), vertexStride); } void Batcher::InsertListOfStrip(GLState const & state, RefPointer params, TransferPointer handle, uint8_t vertexStride) { InsertTriangles(state, params, handle, vertexStride); } void Batcher::StartSession(flush_fn const & flusher) { m_flushInterface = flusher; } void Batcher::EndSession() { Flush(); m_flushInterface = flush_fn(); } void Batcher::ChangeBuffer(RefPointer wrapper, bool checkFilledBuffer) { if (wrapper->IsVAOFilled() || checkFilledBuffer == false) { GLState const & state = wrapper->GetState(); FinalizeBucket(state); RefPointer bucket = GetBucket(state); wrapper->SetVAO(bucket->GetBuffer()); } } RefPointer Batcher::GetBucket(GLState const & state) { buckets_t::iterator it = m_buckets.find(state); if (it != m_buckets.end()) return it->second.GetRefPointer(); MasterPointer vao(new VertexArrayBuffer(m_indexBufferSize, m_vertexBufferSize)); MasterPointer buffer(new RenderBucket(vao.Move())); m_buckets.insert(make_pair(state, buffer)); return buffer.GetRefPointer(); } void Batcher::FinalizeBucket(GLState const & state) { ASSERT(m_buckets.find(state) != m_buckets.end(), ("Have no bucket for finalize with given state")); MasterPointer bucket = m_buckets[state]; m_buckets.erase(state); bucket->GetBuffer()->Preflush(); m_flushInterface(state, bucket.Move()); } void Batcher::Flush() { ASSERT(m_flushInterface != NULL, ()); for (buckets_t::iterator it = m_buckets.begin(); it != m_buckets.end(); ++it) { it->second->GetBuffer()->Preflush(); m_flushInterface(it->first, it->second.Move()); } m_buckets.clear(); } template void Batcher::InsertTriangles(GLState const & state, RefPointer params, TransferPointer transferHandle, uint8_t vertexStride) { RefPointer bucket = GetBucket(state); RefPointer vao = bucket->GetBuffer(); MasterPointer handle(transferHandle); { Batcher::CallbacksWrapper wrapper(state, handle.GetRefPointer()); wrapper.SetVAO(vao); BatchCallbacks callbacks; callbacks.m_flushVertex = bind(&CallbacksWrapper::FlushData, &wrapper, _1, _2, _3); callbacks.m_getIndexStorage = bind(&CallbacksWrapper::GetIndexStorage, &wrapper, _1, _2); callbacks.m_submitIndex = bind(&CallbacksWrapper::SubmitIndexes, &wrapper); callbacks.m_getAvailableVertex = bind(&CallbacksWrapper::GetAvailableVertexCount, &wrapper); callbacks.m_getAvailableIndex = bind(&CallbacksWrapper::GetAvailableIndexCount, &wrapper); callbacks.m_changeBuffer = bind(&Batcher::ChangeBuffer, this, MakeStackRefPointer(&wrapper), _1); TBatcher batch(callbacks); batch.SetIsCanDevideStreams(handle.IsNull()); batch.SetVertexStride(vertexStride); batch.BatchData(params); } if (!handle.IsNull()) bucket->AddOverlayHandle(handle.Move()); } } // namespace dp