LCOV - code coverage report
Current view: top level - source/renderer - VertexBufferManager.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 56 92 60.9 %
Date: 2023-01-19 00:18:29 Functions: 10 13 76.9 %

          Line data    Source code
       1             : /* Copyright (C) 2022 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "VertexBufferManager.h"
      21             : 
      22             : #include "ps/CLogger.h"
      23             : 
      24             : #define DUMP_VB_STATS 0 // for debugging
      25             : 
      26             : namespace
      27             : {
      28             : 
      29           1 : const char* GetBufferTypeName(
      30             :     const Renderer::Backend::IBuffer::Type type)
      31             : {
      32           1 :     const char* name = "UnknownBuffer";
      33           1 :     switch (type)
      34             :     {
      35           0 :     case Renderer::Backend::IBuffer::Type::VERTEX:
      36           0 :         name = "VertexBuffer";
      37           0 :         break;
      38           1 :     case Renderer::Backend::IBuffer::Type::INDEX:
      39           1 :         name = "IndexBuffer";
      40           1 :         break;
      41           0 :     default:
      42           0 :         debug_warn("Unknown buffer type");
      43           0 :         break;
      44             :     }
      45           1 :     return name;
      46             : }
      47             : 
      48           1 : const char* GetGroupName(
      49             :     const CVertexBufferManager::Group group)
      50             : {
      51           1 :     const char* name = "Unknown";
      52           1 :     switch (group)
      53             :     {
      54           1 :     case CVertexBufferManager::Group::DEFAULT:
      55           1 :         name = "Default";
      56           1 :         break;
      57           0 :     case CVertexBufferManager::Group::TERRAIN:
      58           0 :         name = "Terrain";
      59           0 :         break;
      60           0 :     case CVertexBufferManager::Group::WATER:
      61           0 :         name = "Water";
      62           0 :         break;
      63           0 :     default:
      64           0 :         debug_warn("Unknown buffer group");
      65           0 :         break;
      66             :     }
      67           1 :     return name;
      68             : }
      69             : 
      70             : } // anonymous namespace
      71             : 
      72           1 : CVertexBufferManager g_VBMan;
      73             : 
      74           6 : CVertexBufferManager::Handle::Handle(Handle&& other)
      75           6 :     : m_Chunk(other.m_Chunk)
      76             : {
      77           6 :     other.m_Chunk = nullptr;
      78           6 : }
      79             : 
      80           6 : CVertexBufferManager::Handle& CVertexBufferManager::Handle::operator=(Handle&& other)
      81             : {
      82           6 :     if (&other == this)
      83           0 :         return *this;
      84             : 
      85           6 :     if (IsValid())
      86           0 :         Reset();
      87             : 
      88          12 :     Handle tmp(std::move(other));
      89           6 :     swap(*this, tmp);
      90             : 
      91           6 :     return *this;
      92             : }
      93             : 
      94           6 : CVertexBufferManager::Handle::Handle(CVertexBuffer::VBChunk* chunk)
      95           6 :     : m_Chunk(chunk)
      96             : {
      97           6 : }
      98             : 
      99         108 : void CVertexBufferManager::Handle::Reset()
     100             : {
     101         108 :     if (!IsValid())
     102         102 :         return;
     103             : 
     104           6 :     g_VBMan.Release(m_Chunk);
     105           6 :     m_Chunk = nullptr;
     106             : }
     107             : 
     108             : // Explicit shutdown of the vertex buffer subsystem.
     109             : // This avoids the ordering issues that arise when using destructors of
     110             : // global instances.
     111           0 : void CVertexBufferManager::Shutdown()
     112             : {
     113           0 :     for (int group = static_cast<int>(Group::DEFAULT); group < static_cast<int>(Group::COUNT); ++group)
     114           0 :         m_Buffers[group].clear();
     115           0 : }
     116             : 
     117             : /**
     118             :  * AllocateChunk: try to allocate a buffer of given number of vertices (each of
     119             :  * given size), with the given type, and using the given texture - return null
     120             :  * if no free chunks available
     121             :  */
     122           6 : CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk(
     123             :     const size_t vertexSize, const size_t numberOfVertices,
     124             :     const Renderer::Backend::IBuffer::Type type,
     125             :     const bool dynamic, void* backingStore, Group group)
     126             : {
     127           6 :     ENSURE(vertexSize > 0);
     128           6 :     ENSURE(numberOfVertices > 0);
     129             : 
     130           6 :     CVertexBuffer::VBChunk* result = nullptr;
     131             : 
     132           6 :     if (CVertexBuffer::UseStreaming(dynamic))
     133           0 :         ENSURE(backingStore != NULL);
     134             : 
     135             :     // TODO, RC - run some sanity checks on allocation request
     136             : 
     137           6 :     std::vector<std::unique_ptr<CVertexBuffer>>& buffers = m_Buffers[static_cast<int>(group)];
     138             : 
     139             : #if DUMP_VB_STATS
     140             :     debug_printf("\n============================\n# allocate vsize=%zu nverts=%zu\n\n", vertexSize, numVertices);
     141             :     for (const std::unique_ptr<CVertexBuffer>& buffer : buffers)
     142             :     {
     143             :         if (buffer->CompatibleVertexType(vertexSize, type, dynamic))
     144             :         {
     145             :             debug_printf("%p\n", buffer.get());
     146             :             buffer->DumpStatus();
     147             :         }
     148             :     }
     149             : #endif
     150             : 
     151             :     // iterate through all existing buffers testing for one that'll
     152             :     // satisfy the allocation
     153           6 :     for (const std::unique_ptr<CVertexBuffer>& buffer : buffers)
     154             :     {
     155           5 :         result = buffer->Allocate(vertexSize, numberOfVertices, type, dynamic, backingStore);
     156           5 :         if (result)
     157           5 :             return Handle(result);
     158             :     }
     159             : 
     160           1 :     char bufferName[64] = {0};
     161           1 :     snprintf(
     162             :         bufferName, std::size(bufferName), "%s (%s, %zu%s)",
     163             :         GetBufferTypeName(type), GetGroupName(group), vertexSize, (dynamic ? ", dynamic" : ""));
     164             : 
     165             :     // got this far; need to allocate a new buffer
     166           1 :     buffers.emplace_back(
     167             :         group == Group::DEFAULT
     168           2 :             ? std::make_unique<CVertexBuffer>(bufferName, vertexSize, type, dynamic)
     169             :             // Reduces the buffer size for not so frequent buffers.
     170           1 :             : std::make_unique<CVertexBuffer>(bufferName, vertexSize, type, dynamic, 1024 * 1024));
     171           1 :     result = buffers.back()->Allocate(vertexSize, numberOfVertices, type, dynamic, backingStore);
     172             : 
     173           1 :     if (!result)
     174             :     {
     175           0 :         LOGERROR("Failed to create backend buffer (%zu*%zu)", vertexSize, numberOfVertices);
     176           0 :         return Handle();
     177             :     }
     178             : 
     179           1 :     return Handle(result);
     180             : }
     181             : 
     182           6 : void CVertexBufferManager::Release(CVertexBuffer::VBChunk* chunk)
     183             : {
     184           6 :     ENSURE(chunk);
     185             : #if DUMP_VB_STATS
     186             :     debug_printf("\n============================\n# release %p nverts=%zu\n\n", chunk, chunk->m_Count);
     187             : #endif
     188           6 :     chunk->m_Owner->Release(chunk);
     189           6 : }
     190             : 
     191           0 : size_t CVertexBufferManager::GetBytesReserved() const
     192             : {
     193           0 :     size_t total = 0;
     194           0 :     for (int group = static_cast<int>(Group::DEFAULT); group < static_cast<int>(Group::COUNT); ++group)
     195           0 :         for (const std::unique_ptr<CVertexBuffer>& buffer : m_Buffers[static_cast<int>(group)])
     196           0 :             total += buffer->GetBytesReserved();
     197           0 :     return total;
     198             : }
     199             : 
     200           0 : size_t CVertexBufferManager::GetBytesAllocated() const
     201             : {
     202           0 :     size_t total = 0;
     203           0 :     for (int group = static_cast<int>(Group::DEFAULT); group < static_cast<int>(Group::COUNT); ++group)
     204           0 :         for (const std::unique_ptr<CVertexBuffer>& buffer : m_Buffers[static_cast<int>(group)])
     205           0 :             total += buffer->GetBytesAllocated();
     206           0 :     return total;
     207           3 : }

Generated by: LCOV version 1.13