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 : }
|