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