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