1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL Utilities
3 * ---------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Draw call utilities.
22 *//*--------------------------------------------------------------------*/
23
24 #include "gluDrawUtil.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluObjectWrapper.hpp"
27 #include "glwFunctions.hpp"
28 #include "glwEnums.hpp"
29 #include "deInt32.h"
30 #include "deMemory.h"
31
32 #include <vector>
33 #include <set>
34 #include <iterator>
35
36 namespace glu
37 {
38 namespace
39 {
40
41 struct VertexAttributeDescriptor
42 {
43 int location;
44 VertexComponentType componentType;
45 VertexComponentConversion convert;
46 int numComponents;
47 int numElements;
48 int stride; //!< Stride or 0 if using default stride.
49 const void *pointer; //!< Pointer or offset.
50
VertexAttributeDescriptorglu::__anonf067fd160111::VertexAttributeDescriptor51 VertexAttributeDescriptor(int location_, VertexComponentType componentType_, VertexComponentConversion convert_,
52 int numComponents_, int numElements_, int stride_, const void *pointer_)
53 : location(location_)
54 , componentType(componentType_)
55 , convert(convert_)
56 , numComponents(numComponents_)
57 , numElements(numElements_)
58 , stride(stride_)
59 , pointer(pointer_)
60 {
61 }
62
VertexAttributeDescriptorglu::__anonf067fd160111::VertexAttributeDescriptor63 VertexAttributeDescriptor(void)
64 : location(0)
65 , componentType(VTX_COMP_TYPE_LAST)
66 , convert(VTX_COMP_CONVERT_LAST)
67 , numComponents(0)
68 , numElements(0)
69 , stride(0)
70 , pointer(0)
71 {
72 }
73 };
74
75 struct VertexBufferLayout
76 {
77 int size;
78 std::vector<VertexAttributeDescriptor> attributes;
79
VertexBufferLayoutglu::__anonf067fd160111::VertexBufferLayout80 VertexBufferLayout(int size_ = 0) : size(size_)
81 {
82 }
83 };
84
85 struct VertexBufferDescriptor
86 {
87 uint32_t buffer;
88 std::vector<VertexAttributeDescriptor> attributes;
89
VertexBufferDescriptorglu::__anonf067fd160111::VertexBufferDescriptor90 VertexBufferDescriptor(uint32_t buffer_ = 0) : buffer(buffer_)
91 {
92 }
93 };
94
95 class VertexBuffer : public Buffer
96 {
97 public:
98 enum Type
99 {
100 TYPE_PLANAR = 0, //!< Data for each vertex array resides in a separate contiguous block in buffer.
101 TYPE_STRIDED, //!< Vertex arrays are interleaved.
102
103 TYPE_LAST
104 };
105
106 VertexBuffer(const RenderContext &context, int numBindings, const VertexArrayBinding *bindings,
107 Type type = TYPE_PLANAR);
108 ~VertexBuffer(void);
109
getDescriptor(void) const110 const VertexBufferDescriptor &getDescriptor(void) const
111 {
112 return m_layout;
113 }
114
115 private:
116 VertexBuffer(const VertexBuffer &other);
117 VertexBuffer &operator=(const VertexBuffer &other);
118
119 VertexBufferDescriptor m_layout;
120 };
121
122 class IndexBuffer : public Buffer
123 {
124 public:
125 IndexBuffer(const RenderContext &context, IndexType indexType, int numIndices, const void *indices);
126 ~IndexBuffer(void);
127
128 private:
129 IndexBuffer(const IndexBuffer &other);
130 IndexBuffer &operator=(const IndexBuffer &other);
131 };
132
getVtxCompGLType(VertexComponentType type)133 static uint32_t getVtxCompGLType(VertexComponentType type)
134 {
135 switch (type)
136 {
137 case VTX_COMP_UNSIGNED_INT8:
138 return GL_UNSIGNED_BYTE;
139 case VTX_COMP_UNSIGNED_INT16:
140 return GL_UNSIGNED_SHORT;
141 case VTX_COMP_UNSIGNED_INT32:
142 return GL_UNSIGNED_INT;
143 case VTX_COMP_SIGNED_INT8:
144 return GL_BYTE;
145 case VTX_COMP_SIGNED_INT16:
146 return GL_SHORT;
147 case VTX_COMP_SIGNED_INT32:
148 return GL_INT;
149 case VTX_COMP_FIXED:
150 return GL_FIXED;
151 case VTX_COMP_HALF_FLOAT:
152 return GL_HALF_FLOAT;
153 case VTX_COMP_FLOAT:
154 return GL_FLOAT;
155 default:
156 DE_ASSERT(false);
157 return GL_NONE;
158 }
159 }
160
getVtxCompSize(VertexComponentType type)161 static int getVtxCompSize(VertexComponentType type)
162 {
163 switch (type)
164 {
165 case VTX_COMP_UNSIGNED_INT8:
166 return 1;
167 case VTX_COMP_UNSIGNED_INT16:
168 return 2;
169 case VTX_COMP_UNSIGNED_INT32:
170 return 4;
171 case VTX_COMP_SIGNED_INT8:
172 return 1;
173 case VTX_COMP_SIGNED_INT16:
174 return 2;
175 case VTX_COMP_SIGNED_INT32:
176 return 4;
177 case VTX_COMP_FIXED:
178 return 4;
179 case VTX_COMP_HALF_FLOAT:
180 return 2;
181 case VTX_COMP_FLOAT:
182 return 4;
183 default:
184 DE_ASSERT(false);
185 return 0;
186 }
187 }
188
getIndexGLType(IndexType type)189 static uint32_t getIndexGLType(IndexType type)
190 {
191 switch (type)
192 {
193 case INDEXTYPE_UINT8:
194 return GL_UNSIGNED_BYTE;
195 case INDEXTYPE_UINT16:
196 return GL_UNSIGNED_SHORT;
197 case INDEXTYPE_UINT32:
198 return GL_UNSIGNED_INT;
199 default:
200 DE_ASSERT(false);
201 return 0;
202 }
203 }
204
getIndexSize(IndexType type)205 static int getIndexSize(IndexType type)
206 {
207 switch (type)
208 {
209 case INDEXTYPE_UINT8:
210 return 1;
211 case INDEXTYPE_UINT16:
212 return 2;
213 case INDEXTYPE_UINT32:
214 return 4;
215 default:
216 DE_ASSERT(false);
217 return 0;
218 }
219 }
220
getPrimitiveGLType(PrimitiveType type)221 static uint32_t getPrimitiveGLType(PrimitiveType type)
222 {
223 switch (type)
224 {
225 case PRIMITIVETYPE_TRIANGLES:
226 return GL_TRIANGLES;
227 case PRIMITIVETYPE_TRIANGLE_STRIP:
228 return GL_TRIANGLE_STRIP;
229 case PRIMITIVETYPE_TRIANGLE_FAN:
230 return GL_TRIANGLE_FAN;
231 case PRIMITIVETYPE_LINES:
232 return GL_LINES;
233 case PRIMITIVETYPE_LINE_STRIP:
234 return GL_LINE_STRIP;
235 case PRIMITIVETYPE_LINE_LOOP:
236 return GL_LINE_LOOP;
237 case PRIMITIVETYPE_POINTS:
238 return GL_POINTS;
239 case PRIMITIVETYPE_PATCHES:
240 return GL_PATCHES;
241 default:
242 DE_ASSERT(false);
243 return 0;
244 }
245 }
246
247 //! Lower named bindings to locations and eliminate bindings that are not used by program.
248 template <typename InputIter, typename OutputIter>
namedBindingsToProgramLocations(const glw::Functions & gl,uint32_t program,InputIter first,InputIter end,OutputIter out)249 static OutputIter namedBindingsToProgramLocations(const glw::Functions &gl, uint32_t program, InputIter first,
250 InputIter end, OutputIter out)
251 {
252 for (InputIter cur = first; cur != end; ++cur)
253 {
254 const BindingPoint &binding = cur->binding;
255 if (binding.type == BindingPoint::BPTYPE_NAME)
256 {
257 DE_ASSERT(binding.location >= 0);
258 int location = gl.getAttribLocation(program, binding.name.c_str());
259 if (location >= 0)
260 {
261 // Add binding.location as an offset to accommodate matrices.
262 *out = VertexArrayBinding(BindingPoint(location + binding.location), cur->pointer);
263 ++out;
264 }
265 }
266 else
267 {
268 *out = *cur;
269 ++out;
270 }
271 }
272
273 return out;
274 }
275
getMinimumAlignment(const VertexArrayPointer & pointer)276 static uint32_t getMinimumAlignment(const VertexArrayPointer &pointer)
277 {
278 // \todo [2013-05-07 pyry] What is the actual min?
279 DE_UNREF(pointer);
280 return (uint32_t)sizeof(float);
281 }
282
283 template <typename BindingIter>
areVertexArrayLocationsValid(BindingIter first,BindingIter end)284 static bool areVertexArrayLocationsValid(BindingIter first, BindingIter end)
285 {
286 std::set<int> usedLocations;
287 for (BindingIter cur = first; cur != end; ++cur)
288 {
289 const BindingPoint &binding = cur->binding;
290
291 if (binding.type != BindingPoint::BPTYPE_LOCATION)
292 return false;
293
294 if (usedLocations.find(binding.location) != usedLocations.end())
295 return false;
296
297 usedLocations.insert(binding.location);
298 }
299
300 return true;
301 }
302
303 // \todo [2013-05-08 pyry] Buffer upload should try to match pointers to reduce dataset size.
304
appendAttributeNonStrided(VertexBufferLayout & layout,const VertexArrayBinding & va)305 static void appendAttributeNonStrided(VertexBufferLayout &layout, const VertexArrayBinding &va)
306 {
307 const int offset = deAlign32(layout.size, getMinimumAlignment(va.pointer));
308 const int elementSize = getVtxCompSize(va.pointer.componentType) * va.pointer.numComponents;
309 const int size = elementSize * va.pointer.numElements;
310
311 // Must be assigned to location at this point.
312 DE_ASSERT(va.binding.type == BindingPoint::BPTYPE_LOCATION);
313
314 layout.attributes.push_back(VertexAttributeDescriptor(va.binding.location, va.pointer.componentType,
315 va.pointer.convert, va.pointer.numComponents,
316 va.pointer.numElements,
317 0, // default stride
318 (const void *)(uintptr_t)offset));
319 layout.size = offset + size;
320 }
321
322 template <typename BindingIter>
computeNonStridedBufferLayout(VertexBufferLayout & layout,BindingIter first,BindingIter end)323 static void computeNonStridedBufferLayout(VertexBufferLayout &layout, BindingIter first, BindingIter end)
324 {
325 for (BindingIter iter = first; iter != end; ++iter)
326 appendAttributeNonStrided(layout, *iter);
327 }
328
copyToLayout(void * dstBasePtr,const VertexAttributeDescriptor & dstVA,const VertexArrayPointer & srcPtr)329 static void copyToLayout(void *dstBasePtr, const VertexAttributeDescriptor &dstVA, const VertexArrayPointer &srcPtr)
330 {
331 DE_ASSERT(dstVA.componentType == srcPtr.componentType && dstVA.numComponents == srcPtr.numComponents &&
332 dstVA.numElements == srcPtr.numElements);
333
334 const int elementSize = getVtxCompSize(dstVA.componentType) * dstVA.numComponents;
335 const bool srcHasCustomStride = srcPtr.stride != 0 && srcPtr.stride != elementSize;
336 const bool dstHasCustomStride = dstVA.stride != 0 && dstVA.stride != elementSize;
337
338 if (srcHasCustomStride || dstHasCustomStride)
339 {
340 const int dstStride = dstVA.stride != 0 ? dstVA.stride : elementSize;
341 const int srcStride = srcPtr.stride != 0 ? srcPtr.stride : elementSize;
342
343 for (int ndx = 0; ndx < dstVA.numElements; ndx++)
344 deMemcpy((uint8_t *)dstBasePtr + (uintptr_t)dstVA.pointer + ndx * dstStride,
345 (const uint8_t *)srcPtr.data + ndx * srcStride, elementSize);
346 }
347 else
348 deMemcpy((uint8_t *)dstBasePtr + (uintptr_t)dstVA.pointer, srcPtr.data, elementSize * dstVA.numElements);
349 }
350
uploadBufferData(const glw::Functions & gl,uint32_t buffer,uint32_t usage,const VertexBufferLayout & layout,const VertexArrayPointer * srcArrays)351 void uploadBufferData(const glw::Functions &gl, uint32_t buffer, uint32_t usage, const VertexBufferLayout &layout,
352 const VertexArrayPointer *srcArrays)
353 {
354 // Create temporary data buffer for upload.
355 std::vector<uint8_t> localBuf(layout.size);
356
357 for (int attrNdx = 0; attrNdx < (int)layout.attributes.size(); ++attrNdx)
358 copyToLayout(&localBuf[0], layout.attributes[attrNdx], srcArrays[attrNdx]);
359
360 gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
361 gl.bufferData(GL_ARRAY_BUFFER, (int)localBuf.size(), &localBuf[0], usage);
362 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
363 GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading buffer data failed");
364 }
365
366 // VertexBuffer
367
VertexBuffer(const RenderContext & context,int numBindings,const VertexArrayBinding * bindings,Type type)368 VertexBuffer::VertexBuffer(const RenderContext &context, int numBindings, const VertexArrayBinding *bindings, Type type)
369 : Buffer(context)
370 {
371 const glw::Functions &gl = context.getFunctions();
372 const uint32_t usage = GL_STATIC_DRAW;
373 VertexBufferLayout layout;
374
375 if (!areVertexArrayLocationsValid(bindings, bindings + numBindings))
376 throw tcu::TestError("Invalid vertex array locations");
377
378 if (type == TYPE_PLANAR)
379 computeNonStridedBufferLayout(layout, bindings, bindings + numBindings);
380 else
381 throw tcu::InternalError("Strided layout is not yet supported");
382
383 std::vector<VertexArrayPointer> srcPtrs(numBindings);
384 for (int ndx = 0; ndx < numBindings; ndx++)
385 srcPtrs[ndx] = bindings[ndx].pointer;
386
387 DE_ASSERT(srcPtrs.size() == layout.attributes.size());
388 if (!srcPtrs.empty())
389 uploadBufferData(gl, m_object, usage, layout, &srcPtrs[0]);
390
391 // Construct descriptor.
392 m_layout.buffer = m_object;
393 m_layout.attributes = layout.attributes;
394 }
395
~VertexBuffer(void)396 VertexBuffer::~VertexBuffer(void)
397 {
398 }
399
400 // IndexBuffer
401
IndexBuffer(const RenderContext & context,IndexType indexType,int numIndices,const void * indices)402 IndexBuffer::IndexBuffer(const RenderContext &context, IndexType indexType, int numIndices, const void *indices)
403 : Buffer(context)
404 {
405 const glw::Functions &gl = context.getFunctions();
406 const uint32_t usage = GL_STATIC_DRAW;
407
408 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_object);
409 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices * getIndexSize(indexType), indices, usage);
410 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
411 GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading index data failed");
412 }
413
~IndexBuffer(void)414 IndexBuffer::~IndexBuffer(void)
415 {
416 }
417
getUserPointerDescriptor(const VertexArrayBinding & vertexArray)418 static inline VertexAttributeDescriptor getUserPointerDescriptor(const VertexArrayBinding &vertexArray)
419 {
420 DE_ASSERT(vertexArray.binding.type == BindingPoint::BPTYPE_LOCATION);
421
422 return VertexAttributeDescriptor(vertexArray.binding.location, vertexArray.pointer.componentType,
423 vertexArray.pointer.convert, vertexArray.pointer.numComponents,
424 vertexArray.pointer.numElements, vertexArray.pointer.stride,
425 vertexArray.pointer.data);
426 }
427
428 //! Setup VA according to allocation spec. Assumes that other state (VAO binding, buffer) is set already.
setVertexAttribPointer(const glw::Functions & gl,const VertexAttributeDescriptor & va)429 static void setVertexAttribPointer(const glw::Functions &gl, const VertexAttributeDescriptor &va)
430 {
431 const bool isIntType = de::inRange<int>(va.componentType, VTX_COMP_UNSIGNED_INT8, VTX_COMP_SIGNED_INT32);
432 const bool isSpecialType = de::inRange<int>(va.componentType, VTX_COMP_FIXED, VTX_COMP_FLOAT);
433 const uint32_t compTypeGL = getVtxCompGLType(va.componentType);
434
435 DE_ASSERT(isIntType != isSpecialType); // Must be either int or special type.
436 DE_ASSERT(isIntType || va.convert == VTX_COMP_CONVERT_NONE); // Conversion allowed only for special types.
437 DE_UNREF(isSpecialType);
438
439 gl.enableVertexAttribArray(va.location);
440
441 if (isIntType && va.convert == VTX_COMP_CONVERT_NONE)
442 gl.vertexAttribIPointer(va.location, va.numComponents, compTypeGL, va.stride, va.pointer);
443 else
444 gl.vertexAttribPointer(va.location, va.numComponents, compTypeGL,
445 va.convert == VTX_COMP_CONVERT_NORMALIZE_TO_FLOAT ? GL_TRUE : GL_FALSE, va.stride,
446 va.pointer);
447 }
448
449 //! Setup vertex buffer and attributes.
setVertexBufferAttributes(const glw::Functions & gl,const VertexBufferDescriptor & buffer)450 static void setVertexBufferAttributes(const glw::Functions &gl, const VertexBufferDescriptor &buffer)
451 {
452 gl.bindBuffer(GL_ARRAY_BUFFER, buffer.buffer);
453
454 for (std::vector<VertexAttributeDescriptor>::const_iterator vaIter = buffer.attributes.begin();
455 vaIter != buffer.attributes.end(); ++vaIter)
456 setVertexAttribPointer(gl, *vaIter);
457
458 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
459 }
460
disableVertexArrays(const glw::Functions & gl,const std::vector<VertexArrayBinding> & bindings)461 static void disableVertexArrays(const glw::Functions &gl, const std::vector<VertexArrayBinding> &bindings)
462 {
463 for (std::vector<VertexArrayBinding>::const_iterator vaIter = bindings.begin(); vaIter != bindings.end(); ++vaIter)
464 {
465 DE_ASSERT(vaIter->binding.type == BindingPoint::BPTYPE_LOCATION);
466 gl.disableVertexAttribArray(vaIter->binding.location);
467 }
468 }
469
470 #if defined(DE_DEBUG)
isProgramActive(const RenderContext & context,uint32_t program)471 static bool isProgramActive(const RenderContext &context, uint32_t program)
472 {
473 // \todo [2013-05-08 pyry] Is this query broken?
474 /* uint32_t activeProgram = 0;
475 context.getFunctions().getIntegerv(GL_ACTIVE_PROGRAM, (int*)&activeProgram);
476 GLU_EXPECT_NO_ERROR(context.getFunctions().getError(), "oh");
477 return activeProgram == program;*/
478 DE_UNREF(context);
479 DE_UNREF(program);
480 return true;
481 }
482
isDrawCallValid(int numVertexArrays,const VertexArrayBinding * vertexArrays,const PrimitiveList & primitives)483 static bool isDrawCallValid(int numVertexArrays, const VertexArrayBinding *vertexArrays,
484 const PrimitiveList &primitives)
485 {
486 if (numVertexArrays < 0)
487 return false;
488
489 if ((primitives.indexType == INDEXTYPE_LAST) != (primitives.indices == 0))
490 return false;
491
492 if (primitives.numElements < 0)
493 return false;
494
495 if (!primitives.indices)
496 {
497 for (int ndx = 0; ndx < numVertexArrays; ndx++)
498 {
499 if (primitives.numElements > vertexArrays[ndx].pointer.numElements)
500 return false;
501 }
502 }
503 // \todo [2013-05-08 pyry] We could walk whole index array and determine index range
504
505 return true;
506 }
507 #endif // DE_DEBUG
508
drawNonIndexed(const glw::Functions & gl,PrimitiveType type,int numElements)509 static inline void drawNonIndexed(const glw::Functions &gl, PrimitiveType type, int numElements)
510 {
511 uint32_t mode = getPrimitiveGLType(type);
512 gl.drawArrays(mode, 0, numElements);
513 }
514
drawIndexed(const glw::Functions & gl,PrimitiveType type,int numElements,IndexType indexType,const void * indexPtr)515 static inline void drawIndexed(const glw::Functions &gl, PrimitiveType type, int numElements, IndexType indexType,
516 const void *indexPtr)
517 {
518 uint32_t mode = getPrimitiveGLType(type);
519 uint32_t indexGLType = getIndexGLType(indexType);
520
521 gl.drawElements(mode, numElements, indexGLType, indexPtr);
522 }
523
524 } // namespace
525
drawFromUserPointers(const RenderContext & context,uint32_t program,int numVertexArrays,const VertexArrayBinding * vertexArrays,const PrimitiveList & primitives,DrawUtilCallback * callback)526 void drawFromUserPointers(const RenderContext &context, uint32_t program, int numVertexArrays,
527 const VertexArrayBinding *vertexArrays, const PrimitiveList &primitives,
528 DrawUtilCallback *callback)
529 {
530 const glw::Functions &gl = context.getFunctions();
531 std::vector<VertexArrayBinding> bindingsWithLocations;
532
533 DE_ASSERT(isDrawCallValid(numVertexArrays, vertexArrays, primitives));
534 DE_ASSERT(isProgramActive(context, program));
535
536 // Lower bindings to locations.
537 namedBindingsToProgramLocations(gl, program, vertexArrays, vertexArrays + numVertexArrays,
538 std::inserter(bindingsWithLocations, bindingsWithLocations.begin()));
539
540 TCU_CHECK(areVertexArrayLocationsValid(bindingsWithLocations.begin(), bindingsWithLocations.end()));
541
542 // Set VA state.
543 for (std::vector<VertexArrayBinding>::const_iterator vaIter = bindingsWithLocations.begin();
544 vaIter != bindingsWithLocations.end(); ++vaIter)
545 setVertexAttribPointer(gl, getUserPointerDescriptor(*vaIter));
546
547 if (callback)
548 callback->beforeDrawCall();
549
550 if (primitives.indices)
551 drawIndexed(gl, primitives.type, primitives.numElements, primitives.indexType, primitives.indices);
552 else
553 drawNonIndexed(gl, primitives.type, primitives.numElements);
554
555 if (callback)
556 callback->afterDrawCall();
557
558 // Disable attribute arrays or otherwise someone later on might get crash thanks to invalid pointers.
559 disableVertexArrays(gl, bindingsWithLocations);
560 }
561
drawFromBuffers(const RenderContext & context,uint32_t program,int numVertexArrays,const VertexArrayBinding * vertexArrays,const PrimitiveList & primitives,DrawUtilCallback * callback)562 void drawFromBuffers(const RenderContext &context, uint32_t program, int numVertexArrays,
563 const VertexArrayBinding *vertexArrays, const PrimitiveList &primitives,
564 DrawUtilCallback *callback)
565 {
566 const glw::Functions &gl = context.getFunctions();
567 std::vector<VertexArrayBinding> bindingsWithLocations;
568
569 DE_ASSERT(isDrawCallValid(numVertexArrays, vertexArrays, primitives));
570 DE_ASSERT(isProgramActive(context, program));
571
572 // Lower bindings to locations.
573 namedBindingsToProgramLocations(gl, program, vertexArrays, vertexArrays + numVertexArrays,
574 std::inserter(bindingsWithLocations, bindingsWithLocations.begin()));
575
576 TCU_CHECK(areVertexArrayLocationsValid(bindingsWithLocations.begin(), bindingsWithLocations.end()));
577
578 // Create buffers for duration of draw call.
579 {
580 VertexBuffer vertexBuffer(context, (int)bindingsWithLocations.size(),
581 (bindingsWithLocations.empty()) ? (DE_NULL) : (&bindingsWithLocations[0]));
582
583 // Set state.
584 setVertexBufferAttributes(gl, vertexBuffer.getDescriptor());
585
586 if (primitives.indices)
587 {
588 IndexBuffer indexBuffer(context, primitives.indexType, primitives.numElements, primitives.indices);
589
590 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
591
592 if (callback)
593 callback->beforeDrawCall();
594
595 drawIndexed(gl, primitives.type, primitives.numElements, primitives.indexType, 0);
596
597 if (callback)
598 callback->afterDrawCall();
599
600 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
601 }
602 else
603 {
604 if (callback)
605 callback->beforeDrawCall();
606
607 drawNonIndexed(gl, primitives.type, primitives.numElements);
608
609 if (callback)
610 callback->afterDrawCall();
611 }
612 }
613
614 // Disable attribute arrays or otherwise someone later on might get crash thanks to invalid pointers.
615 for (std::vector<VertexArrayBinding>::const_iterator vaIter = bindingsWithLocations.begin();
616 vaIter != bindingsWithLocations.end(); ++vaIter)
617 gl.disableVertexAttribArray(vaIter->binding.location);
618 }
619
drawFromVAOBuffers(const RenderContext & context,uint32_t program,int numVertexArrays,const VertexArrayBinding * vertexArrays,const PrimitiveList & primitives,DrawUtilCallback * callback)620 void drawFromVAOBuffers(const RenderContext &context, uint32_t program, int numVertexArrays,
621 const VertexArrayBinding *vertexArrays, const PrimitiveList &primitives,
622 DrawUtilCallback *callback)
623 {
624 const glw::Functions &gl = context.getFunctions();
625 VertexArray vao(context);
626
627 gl.bindVertexArray(*vao);
628 drawFromBuffers(context, program, numVertexArrays, vertexArrays, primitives, callback);
629 gl.bindVertexArray(0);
630 }
631
draw(const RenderContext & context,uint32_t program,int numVertexArrays,const VertexArrayBinding * vertexArrays,const PrimitiveList & primitives,DrawUtilCallback * callback)632 void draw(const RenderContext &context, uint32_t program, int numVertexArrays, const VertexArrayBinding *vertexArrays,
633 const PrimitiveList &primitives, DrawUtilCallback *callback)
634 {
635 const glu::ContextType ctxType = context.getType();
636
637 if (isContextTypeGLCore(ctxType) || contextSupports(ctxType, ApiType::es(3, 1)))
638 drawFromVAOBuffers(context, program, numVertexArrays, vertexArrays, primitives, callback);
639 else
640 {
641 DE_ASSERT(isContextTypeES(ctxType));
642 drawFromUserPointers(context, program, numVertexArrays, vertexArrays, primitives, callback);
643 }
644 }
645
646 } // namespace glu
647