xref: /aosp_15_r20/external/deqp/framework/opengl/gluDrawUtil.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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