1 /* Copyright (C) 2023 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #include "precompiled.h"
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"
34 uint32_t GetAttributeSize(const Renderer::Backend::Format format
)
38 case Renderer::Backend::Format::R8G8B8A8_UNORM
: FALLTHROUGH
;
39 case Renderer::Backend::Format::R8G8B8A8_UINT
:
40 return sizeof(u8
) * 4;
41 case Renderer::Backend::Format::A8_UNORM
:
43 case Renderer::Backend::Format::R16_UNORM
: FALLTHROUGH
;
44 case Renderer::Backend::Format::R16_UINT
: FALLTHROUGH
;
45 case Renderer::Backend::Format::R16_SINT
:
47 case Renderer::Backend::Format::R16G16_UNORM
: FALLTHROUGH
;
48 case Renderer::Backend::Format::R16G16_UINT
: FALLTHROUGH
;
49 case Renderer::Backend::Format::R16G16_SINT
:
50 return sizeof(u16
) * 2;
51 case Renderer::Backend::Format::R32_SFLOAT
:
53 case Renderer::Backend::Format::R32G32_SFLOAT
:
54 return sizeof(float) * 2;
55 case Renderer::Backend::Format::R32G32B32_SFLOAT
:
56 return sizeof(float) * 3;
57 case Renderer::Backend::Format::R32G32B32A32_SFLOAT
:
58 return sizeof(float) * 4;
65 } // anonymous namespace
67 VertexArray::VertexArray(
68 const Renderer::Backend::IBuffer::Type type
, const bool dynamic
)
69 : m_Type(type
), m_Dynamic(dynamic
)
71 m_NumberOfVertices
= 0;
77 VertexArray::~VertexArray()
82 // Free all resources on destruction or when a layout parameter changes
83 void VertexArray::Free()
85 rtl_FreeAligned(m_BackingStore
);
91 // Set the number of vertices stored in the array
92 void VertexArray::SetNumberOfVertices(const size_t numberOfVertices
)
94 if (numberOfVertices
== m_NumberOfVertices
)
98 m_NumberOfVertices
= numberOfVertices
;
101 // Add vertex attributes like Position, Normal, UV
102 void VertexArray::AddAttribute(Attribute
* attr
)
104 // Attribute is supported is its size is greater than zero.
105 ENSURE(GetAttributeSize(attr
->format
) > 0 && "Unsupported attribute.");
107 attr
->vertexArray
= this;
108 m_Attributes
.push_back(attr
);
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.
117 VertexArrayIterator
<CVector3D
> VertexArray::Attribute::GetIterator
<CVector3D
>() const
121 format
== Renderer::Backend::Format::R32G32B32_SFLOAT
||
122 format
== Renderer::Backend::Format::R32G32B32A32_SFLOAT
);
124 return vertexArray
->MakeIterator
<CVector3D
>(this);
128 VertexArrayIterator
<CVector4D
> VertexArray::Attribute::GetIterator
<CVector4D
>() const
131 ENSURE(format
== Renderer::Backend::Format::R32G32B32A32_SFLOAT
);
133 return vertexArray
->MakeIterator
<CVector4D
>(this);
137 VertexArrayIterator
<float[2]> VertexArray::Attribute::GetIterator
<float[2]>() const
140 ENSURE(format
== Renderer::Backend::Format::R32G32_SFLOAT
);
142 return vertexArray
->MakeIterator
<float[2]>(this);
146 VertexArrayIterator
<SColor4ub
> VertexArray::Attribute::GetIterator
<SColor4ub
>() const
150 format
== Renderer::Backend::Format::R8G8B8A8_UNORM
||
151 format
== Renderer::Backend::Format::R8G8B8A8_UINT
);
153 return vertexArray
->MakeIterator
<SColor4ub
>(this);
157 VertexArrayIterator
<u16
> VertexArray::Attribute::GetIterator
<u16
>() const
160 ENSURE(format
== Renderer::Backend::Format::R16_UINT
);
162 return vertexArray
->MakeIterator
<u16
>(this);
166 VertexArrayIterator
<u16
[2]> VertexArray::Attribute::GetIterator
<u16
[2]>() const
169 ENSURE(format
== Renderer::Backend::Format::R16G16_UINT
);
171 return vertexArray
->MakeIterator
<u16
[2]>(this);
175 VertexArrayIterator
<u8
> VertexArray::Attribute::GetIterator
<u8
>() const
178 ENSURE(format
== Renderer::Backend::Format::A8_UNORM
);
180 return vertexArray
->MakeIterator
<u8
>(this);
184 VertexArrayIterator
<u8
[4]> VertexArray::Attribute::GetIterator
<u8
[4]>() const
188 format
== Renderer::Backend::Format::R8G8B8A8_UNORM
||
189 format
== Renderer::Backend::Format::R8G8B8A8_UINT
);
191 return vertexArray
->MakeIterator
<u8
[4]>(this);
195 VertexArrayIterator
<short> VertexArray::Attribute::GetIterator
<short>() const
198 ENSURE(format
== Renderer::Backend::Format::R16_SINT
);
200 return vertexArray
->MakeIterator
<short>(this);
204 VertexArrayIterator
<short[2]> VertexArray::Attribute::GetIterator
<short[2]>() const
207 ENSURE(format
== Renderer::Backend::Format::R16G16_SINT
);
209 return vertexArray
->MakeIterator
<short[2]>(this);
212 static uint32_t RoundStride(uint32_t stride
)
223 return Align
<32>(stride
);
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 void VertexArray::Layout()
235 for (ssize_t idx
= m_Attributes
.size()-1; idx
>= 0; --idx
)
237 Attribute
* attr
= m_Attributes
[idx
];
238 if (attr
->format
== Renderer::Backend::Format::UNDEFINED
)
241 const uint32_t attrSize
= GetAttributeSize(attr
->format
);
242 ENSURE(attrSize
> 0);
244 attr
->offset
= m_Stride
;
246 m_Stride
+= attrSize
;
248 if (m_Type
== Renderer::Backend::IBuffer::Type::VERTEX
)
249 m_Stride
= Align
<4>(m_Stride
);
252 if (m_Type
== Renderer::Backend::IBuffer::Type::VERTEX
)
253 m_Stride
= RoundStride(m_Stride
);
256 m_BackingStore
= (char*)rtl_AllocateAligned(m_Stride
* m_NumberOfVertices
, 16);
259 void VertexArray::PrepareForRendering()
261 m_VB
->m_Owner
->PrepareForRendering(m_VB
.Get());
264 // (Re-)Upload the attributes.
265 // Create the backend buffer if necessary.
266 void VertexArray::Upload()
268 ENSURE(m_BackingStore
);
272 m_VB
= g_VBMan
.AllocateChunk(
273 m_Stride
, m_NumberOfVertices
, m_Type
, m_Dynamic
, m_BackingStore
);
278 LOGERROR("Failed to allocate backend buffer for vertex array");
282 m_VB
->m_Owner
->UpdateChunkVertices(m_VB
.Get(), m_BackingStore
);
285 void VertexArray::UploadIfNeeded(
286 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
)
288 m_VB
->m_Owner
->UploadIfNeeded(deviceCommandContext
);
291 // Free the backing store to save some memory
292 void VertexArray::FreeBackingStore()
294 // In streaming modes, the backing store must be retained
295 ENSURE(!CVertexBuffer::UseStreaming(m_Dynamic
));
297 rtl_FreeAligned(m_BackingStore
);
301 VertexIndexArray::VertexIndexArray(const bool dynamic
) :
302 VertexArray(Renderer::Backend::IBuffer::Type::INDEX
, dynamic
)
304 m_Attr
.format
= Renderer::Backend::Format::R16_UINT
;
305 AddAttribute(&m_Attr
);
308 VertexArrayIterator
<u16
> VertexIndexArray::GetIterator() const
310 return m_Attr
.GetIterator
<u16
>();