diff --git a/graphics/area_renderer.cpp b/graphics/area_renderer.cpp index 096e547661..7ad3dd978b 100644 --- a/graphics/area_renderer.cpp +++ b/graphics/area_renderer.cpp @@ -61,7 +61,7 @@ namespace graphics float texY = res->m_texRect.minY() + 1.0f; GeometryPipeline & p = pipeline(res->m_pipelineID); - shared_ptr texture = p.m_cache->texture(); + shared_ptr texture = p.texture(); if (!texture) { @@ -109,7 +109,7 @@ namespace graphics float texY = res->m_texRect.minY() + 1.0f; GeometryPipeline & p = pipeline(res->m_pipelineID); - shared_ptr texture = p.m_cache->texture(); + shared_ptr texture = p.texture(); if (!texture) { diff --git a/graphics/geometry_batcher.cpp b/graphics/geometry_batcher.cpp index a0baccf79e..426d32237c 100644 --- a/graphics/geometry_batcher.cpp +++ b/graphics/geometry_batcher.cpp @@ -20,21 +20,68 @@ namespace graphics { - GeometryBatcher::GeometryBatcher(base_t::Params const & params) - : base_t(params), + GeometryBatcher::Params::Params() + : m_storageType(ELargeStorage), + m_textureType(ELargeTexture) + {} + + GeometryBatcher::GeometryBatcher(Params const & p) + : base_t(p), m_isAntiAliased(true) { base_t::applyStates(); - /// TODO: Perform this after full initialization. - for (size_t i = 0; i < pipelinesCount(); ++i) - addClearPageFn(i, bind(&GeometryBatcher::flush, this, i), 100); + vector > caches; + loadSkin(resourceManager(), p.m_skinName, caches); + + m_staticPagesCount = caches.size(); + m_startStaticPage = reservePipelines(caches, + EMediumStorage, + gl::Vertex::getVertexDecl()); + + m_dynamicPagesCount = 2; + m_startDynamicPage = reservePipelines(m_dynamicPagesCount, + p.m_textureType, + p.m_storageType, + gl::Vertex::getVertexDecl()); + m_dynamicPage = m_startDynamicPage; /// 1 to turn antialiasing on /// 2 to switch it off m_aaShift = m_isAntiAliased ? 1 : 2; } + unsigned GeometryBatcher::reservePipelines(vector > const & caches, + EStorageType storageType, + VertexDecl const * decl) + { + unsigned res = base_t::reservePipelines(caches, storageType, decl); + + for (size_t i = res; i < res + caches.size(); ++i) + { + addClearPageFn(i, bind(&GeometryBatcher::flush, this, i), 100); + pipeline(i).addHandlesOverflowFn(bind(&GeometryBatcher::onDynamicOverflow, this, i), 0); + } + + return res; + } + + unsigned GeometryBatcher::reservePipelines(unsigned count, + ETextureType textureType, + EStorageType storageType, + VertexDecl const * decl) + { + unsigned res = base_t::reservePipelines(count, textureType, storageType, decl); + + for (size_t i = res; i < res + count; ++i) + { + addClearPageFn(i, bind(&GeometryBatcher::flush, this, i), 100); + pipeline(i).addHandlesOverflowFn(bind(&GeometryBatcher::onDynamicOverflow, this, i), 0); + } + + return res; + } + void GeometryBatcher::beginFrame() { base_t::beginFrame(); @@ -55,36 +102,19 @@ namespace graphics bool GeometryBatcher::hasRoom(size_t verticesCount, size_t indicesCount, int pipelineID) const { - GeometryPipeline const & p = pipeline(pipelineID); - - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) - return false; - - return ((p.m_currentVertex + verticesCount <= p.m_maxVertices) - && (p.m_currentIndex + indicesCount <= p.m_maxIndices)); + return pipeline(pipelineID).hasRoom(verticesCount, indicesCount); } int GeometryBatcher::verticesLeft(int pipelineID) const { GeometryPipeline const & p = pipeline(pipelineID); - - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) - return -1; - - return p.m_maxVertices - p.m_currentVertex; + return p.vxLeft(); } int GeometryBatcher::indicesLeft(int pipelineID) const { GeometryPipeline const & p = pipeline(pipelineID); - - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) - return -1; - - return p.m_maxIndices - p.m_currentIndex; + return p.idxLeft(); } void GeometryBatcher::flush(int pipelineID) @@ -97,21 +127,19 @@ namespace graphics { if (flushPipeline(id)) { - int np = nextPage(id); + int np = nextPipeline(id); if (np != id) { // reserving texture in advance, before we'll // potentially return current texture into the pool. - pipeline(np).m_cache->checkTexture(); + // this way we make sure that the reserved texture will + // be different from the returned one. + pipeline(np).checkTexture(); } - changePage(id); + changePipeline(id); } - - /// resetting geometry storage associated - /// with the specified pipeline. - reset(id); } } } @@ -129,8 +157,8 @@ namespace graphics GeometryPipeline & p = pipeline(pipelineID); - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) + p.checkStorage(); + if (!p.hasStorage()) return; float texMinX = tx0; @@ -138,7 +166,7 @@ namespace graphics float texMinY = ty0; float texMaxY = ty1; - shared_ptr const & texture = p.m_cache->texture(); + shared_ptr const & texture = p.texture(); if (!texture) { @@ -202,8 +230,8 @@ namespace graphics GeometryPipeline & p = pipeline(pipelineID); - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) + p.checkStorage(); + if (!p.hasStorage()) return; float texMinX = tx0; @@ -211,7 +239,7 @@ namespace graphics float texMinY = ty0; float texMaxY = ty1; - shared_ptr const & texture = p.m_cache->texture(); + shared_ptr const & texture = p.texture(); if (!texture) { @@ -222,8 +250,6 @@ namespace graphics texture->mapPixel(texMinX, texMinY); texture->mapPixel(texMaxX, texMaxY); - /// rotated and translated four points (x0, y0), (x0, y1), (x1, y1), (x1, y0) - m2::PointF offsets[4] = { m2::PointF(x0, y0), @@ -281,36 +307,38 @@ namespace graphics GeometryPipeline & p = pipeline(pipelineID); - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) + p.checkStorage(); + if (!p.hasStorage()) return; ASSERT(size > 2, ()); - size_t vOffset = p.m_currentVertex; - size_t iOffset = p.m_currentIndex; + unsigned vOffset = p.currentVx(); + unsigned iOffset = p.currentIdx(); + + gl::Vertex * vertices = static_cast(p.vxData()); + unsigned short * indices = static_cast(p.idxData()); for (unsigned i = 0; i < size; ++i) { - p.m_vertices[vOffset + i].pt = *coords; - p.m_vertices[vOffset + i].normal = *normals; - p.m_vertices[vOffset + i].tex = *texCoords; - p.m_vertices[vOffset + i].depth = depth; + vertices[vOffset + i].pt = *coords; + vertices[vOffset + i].normal = *normals; + vertices[vOffset + i].tex = *texCoords; + vertices[vOffset + i].depth = depth; coords = reinterpret_cast(reinterpret_cast(coords) + coordsStride); normals = reinterpret_cast(reinterpret_cast(normals) + normalsStride); texCoords = reinterpret_cast(reinterpret_cast(texCoords) + texCoordsStride); } - p.m_currentVertex += size; - for (size_t j = 0; j < size - 2; ++j) { - p.m_indices[iOffset + j * 3] = vOffset; - p.m_indices[iOffset + j * 3 + 1] = vOffset + j + 1; - p.m_indices[iOffset + j * 3 + 2] = vOffset + j + 2; + indices[iOffset + j * 3] = vOffset; + indices[iOffset + j * 3 + 1] = vOffset + j + 1; + indices[iOffset + j * 3 + 2] = vOffset + j + 2; } - p.m_currentIndex += (size - 2) * 3; + p.advanceVx(size); + p.advanceIdx((size - 2) * 3); } void GeometryBatcher::addTexturedStrip( @@ -346,42 +374,45 @@ namespace graphics GeometryPipeline & p = pipeline(pipelineID); - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) + p.checkStorage(); + if (!p.hasStorage()) return; ASSERT(size > 2, ()); - size_t vOffset = p.m_currentVertex; - size_t iOffset = p.m_currentIndex; + size_t vOffset = p.currentVx(); + size_t iOffset = p.currentIdx(); + + gl::Vertex * vertices = static_cast(p.vxData()); + unsigned short * indices = static_cast(p.idxData()); for (unsigned i = 0; i < size; ++i) { - p.m_vertices[vOffset + i].pt = *coords; - p.m_vertices[vOffset + i].normal = *normals; - p.m_vertices[vOffset + i].tex = *texCoords; - p.m_vertices[vOffset + i].depth = depth; + vertices[vOffset + i].pt = *coords; + vertices[vOffset + i].normal = *normals; + vertices[vOffset + i].tex = *texCoords; + vertices[vOffset + i].depth = depth; coords = reinterpret_cast(reinterpret_cast(coords) + coordsStride); normals = reinterpret_cast(reinterpret_cast(normals) + normalsStride); texCoords = reinterpret_cast(reinterpret_cast(texCoords) + texCoordsStride); } - p.m_currentVertex += size; + p.advanceVx(size); size_t oldIdx1 = vOffset; size_t oldIdx2 = vOffset + 1; for (size_t j = 0; j < size - 2; ++j) { - p.m_indices[iOffset + j * 3] = oldIdx1; - p.m_indices[iOffset + j * 3 + 1] = oldIdx2; - p.m_indices[iOffset + j * 3 + 2] = vOffset + j + 2; + indices[iOffset + j * 3] = oldIdx1; + indices[iOffset + j * 3 + 1] = oldIdx2; + indices[iOffset + j * 3 + 2] = vOffset + j + 2; oldIdx1 = oldIdx2; oldIdx2 = vOffset + j + 2; } - p.m_currentIndex += (size - 2) * 3; + p.advanceIdx((size - 2) * 3); } void GeometryBatcher::addTexturedListStrided( @@ -400,32 +431,35 @@ namespace graphics GeometryPipeline & p = pipeline(pipelineID); - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) + p.checkStorage(); + if (!p.hasStorage()) return; ASSERT(size > 2, ()); - size_t vOffset = p.m_currentVertex; - size_t iOffset = p.m_currentIndex; + size_t vOffset = p.currentVx(); + size_t iOffset = p.currentIdx(); + + gl::Vertex * vertices = static_cast(p.vxData()); + unsigned short * indices = static_cast(p.idxData()); for (size_t i = 0; i < size; ++i) { - p.m_vertices[vOffset + i].pt = m2::PointF(coords->x, coords->y); - p.m_vertices[vOffset + i].normal = *normals; - p.m_vertices[vOffset + i].tex = *texCoords; - p.m_vertices[vOffset + i].depth = depth; + vertices[vOffset + i].pt = m2::PointF(coords->x, coords->y); + vertices[vOffset + i].normal = *normals; + vertices[vOffset + i].tex = *texCoords; + vertices[vOffset + i].depth = depth; coords = reinterpret_cast(reinterpret_cast(coords) + coordsStride); normals = reinterpret_cast(reinterpret_cast(normals) + normalsStride); texCoords = reinterpret_cast(reinterpret_cast(texCoords) + texCoordsStride); } - p.m_currentVertex += size; + p.advanceVx(size); for (size_t i = 0; i < size; ++i) - p.m_indices[iOffset + i] = vOffset + i; + indices[iOffset + i] = vOffset + i; - p.m_currentIndex += size; + p.advanceIdx(size); } @@ -445,32 +479,35 @@ namespace graphics GeometryPipeline & p = pipeline(pipelineID); - p.checkStorage(resourceManager()); - if (!p.m_hasStorage) + p.checkStorage(); + if (!p.hasStorage()) return; ASSERT(size > 2, ()); - size_t vOffset = p.m_currentVertex; - size_t iOffset = p.m_currentIndex; + size_t vOffset = p.currentVx(); + size_t iOffset = p.currentIdx(); + + gl::Vertex * vertices = static_cast(p.vxData()); + unsigned short * indices = static_cast(p.idxData()); for (size_t i = 0; i < size; ++i) { - p.m_vertices[vOffset + i].pt = *coords; - p.m_vertices[vOffset + i].normal = *normals; - p.m_vertices[vOffset + i].tex = *texCoords; - p.m_vertices[vOffset + i].depth = depth; + vertices[vOffset + i].pt = *coords; + vertices[vOffset + i].normal = *normals; + vertices[vOffset + i].tex = *texCoords; + vertices[vOffset + i].depth = depth; coords = reinterpret_cast(reinterpret_cast(coords) + coordsStride); normals = reinterpret_cast(reinterpret_cast(normals) + normalsStride); texCoords = reinterpret_cast(reinterpret_cast(texCoords) + texCoordsStride); } - p.m_currentVertex += size; + p.advanceVx(size); for (size_t i = 0; i < size; ++i) - p.m_indices[iOffset + i] = vOffset + i; + indices[iOffset + i] = vOffset + i; - p.m_currentIndex += size; + p.advanceIdx(size); } void GeometryBatcher::addTexturedList(m2::PointF const * coords, @@ -567,4 +604,139 @@ namespace graphics flush(-1); base_t::applySharpStates(); } + + bool GeometryBatcher::isDynamicPage(int i) const + { + return (i >= m_startDynamicPage) && (i < m_startDynamicPage + m_dynamicPagesCount); + } + + void GeometryBatcher::flushDynamicPage() + { + callClearPageFns(m_dynamicPage); + changeDynamicPage(); + } + + int GeometryBatcher::nextDynamicPage() const + { + if (m_dynamicPage == m_startDynamicPage + m_dynamicPagesCount - 1) + return m_startDynamicPage; + else + return m_dynamicPage + 1; + } + + void GeometryBatcher::changeDynamicPage() + { + m_dynamicPage = nextDynamicPage(); + } + + int GeometryBatcher::nextPipeline(int i) const + { + ASSERT(i < pipelinesCount(), ()); + + if (isDynamicPage(i)) + return nextDynamicPage(); + + /// for static and text pages return same index as passed in. + return i; + } + + void GeometryBatcher::changePipeline(int i) + { + if (isDynamicPage(i)) + changeDynamicPage(); + } + + /// This function is set to perform as a callback on texture or handles overflow + /// BUT! Never called on texture overflow, as this situation + /// is explicitly checked in the mapXXX() functions. + void GeometryBatcher::onDynamicOverflow(int pipelineID) + { + LOG(LINFO, ("DynamicPage flushing, pipelineID=", (uint32_t)pipelineID)); + flushDynamicPage(); + } + + uint8_t GeometryBatcher::dynamicPage() const + { + return m_dynamicPage; + } + + uint32_t GeometryBatcher::mapInfo(Resource::Info const & info) + { + uint32_t res = invalidPageHandle(); + + for (uint8_t i = 0; i < pipelinesCount(); ++i) + { + res = pipeline(i).cache()->findInfo(info); + if (res != invalidPageHandle()) + return packID(i, res); + } + + if (!pipeline(m_dynamicPage).cache()->hasRoom(info)) + flushDynamicPage(); + + return packID(m_dynamicPage, + pipeline(m_dynamicPage).cache()->mapInfo(info)); + } + + uint32_t GeometryBatcher::findInfo(Resource::Info const & info) + { + uint32_t res = invalidPageHandle(); + + for (uint8_t i = 0; i < pipelinesCount(); ++i) + { + res = pipeline(i).cache()->findInfo(info); + if (res != invalidPageHandle()) + return packID(i, res); + } + + return res; + } + + bool GeometryBatcher::mapInfo(Resource::Info const * const * infos, + uint32_t * ids, + size_t count) + { + int startDynamicPage = m_dynamicPage; + int cycles = 0; + + int i = 0; + + do + { + ids[i] = pipeline(m_dynamicPage).cache()->findInfo(*infos[i]); + + if ((ids[i] == invalidPageHandle()) + || (unpackID(ids[i]).first != m_dynamicPage)) + { + /// try to pack on the currentDynamicPage + while (!pipeline(m_dynamicPage).cache()->hasRoom(*infos[i])) + { + /// no room - flush the page + flushDynamicPage(); + + if (startDynamicPage == m_dynamicPage) + cycles += 1; + + /// there could be maximum 2 cycles to + /// pack the sequence as a whole. + /// second cycle is necessary as the first one + /// could possibly run on partially packed skin pages. + if (cycles == 2) + return false; + + /// re-start packing + i = 0; + } + + ids[i] = packID(m_dynamicPage, + pipeline(m_dynamicPage).cache()->mapInfo(*infos[i])); + } + + ++i; + } + while (i != count); + + return true; + } + } // namespace graphics diff --git a/graphics/geometry_batcher.hpp b/graphics/geometry_batcher.hpp index 0f2800d8a6..9098348697 100644 --- a/graphics/geometry_batcher.hpp +++ b/graphics/geometry_batcher.hpp @@ -28,7 +28,6 @@ namespace graphics typedef PipelinesManager base_t; bool m_isAntiAliased; - bool m_isSynchronized; int m_aaShift; @@ -43,11 +42,33 @@ namespace graphics int verticesLeft(int pipelineID) const; int indicesLeft(int pipelineID) const; - GeometryBatcher(base_t::Params const & params); + struct Params : public base_t::Params + { + EStorageType m_storageType; + ETextureType m_textureType; + string m_skinName; + Params(); + }; + + uint8_t m_startStaticPage; + uint8_t m_staticPagesCount; + + uint8_t m_startDynamicPage; + uint8_t m_dynamicPage; + uint8_t m_dynamicPagesCount; + + GeometryBatcher(Params const & params); void beginFrame(); void endFrame(); + bool isDynamicPage(int i) const; + void flushDynamicPage(); + int nextDynamicPage() const; + void changeDynamicPage(); + + void onDynamicOverflow(int pipelineID); + public: /// This functions hide the base_t functions with the same name and signature @@ -59,6 +80,15 @@ namespace graphics void clear(Color const & c, bool clearRT = true, float depth = 1.0, bool clearDepth = true); /// @} + unsigned reservePipelines(vector > const & caches, + EStorageType storageType, + VertexDecl const * decl); + + unsigned reservePipelines(unsigned count, + ETextureType textureType, + EStorageType storageType, + VertexDecl const * decl); + void addTexturedFan(m2::PointF const * coords, m2::PointF const * normals, m2::PointF const * texCoords, @@ -100,7 +130,7 @@ namespace graphics double depth, int pipelineID); - void addTexturedListStrided(m2::PointD const * coords, + void addTexturedListStrided(m2::PointF const * coords, size_t coordsStride, m2::PointF const * normals, size_t normalsStride, @@ -110,7 +140,7 @@ namespace graphics double depth, int pipelineID); - void addTexturedListStrided(m2::PointF const * coords, + void addTexturedListStrided(m2::PointD const * coords, size_t coordsStride, m2::PointF const * normals, size_t normalsStride, @@ -150,5 +180,30 @@ namespace graphics void applyStates(); void applyBlitStates(); void applySharpStates(); + + /// map Resource::Info on skin + /// if found - return id. + /// if not - pack and return id. + uint32_t mapInfo(Resource::Info const & info); + /// map array of Resource::Info's on skin + bool mapInfo(Resource::Info const * const * infos, + uint32_t * ids, + size_t count); + + uint32_t findInfo(Resource::Info const & info); + + + uint8_t dynamicPage() const; + + /// change pipeline for its "backbuffer" counterpart. + /// pipelines works in pairs to employ "double-buffering" technique + /// to enhance CPU-GPU parallelism. + /// this function is called after any rendering command + /// issued to avoid the "GPU is waiting on texture used in + /// rendering call" issue. + /// @warning does nothing for pipelines with EStaticTexture type. + /// (pipelines loaded at screen creation time) + void changePipeline(int i); + int nextPipeline(int i) const; }; } diff --git a/graphics/geometry_pipeline.cpp b/graphics/geometry_pipeline.cpp index adde464882..f5f7182871 100644 --- a/graphics/geometry_pipeline.cpp +++ b/graphics/geometry_pipeline.cpp @@ -9,14 +9,14 @@ namespace graphics EStorageType storageType, shared_ptr const & rm, VertexDecl const * decl) - : m_cache(cache), + : m_decl(decl), + m_cache(cache), m_currentVx(0), m_currentIdx(0), m_maxVx(0), m_maxIdx(0), m_rm(rm), - m_storageType(storageType), - m_decl(decl) + m_storageType(storageType) {} GeometryPipeline::GeometryPipeline(ETextureType textureType, @@ -24,14 +24,14 @@ namespace graphics shared_ptr const & rm, VertexDecl const * decl, uint8_t pipelineID) - : m_cache(new ResourceCache(rm, textureType, pipelineID)), + : m_decl(decl), + m_cache(new ResourceCache(rm, textureType, pipelineID)), m_currentVx(0), m_currentIdx(0), m_maxVx(0), m_maxIdx(0), m_rm(rm), - m_storageType(storageType), - m_decl(decl) + m_storageType(storageType) {} bool GeometryPipeline::hasStorage() const @@ -53,6 +53,11 @@ namespace graphics if (m_storage.isValid()) { + if (!m_storage.m_vertices->isLocked()) + m_storage.m_vertices->lock(); + if (!m_storage.m_indices->isLocked()) + m_storage.m_indices->lock(); + m_maxVx = m_storage.m_vertices->size() / m_decl->elemSize(); m_maxIdx = m_storage.m_indices->size() / sizeof(unsigned short); } @@ -69,13 +74,18 @@ namespace graphics m_cache->resetTexture(); } + void GeometryPipeline::clearStorage() const + { + m_currentVx = 0; + m_currentIdx = 0; + } + void GeometryPipeline::resetStorage() const { m_storage = gl::Storage(); - m_currentVx = 0; - m_currentIdx = 0; m_maxIdx = 0; m_maxVx = 0; + clearStorage(); } bool GeometryPipeline::hasRoom(unsigned verticesCount, unsigned indicesCount) const diff --git a/graphics/geometry_pipeline.hpp b/graphics/geometry_pipeline.hpp index 6543dba964..c3d8de6ea4 100644 --- a/graphics/geometry_pipeline.hpp +++ b/graphics/geometry_pipeline.hpp @@ -125,6 +125,8 @@ namespace graphics /// Reset storage and rendering info, /// associated with this pipeline. void resetStorage() const; + /// Clear rendered geometry information. + void clearStorage() const; /// Does this pipeline has something to render? bool hasGeometry() const; diff --git a/graphics/image_renderer.cpp b/graphics/image_renderer.cpp index 26ea05e730..8bd12404c9 100644 --- a/graphics/image_renderer.cpp +++ b/graphics/image_renderer.cpp @@ -41,7 +41,7 @@ namespace graphics GeometryPipeline & p = pipeline(res->m_pipelineID); - shared_ptr const & texture = p.m_cache->texture(); + shared_ptr const & texture = p.texture(); m2::PointF texPts[6] = { diff --git a/graphics/opengl/geometry_renderer.hpp b/graphics/opengl/geometry_renderer.hpp index ccad9699ff..f8cc53c4c4 100644 --- a/graphics/opengl/geometry_renderer.hpp +++ b/graphics/opengl/geometry_renderer.hpp @@ -46,6 +46,8 @@ namespace graphics size_t m_indicesCount; size_t m_indicesOffs; EPrimitives m_primitiveType; + VertexDecl * m_vertexDecl; + shared_ptr m_program; void perform(); void dump(); diff --git a/graphics/opengl/storage.cpp b/graphics/opengl/storage.cpp index 6578ddec39..6b3eba7a76 100644 --- a/graphics/opengl/storage.cpp +++ b/graphics/opengl/storage.cpp @@ -17,7 +17,7 @@ namespace graphics bool Storage::isValid() const { - return m_vertices.get(); + return m_vertices && m_indices; } } } diff --git a/graphics/path_renderer.cpp b/graphics/path_renderer.cpp index 8141b4a625..e293226711 100644 --- a/graphics/path_renderer.cpp +++ b/graphics/path_renderer.cpp @@ -96,7 +96,7 @@ namespace graphics GeometryPipeline & p = pipeline(res->m_pipelineID); - shared_ptr texture = p.m_cache->texture(); + shared_ptr texture = p.texture(); if (!texture) { @@ -194,7 +194,7 @@ namespace graphics GeometryPipeline & p = pipeline(pen->m_pipelineID); - shared_ptr texture = p.m_cache->texture(); + shared_ptr texture = p.texture(); if (!texture) { @@ -291,7 +291,7 @@ namespace graphics GeometryPipeline & p = pipeline(res->m_pipelineID); - shared_ptr texture = p.m_cache->texture(); + shared_ptr texture = p.texture(); if (!texture) { diff --git a/graphics/pipeline_manager.cpp b/graphics/pipeline_manager.cpp index e7f28e3452..7666ec1b00 100644 --- a/graphics/pipeline_manager.cpp +++ b/graphics/pipeline_manager.cpp @@ -14,87 +14,14 @@ namespace graphics { - PipelinesManager::Params::Params() - : m_storageType(ELargeStorage), - m_textureType(ELargeTexture) - {} - - PipelinesManager::PipelinesManager(Params const & p) + PipelinesManager::PipelinesManager(base_t::Params const & p) : base_t(p) - { - vector > caches; - loadSkin(resourceManager(), p.m_skinName, caches); - - m_staticPagesCount = caches.size(); - m_startStaticPage = reservePipelines(caches, - EMediumStorage); - - - m_dynamicPagesCount = 2; - m_startDynamicPage = reservePipelines(m_dynamicPagesCount, - p.m_textureType, - p.m_storageType); - m_dynamicPage = m_startDynamicPage; - } - - void PipelinesManager::GeometryPipeline::checkStorage(shared_ptr const & rm) const - { - if (!m_hasStorage) - { - if (m_storageType != EInvalidStorage) - m_storage = rm->storagePool(m_storageType)->Reserve(); - else - { - LOG(LERROR, ("invalid storage type in checkStorage")); - return; - } - - if (m_storage.m_vertices && m_storage.m_indices) - { - m_maxVertices = m_storage.m_vertices->size() / sizeof(gl::Vertex); - m_maxIndices = m_storage.m_indices->size() / sizeof(unsigned short); - - if (!m_storage.m_vertices->isLocked()) - m_storage.m_vertices->lock(); - if (!m_storage.m_indices->isLocked()) - m_storage.m_indices->lock(); - - m_vertices = static_cast(m_storage.m_vertices->data()); - m_indices = static_cast(m_storage.m_indices->data()); - - m_hasStorage = true; - } - else - { - m_maxVertices = 0; - m_maxIndices = 0; - - m_vertices = 0; - m_indices = 0; - - m_hasStorage = false; - } - } - } - - ETextureType PipelinesManager::GeometryPipeline::textureType() const - { - return m_cache->type(); - } - - void PipelinesManager::GeometryPipeline::setTextureType(ETextureType type) - { - m_cache->setType(type); - } - - void PipelinesManager::GeometryPipeline::setStorageType(EStorageType type) - { - m_storageType = type; - } + {} unsigned PipelinesManager::reservePipelines(unsigned count, ETextureType textureType, - EStorageType storageType) + EStorageType storageType, + VertexDecl const * decl) { vector > v; @@ -103,30 +30,21 @@ namespace graphics textureType, pipelinesCount() + i))); - return reservePipelines(v, storageType); + return reservePipelines(v, storageType, decl); } unsigned PipelinesManager::reservePipelines(vector > const & caches, - EStorageType storageType) + EStorageType storageType, + VertexDecl const * decl) { unsigned res = m_pipelines.size(); for (unsigned i = 0; i < caches.size(); ++i) { - GeometryPipeline p; - - p.m_cache = caches[i]; - p.m_currentIndex = 0; - p.m_currentVertex = 0; - p.m_hasStorage = false; - - p.m_maxVertices = 0; - p.m_maxIndices = 0; - - p.m_vertices = 0; - p.m_indices = 0; - - p.m_storageType = storageType; + GeometryPipeline p(caches[i], + storageType, + resourceManager(), + decl); m_pipelines.push_back(p); m_clearPageFns.push_back(clearPageFns()); @@ -136,7 +54,6 @@ namespace graphics addClearPageFn(pipelineID, bind(&PipelinesManager::freeTexture, this, pipelineID), 99); addClearPageFn(pipelineID, bind(&PipelinesManager::clearPageHandles, this, pipelineID), 0); - p.m_cache->addHandlesOverflowFn(bind(&PipelinesManager::onDynamicOverflow, this, pipelineID), 0); } return res; @@ -148,8 +65,7 @@ namespace graphics { discardPipeline(i); freePipeline(i); - if (m_pipelines[i].textureType() != EStaticTexture) - freeTexture(i); + freeTexture(i); } } @@ -175,87 +91,9 @@ namespace graphics id_pair_t p = unpackID(id); ASSERT(p.first < m_pipelines.size(), ()); - return m_pipelines[p.first].m_cache->fromID(p.second); + return m_pipelines[p.first].cache()->fromID(p.second); } - uint32_t PipelinesManager::mapInfo(Resource::Info const & info) - { - uint32_t res = invalidPageHandle(); - - for (uint8_t i = 0; i < m_pipelines.size(); ++i) - { - res = m_pipelines[i].m_cache->findInfo(info); - if (res != invalidPageHandle()) - return packID(i, res); - } - - if (!m_pipelines[m_dynamicPage].m_cache->hasRoom(info)) - flushDynamicPage(); - - return packID(m_dynamicPage, - m_pipelines[m_dynamicPage].m_cache->mapInfo(info)); - } - - uint32_t PipelinesManager::findInfo(Resource::Info const & info) - { - uint32_t res = invalidPageHandle(); - - for (uint8_t i = 0; i < m_pipelines.size(); ++i) - { - res = m_pipelines[i].m_cache->findInfo(info); - if (res != invalidPageHandle()) - return packID(i, res); - } - - return res; - } - - bool PipelinesManager::mapInfo(Resource::Info const * const * infos, - uint32_t * ids, - size_t count) - { - int startDynamicPage = m_dynamicPage; - int cycles = 0; - - int i = 0; - - do - { - ids[i] = m_pipelines[m_dynamicPage].m_cache->findInfo(*infos[i]); - - if ((ids[i] == invalidPageHandle()) - || (unpackID(ids[i]).first != m_dynamicPage)) - { - /// try to pack on the currentDynamicPage - while (!m_pipelines[m_dynamicPage].m_cache->hasRoom(*infos[i])) - { - /// no room - flush the page - flushDynamicPage(); - - if (startDynamicPage == m_dynamicPage) - cycles += 1; - - /// there could be maximum 2 cycles to - /// pack the sequence as a whole. - /// second cycle is necessary as the first one - /// could possibly run on partially packed skin pages. - if (cycles == 2) - return false; - - /// re-start packing - i = 0; - } - - ids[i] = packID(m_dynamicPage, - m_pipelines[m_dynamicPage].m_cache->mapInfo(*infos[i])); - } - - ++i; - } - while (i != count); - - return true; - } void PipelinesManager::addClearPageFn(int pipelineID, clearPageFn fn, int priority) { @@ -274,57 +112,7 @@ namespace graphics void PipelinesManager::clearPageHandles(int pipelineID) { - m_pipelines[pipelineID].m_cache->clearHandles(); - } - - /// This function is set to perform as a callback on texture or handles overflow - /// BUT! Never called on texture overflow, as this situation - /// is explicitly checked in the mapXXX() functions. - void PipelinesManager::onDynamicOverflow(int pipelineID) - { - LOG(LINFO, ("DynamicPage flushing, pipelineID=", (uint32_t)pipelineID)); - flushDynamicPage(); - } - - bool PipelinesManager::isDynamicPage(int i) const - { - return (i >= m_startDynamicPage) && (i < m_startDynamicPage + m_dynamicPagesCount); - } - - void PipelinesManager::flushDynamicPage() - { - callClearPageFns(m_dynamicPage); - changeDynamicPage(); - } - - int PipelinesManager::nextDynamicPage() const - { - if (m_dynamicPage == m_startDynamicPage + m_dynamicPagesCount - 1) - return m_startDynamicPage; - else - return m_dynamicPage + 1; - } - - void PipelinesManager::changeDynamicPage() - { - m_dynamicPage = nextDynamicPage(); - } - - int PipelinesManager::nextPage(int i) const - { - ASSERT(i < m_pipelines.size(), ()); - - if (isDynamicPage(i)) - return nextDynamicPage(); - - /// for static and text pages return same index as passed in. - return i; - } - - void PipelinesManager::changePage(int i) - { - if (isDynamicPage(i)) - changeDynamicPage(); + m_pipelines[pipelineID].cache()->clearHandles(); } uint32_t PipelinesManager::invalidHandle() const @@ -337,11 +125,6 @@ namespace graphics return 0x00FFFFFF; } - uint8_t PipelinesManager::dynamicPage() const - { - return m_dynamicPage; - } - void PipelinesManager::memoryWarning() { } @@ -357,92 +140,74 @@ namespace graphics void PipelinesManager::clearHandles() { for (unsigned i = 0; i < m_pipelines.size(); ++i) - m_pipelines[i].m_cache->clear(); + m_pipelines[i].cache()->clear(); } void PipelinesManager::freeTexture(int pipelineID) { - if (!m_pipelines[pipelineID].m_cache->hasTexture()) - return; + GeometryPipeline & p = m_pipelines[pipelineID]; - shared_ptr texture = m_pipelines[pipelineID].m_cache->texture(); - TTexturePool * texturePool = 0; - - ETextureType type = m_pipelines[pipelineID].m_cache->type(); - - if (type != EStaticTexture) - texturePool = resourceManager()->texturePool(type); - else + if (p.hasTexture()) { - LOG(LWARNING, ("texture with EStatic can't be freed.")); - return; + shared_ptr texture = p.texture(); + TTexturePool * texturePool = p.texturePool(); + + if (texturePool == 0) + return; + + base_t::freeTexture(texture, texturePool); + + p.resetTexture(); } - - base_t::freeTexture(texture, texturePool); - - m_pipelines[pipelineID].m_cache->resetTexture(); } void PipelinesManager::freePipeline(int pipelineID) { - GeometryPipeline & pipeline = m_pipelines[pipelineID]; + GeometryPipeline & p = m_pipelines[pipelineID]; - if (pipeline.m_hasStorage) + if (p.hasStorage()) { - TStoragePool * storagePool = 0; - if (pipeline.m_storageType != EInvalidStorage) - storagePool = resourceManager()->storagePool(pipeline.m_storageType); - else - { - LOG(LERROR, ("invalid pipeline type in freePipeline")); + TStoragePool * storagePool = p.storagePool(); + + if (storagePool == 0) return; - } - base_t::freeStorage(pipeline.m_storage, storagePool); + base_t::freeStorage(p.storage(), storagePool); - pipeline.m_hasStorage = false; - pipeline.m_storage = gl::Storage(); + p.resetStorage(); } } bool PipelinesManager::flushPipeline(int pipelineID) { GeometryPipeline & p = m_pipelines[pipelineID]; - if (p.m_currentIndex) + + if (p.hasGeometry()) { - if (p.m_cache->hasData()) + if (p.hasUploadData()) { - uploadResources(&p.m_cache->uploadQueue()[0], - p.m_cache->uploadQueue().size(), - p.m_cache->texture()); - p.m_cache->clearUploadQueue(); + ResourceCache::TUploadQueue const & uploadQueue = p.uploadQueue(); + + uploadResources(&uploadQueue[0], + uploadQueue.size(), + p.texture()); + + p.clearUploadQueue(); } unlockPipeline(pipelineID); - drawGeometry(p.m_cache->texture(), - p.m_storage, - p.m_currentIndex, + drawGeometry(p.texture(), + p.storage(), + p.currentIdx(), 0, ETriangles); discardPipeline(pipelineID); - if (isDebugging()) - { - p.m_verticesDrawn += p.m_currentVertex; - p.m_indicesDrawn += p.m_currentIndex; - // LOG(LINFO, ("Pipeline #", i - 1, "draws ", pipeline.m_currentIndex / 3, "/", pipeline.m_maxIndices / 3," triangles")); - } - freePipeline(pipelineID); - p.m_maxIndices = 0; - p.m_maxVertices = 0; - p.m_vertices = 0; - p.m_indices = 0; - p.m_currentIndex = 0; - p.m_currentVertex = 0; + resetPipeline(pipelineID); return true; } @@ -453,52 +218,45 @@ namespace graphics void PipelinesManager::unlockPipeline(int pipelineID) { GeometryPipeline & pipeline = m_pipelines[pipelineID]; - base_t::unlockStorage(pipeline.m_storage); + if (pipeline.hasStorage()) + base_t::unlockStorage(pipeline.storage()); } void PipelinesManager::discardPipeline(int pipelineID) { GeometryPipeline & pipeline = m_pipelines[pipelineID]; - - if (pipeline.m_hasStorage) - base_t::discardStorage(pipeline.m_storage); + if (pipeline.hasStorage()) + base_t::discardStorage(pipeline.storage()); } - void PipelinesManager::reset(int pipelineID) + void PipelinesManager::resetPipeline(int pipelineID) { for (size_t i = 0; i < m_pipelines.size(); ++i) { if ((pipelineID == -1) || ((size_t)pipelineID == i)) - { - m_pipelines[i].m_currentVertex = 0; - m_pipelines[i].m_currentIndex = 0; - } + pipeline(i).resetStorage(); + } + } + + void PipelinesManager::clearPipeline(int pipelineID) + { + for (size_t i = 0; i < m_pipelines.size(); ++i) + { + if ((pipelineID == -1) || ((size_t)pipelineID == i)) + pipeline(i).clearStorage(); } } void PipelinesManager::beginFrame() { base_t::beginFrame(); - reset(-1); - for (size_t i = 0; i < m_pipelines.size(); ++i) - { - m_pipelines[i].m_verticesDrawn = 0; - m_pipelines[i].m_indicesDrawn = 0; - } + clearPipeline(-1); } void PipelinesManager::endFrame() { - /// Syncronization point. enableClipRect(false); - if (isDebugging()) - { - for (size_t i = 0; i < m_pipelines.size(); ++i) - if ((m_pipelines[i].m_verticesDrawn != 0) || (m_pipelines[i].m_indicesDrawn != 0)) - LOG(LINFO, ("pipeline #", i, " vertices=", m_pipelines[i].m_verticesDrawn, ", triangles=", m_pipelines[i].m_indicesDrawn / 3)); - } - /// is the rendering was cancelled, there possibly could /// be "ghost" render styles which are present in internal /// skin structures, but aren't rendered onto skin texture. @@ -515,12 +273,12 @@ namespace graphics return m_pipelines.size(); } - PipelinesManager::GeometryPipeline & PipelinesManager::pipeline(int i) + GeometryPipeline & PipelinesManager::pipeline(int i) { return m_pipelines[i]; } - PipelinesManager::GeometryPipeline const & PipelinesManager::pipeline(int i) const + GeometryPipeline const & PipelinesManager::pipeline(int i) const { return m_pipelines[i]; } diff --git a/graphics/pipeline_manager.hpp b/graphics/pipeline_manager.hpp index 8e38aaa732..2f50bb3763 100644 --- a/graphics/pipeline_manager.hpp +++ b/graphics/pipeline_manager.hpp @@ -11,6 +11,7 @@ #include "display_list_renderer.hpp" #include "resource.hpp" +#include "geometry_pipeline.hpp" namespace graphics { @@ -32,55 +33,11 @@ namespace graphics typedef function clearPageFn; typedef function overflowFn; - struct GeometryPipeline - { - size_t m_verticesDrawn; - size_t m_indicesDrawn; - - size_t m_currentVertex; - size_t m_currentIndex; - - /// made mutable to implement lazy reservation of m_storage - /// @{ - mutable size_t m_maxVertices; - mutable size_t m_maxIndices; - - mutable bool m_hasStorage; - mutable gl::Storage m_storage; - - mutable gl::Vertex * m_vertices; - mutable unsigned short * m_indices; - /// @} - - ETextureType m_textureType; - EStorageType m_storageType; - - int verticesLeft(); - int indicesLeft(); - - ETextureType textureType() const; - void setTextureType(ETextureType type); - void setStorageType(EStorageType type); - - shared_ptr m_cache; - - void checkStorage(shared_ptr const & resourceManager) const; - }; - private: vector m_pipelines; - uint8_t m_startStaticPage; - uint8_t m_staticPagesCount; - - uint8_t m_startDynamicPage; - uint8_t m_dynamicPage; - uint8_t m_dynamicPagesCount; - typedef pair id_pair_t; - id_pair_t unpackID(uint32_t id) const; - uint32_t packID(uint8_t, uint32_t) const; typedef priority_queue, vector >, @@ -88,7 +45,6 @@ namespace graphics > clearPageFns; vector m_clearPageFns; - void callClearPageFns(int pipelineID); typedef priority_queue, vector >, @@ -102,58 +58,37 @@ namespace graphics public: - struct Params : public base_t::Params - { - EStorageType m_storageType; - ETextureType m_textureType; - string m_skinName; - Params(); - }; - - PipelinesManager(Params const & params); + PipelinesManager(base_t::Params const & params); ~PipelinesManager(); + id_pair_t unpackID(uint32_t id) const; + uint32_t packID(uint8_t, uint32_t) const; + + /// obtain Resource from id + Resource const * fromID(uint32_t id); + + void addClearPageFn(int pipelineID, clearPageFn fn, int priority); + void callClearPageFns(int pipelineID); + /// reserve static pipelines unsigned reservePipelines(vector > const & caches, - EStorageType storageType); + EStorageType storageType, + VertexDecl const * decl); + /// reserve dynamic pipelines unsigned reservePipelines(unsigned count, ETextureType textureType, - EStorageType storageType); + EStorageType storageType, + VertexDecl const * decl); - bool isDynamicPage(int i) const; - void flushDynamicPage(); - int nextDynamicPage() const; - void changeDynamicPage(); - - void onDynamicOverflow(int pipelineID); void freePipeline(int pipelineID); void freeTexture(int pipelineID); bool flushPipeline(int pipelineID); void unlockPipeline(int pipelineID); void discardPipeline(int pipelineID); - void reset(int pipelineID); - - public: - - /// obtain Resource from id - Resource const * fromID(uint32_t id); - - /// map Resource::Info on skin - /// if found - return id. - /// if not - pack and return id. - uint32_t mapInfo(Resource::Info const & info); - /// map array of Resource::Info's on skin - bool mapInfo(Resource::Info const * const * infos, - uint32_t * ids, - size_t count); - - uint32_t findInfo(Resource::Info const & info); - - /// adding function which will be called, when some SkinPage - /// is getting cleared. - void addClearPageFn(int pipelineID, clearPageFn fn, int priority); + void resetPipeline(int pipelineID); + void clearPipeline(int pipelineID); GeometryPipeline const & pipeline(int i) const; GeometryPipeline & pipeline(int i); @@ -162,18 +97,6 @@ namespace graphics uint32_t invalidHandle() const; uint32_t invalidPageHandle() const; - uint8_t dynamicPage() const; - - /// change page for its "backbuffer" counterpart. - /// this function is called after any rendering command - /// issued to avoid the "GPU is waiting on texture used in - /// rendering call" issue. - /// @warning does nothing for static pages - /// (pages loaded at skin creation time) - /// and text pages. - void changePage(int i); - int nextPage(int i) const; - void clearHandles(); void memoryWarning(); diff --git a/graphics/resource_cache.cpp b/graphics/resource_cache.cpp index 385462856d..5f6b991625 100644 --- a/graphics/resource_cache.cpp +++ b/graphics/resource_cache.cpp @@ -197,6 +197,20 @@ namespace graphics LOG(LINFO, ("reserveTexture call for with invalid type param")); } + TTexturePool * ResourceCache::texturePool() const + { + if (m_textureType == EStaticTexture) + return 0; + + if (m_textureType != EInvalidTexture) + return m_resourceManager->texturePool(m_textureType); + else + { + LOG(LWARNING, ("no texturePool with such type", m_textureType)); + return 0; + } + } + void ResourceCache::createPacker() { if (m_textureType != EStaticTexture) diff --git a/graphics/resource_cache.hpp b/graphics/resource_cache.hpp index b79db6d752..2b900d3e54 100644 --- a/graphics/resource_cache.hpp +++ b/graphics/resource_cache.hpp @@ -9,6 +9,7 @@ #include "resource.hpp" #include "packets_queue.hpp" #include "defines.hpp" +#include "resource_manager.hpp" namespace graphics { @@ -107,5 +108,7 @@ namespace graphics bool hasTexture() const; shared_ptr const & texture() const; void setTexture(shared_ptr const & t); + + TTexturePool * texturePool() const; }; } diff --git a/graphics/resource_manager.hpp b/graphics/resource_manager.hpp index 217f934c31..8f8aa7513c 100644 --- a/graphics/resource_manager.hpp +++ b/graphics/resource_manager.hpp @@ -12,7 +12,6 @@ #include "opengl/storage.hpp" #include "opengl/program_manager.hpp" #include "glyph_cache.hpp" -#include "resource_cache.hpp" #include "data_formats.hpp" #include "defines.hpp" diff --git a/graphics/shape_renderer.cpp b/graphics/shape_renderer.cpp index 2ef3bcee63..494bd63d55 100644 --- a/graphics/shape_renderer.cpp +++ b/graphics/shape_renderer.cpp @@ -123,7 +123,7 @@ namespace graphics GeometryPipeline & p = pipeline(res->m_pipelineID); - shared_ptr texture = p.m_cache->texture(); + shared_ptr texture = p.texture(); if (!texture) { @@ -167,7 +167,7 @@ namespace graphics GeometryPipeline & p = pipeline(res->m_pipelineID); - shared_ptr texture = p.m_cache->texture(); + shared_ptr texture = p.texture(); if (!texture) { @@ -205,7 +205,7 @@ namespace graphics GeometryPipeline & p = pipeline(res->m_pipelineID); - shared_ptr texture = p.m_cache->texture(); + shared_ptr texture = p.texture(); if (!texture) {