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