LCOV - code coverage report
Current view: top level - source/renderer - VertexArray.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 82 143 57.3 %
Date: 2023-01-19 00:18:29 Functions: 15 26 57.7 %

          Line data    Source code
       1             : /* Copyright (C) 2023 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 "lib/alignment.h"
      21             : #include "lib/sysdep/rtl.h"
      22             : #include "maths/Vector3D.h"
      23             : #include "maths/Vector4D.h"
      24             : #include "ps/CLogger.h"
      25             : #include "graphics/Color.h"
      26             : #include "graphics/SColor.h"
      27             : #include "renderer/VertexArray.h"
      28             : #include "renderer/VertexBuffer.h"
      29             : #include "renderer/VertexBufferManager.h"
      30             : 
      31             : namespace
      32             : {
      33             : 
      34          48 : uint32_t GetAttributeSize(const Renderer::Backend::Format format)
      35             : {
      36          48 :     switch (format)
      37             :     {
      38          12 :     case Renderer::Backend::Format::R8G8B8A8_UNORM: FALLTHROUGH;
      39             :     case Renderer::Backend::Format::R8G8B8A8_UINT:
      40          12 :         return sizeof(u8) * 4;
      41           0 :     case Renderer::Backend::Format::A8_UNORM:
      42           0 :         return sizeof(u8);
      43          12 :     case Renderer::Backend::Format::R16_UNORM: FALLTHROUGH;
      44             :     case Renderer::Backend::Format::R16_UINT: FALLTHROUGH;
      45             :     case Renderer::Backend::Format::R16_SINT:
      46          12 :         return sizeof(u16);
      47           0 :     case Renderer::Backend::Format::R16G16_UNORM: FALLTHROUGH;
      48             :     case Renderer::Backend::Format::R16G16_UINT: FALLTHROUGH;
      49             :     case Renderer::Backend::Format::R16G16_SINT:
      50           0 :         return sizeof(u16) * 2;
      51           0 :     case Renderer::Backend::Format::R32_SFLOAT:
      52           0 :         return sizeof(float);
      53          12 :     case Renderer::Backend::Format::R32G32_SFLOAT:
      54          12 :         return sizeof(float) * 2;
      55          12 :     case Renderer::Backend::Format::R32G32B32_SFLOAT:
      56          12 :         return sizeof(float) * 3;
      57           0 :     case Renderer::Backend::Format::R32G32B32A32_SFLOAT:
      58           0 :         return sizeof(float) * 4;
      59           0 :     default:
      60           0 :         break;
      61             :     };
      62           0 :     return 0;
      63             : }
      64             : 
      65             : } // anonymous namespace
      66             : 
      67          18 : VertexArray::VertexArray(
      68          18 :     const Renderer::Backend::IBuffer::Type type, const bool dynamic)
      69          18 :     : m_Type(type), m_Dynamic(dynamic)
      70             : {
      71          18 :     m_NumberOfVertices = 0;
      72             : 
      73          18 :     m_BackingStore = 0;
      74          18 :     m_Stride = 0;
      75          18 : }
      76             : 
      77          36 : VertexArray::~VertexArray()
      78             : {
      79          18 :     Free();
      80          18 : }
      81             : 
      82             : // Free all resources on destruction or when a layout parameter changes
      83          66 : void VertexArray::Free()
      84             : {
      85          66 :     rtl_FreeAligned(m_BackingStore);
      86          66 :     m_BackingStore = 0;
      87             : 
      88          66 :     m_VB.Reset();
      89          66 : }
      90             : 
      91             : // Set the number of vertices stored in the array
      92          12 : void VertexArray::SetNumberOfVertices(const size_t numberOfVertices)
      93             : {
      94          12 :     if (numberOfVertices == m_NumberOfVertices)
      95           0 :         return;
      96             : 
      97          12 :     Free();
      98          12 :     m_NumberOfVertices = numberOfVertices;
      99             : }
     100             : 
     101             : // Add vertex attributes like Position, Normal, UV
     102          24 : void VertexArray::AddAttribute(Attribute* attr)
     103             : {
     104             :     // Attribute is supported is its size is greater than zero.
     105          24 :     ENSURE(GetAttributeSize(attr->format) > 0 && "Unsupported attribute.");
     106             : 
     107          24 :     attr->vertexArray = this;
     108          24 :     m_Attributes.push_back(attr);
     109             : 
     110          24 :     Free();
     111          24 : }
     112             : 
     113             : // Template specialization for GetIterator().
     114             : // We can put this into the source file because only a fixed set of types
     115             : // is supported for type safety.
     116             : template<>
     117           0 : VertexArrayIterator<CVector3D> VertexArray::Attribute::GetIterator<CVector3D>() const
     118             : {
     119           0 :     ENSURE(vertexArray);
     120           0 :     ENSURE(
     121             :         format == Renderer::Backend::Format::R32G32B32_SFLOAT ||
     122             :         format == Renderer::Backend::Format::R32G32B32A32_SFLOAT);
     123             : 
     124           0 :     return vertexArray->MakeIterator<CVector3D>(this);
     125             : }
     126             : 
     127             : template<>
     128           0 : VertexArrayIterator<CVector4D> VertexArray::Attribute::GetIterator<CVector4D>() const
     129             : {
     130           0 :     ENSURE(vertexArray);
     131           0 :     ENSURE(format == Renderer::Backend::Format::R32G32B32A32_SFLOAT);
     132             : 
     133           0 :     return vertexArray->MakeIterator<CVector4D>(this);
     134             : }
     135             : 
     136             : template<>
     137           0 : VertexArrayIterator<float[2]> VertexArray::Attribute::GetIterator<float[2]>() const
     138             : {
     139           0 :     ENSURE(vertexArray);
     140           0 :     ENSURE(format == Renderer::Backend::Format::R32G32_SFLOAT);
     141             : 
     142           0 :     return vertexArray->MakeIterator<float[2]>(this);
     143             : }
     144             : 
     145             : template<>
     146           0 : VertexArrayIterator<SColor4ub> VertexArray::Attribute::GetIterator<SColor4ub>() const
     147             : {
     148           0 :     ENSURE(vertexArray);
     149           0 :     ENSURE(
     150             :         format == Renderer::Backend::Format::R8G8B8A8_UNORM ||
     151             :         format == Renderer::Backend::Format::R8G8B8A8_UINT);
     152             : 
     153           0 :     return vertexArray->MakeIterator<SColor4ub>(this);
     154             : }
     155             : 
     156             : template<>
     157           6 : VertexArrayIterator<u16> VertexArray::Attribute::GetIterator<u16>() const
     158             : {
     159           6 :     ENSURE(vertexArray);
     160           6 :     ENSURE(format == Renderer::Backend::Format::R16_UINT);
     161             : 
     162           6 :     return vertexArray->MakeIterator<u16>(this);
     163             : }
     164             : 
     165             : template<>
     166           0 : VertexArrayIterator<u16[2]> VertexArray::Attribute::GetIterator<u16[2]>() const
     167             : {
     168           0 :     ENSURE(vertexArray);
     169           0 :     ENSURE(format == Renderer::Backend::Format::R16G16_UINT);
     170             : 
     171           0 :     return vertexArray->MakeIterator<u16[2]>(this);
     172             : }
     173             : 
     174             : template<>
     175           0 : VertexArrayIterator<u8> VertexArray::Attribute::GetIterator<u8>() const
     176             : {
     177           0 :     ENSURE(vertexArray);
     178           0 :     ENSURE(format == Renderer::Backend::Format::A8_UNORM);
     179             : 
     180           0 :     return vertexArray->MakeIterator<u8>(this);
     181             : }
     182             : 
     183             : template<>
     184           0 : VertexArrayIterator<u8[4]> VertexArray::Attribute::GetIterator<u8[4]>() const
     185             : {
     186           0 :     ENSURE(vertexArray);
     187           0 :     ENSURE(
     188             :         format == Renderer::Backend::Format::R8G8B8A8_UNORM ||
     189             :         format == Renderer::Backend::Format::R8G8B8A8_UINT);
     190             : 
     191           0 :     return vertexArray->MakeIterator<u8[4]>(this);
     192             : }
     193             : 
     194             : template<>
     195           0 : VertexArrayIterator<short> VertexArray::Attribute::GetIterator<short>() const
     196             : {
     197           0 :     ENSURE(vertexArray);
     198           0 :     ENSURE(format == Renderer::Backend::Format::R16_SINT);
     199             : 
     200           0 :     return vertexArray->MakeIterator<short>(this);
     201             : }
     202             : 
     203             : template<>
     204           0 : VertexArrayIterator<short[2]> VertexArray::Attribute::GetIterator<short[2]>() const
     205             : {
     206           0 :     ENSURE(vertexArray);
     207           0 :     ENSURE(format == Renderer::Backend::Format::R16G16_SINT);
     208             : 
     209           0 :     return vertexArray->MakeIterator<short[2]>(this);
     210             : }
     211             : 
     212           6 : static uint32_t RoundStride(uint32_t stride)
     213             : {
     214           6 :     if (stride <= 0)
     215           0 :         return 0;
     216           6 :     if (stride <= 4)
     217           0 :         return 4;
     218           6 :     if (stride <= 8)
     219           0 :         return 8;
     220           6 :     if (stride <= 16)
     221           0 :         return 16;
     222             : 
     223           6 :     return Align<32>(stride);
     224             : }
     225             : 
     226             : // Re-layout by assigning offsets on a first-come first-serve basis,
     227             : // then round up to a reasonable stride.
     228             : // Backing store is also created here, backend buffers are created on upload.
     229          12 : void VertexArray::Layout()
     230             : {
     231          12 :     Free();
     232             : 
     233          12 :     m_Stride = 0;
     234             : 
     235          36 :     for (ssize_t idx = m_Attributes.size()-1; idx >= 0; --idx)
     236             :     {
     237          24 :         Attribute* attr = m_Attributes[idx];
     238          24 :         if (attr->format == Renderer::Backend::Format::UNDEFINED)
     239           0 :             continue;
     240             : 
     241          24 :         const uint32_t attrSize = GetAttributeSize(attr->format);
     242          24 :         ENSURE(attrSize > 0);
     243             : 
     244          24 :         attr->offset = m_Stride;
     245             : 
     246          24 :         m_Stride += attrSize;
     247             : 
     248          24 :         if (m_Type == Renderer::Backend::IBuffer::Type::VERTEX)
     249          18 :             m_Stride = Align<4>(m_Stride);
     250             :     }
     251             : 
     252          12 :     if (m_Type == Renderer::Backend::IBuffer::Type::VERTEX)
     253           6 :         m_Stride = RoundStride(m_Stride);
     254             : 
     255          12 :     if (m_Stride)
     256          12 :         m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumberOfVertices, 16);
     257          12 : }
     258             : 
     259           0 : void VertexArray::PrepareForRendering()
     260             : {
     261           0 :     m_VB->m_Owner->PrepareForRendering(m_VB.Get());
     262           0 : }
     263             : 
     264             : // (Re-)Upload the attributes.
     265             : // Create the backend buffer if necessary.
     266           6 : void VertexArray::Upload()
     267             : {
     268           6 :     ENSURE(m_BackingStore);
     269             : 
     270           6 :     if (!m_VB)
     271             :     {
     272          18 :         m_VB = g_VBMan.AllocateChunk(
     273          18 :             m_Stride, m_NumberOfVertices, m_Type, m_Dynamic, m_BackingStore);
     274             :     }
     275             : 
     276           6 :     if (!m_VB)
     277             :     {
     278           0 :         LOGERROR("Failed to allocate backend buffer for vertex array");
     279           0 :         return;
     280             :     }
     281             : 
     282           6 :     m_VB->m_Owner->UpdateChunkVertices(m_VB.Get(), m_BackingStore);
     283             : }
     284             : 
     285           0 : void VertexArray::UploadIfNeeded(
     286             :     Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
     287             : {
     288           0 :     m_VB->m_Owner->UploadIfNeeded(deviceCommandContext);
     289           0 : }
     290             : 
     291             : // Free the backing store to save some memory
     292           6 : void VertexArray::FreeBackingStore()
     293             : {
     294             :     // In streaming modes, the backing store must be retained
     295           6 :     ENSURE(!CVertexBuffer::UseStreaming(m_Dynamic));
     296             : 
     297           6 :     rtl_FreeAligned(m_BackingStore);
     298           6 :     m_BackingStore = 0;
     299           6 : }
     300             : 
     301           6 : VertexIndexArray::VertexIndexArray(const bool dynamic) :
     302           6 :     VertexArray(Renderer::Backend::IBuffer::Type::INDEX, dynamic)
     303             : {
     304           6 :     m_Attr.format = Renderer::Backend::Format::R16_UINT;
     305           6 :     AddAttribute(&m_Attr);
     306           6 : }
     307             : 
     308           6 : VertexArrayIterator<u16> VertexIndexArray::GetIterator() const
     309             : {
     310           6 :     return m_Attr.GetIterator<u16>();
     311           3 : }

Generated by: LCOV version 1.13