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