1/*-------------------------------------------------------------------------
2 * drawElements Quality Program Reference Renderer
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 Vertex attribute fetch.
22 *//*--------------------------------------------------------------------*/
23
24#include "rrVertexAttrib.hpp"
25#include "tcuFloat.hpp"
26#include "deInt32.h"
27#include "deMemory.h"
28
29namespace rr
30{
31
32namespace
33{
34
35struct NormalOrder
36{
37	enum
38	{
39		T0 = 0,
40		T1 = 1,
41		T2 = 2,
42		T3 = 3,
43	};
44};
45
46struct BGRAOrder
47{
48	enum
49	{
50		T0 = 2,
51		T1 = 1,
52		T2 = 0,
53		T3 = 3,
54	};
55};
56
57// readers
58
59template<typename SrcScalarType, typename DstScalarType, typename Order>
60inline void readOrder (typename tcu::Vector<DstScalarType, 4>& dst, const int size, const void* ptr)
61{
62	SrcScalarType aligned[4];
63	deMemcpy(aligned, ptr, size * sizeof(SrcScalarType));
64
65				   dst[Order::T0] = DstScalarType(aligned[0]);
66	if (size >= 2) dst[Order::T1] = DstScalarType(aligned[1]);
67	if (size >= 3) dst[Order::T2] = DstScalarType(aligned[2]);
68	if (size >= 4) dst[Order::T3] = DstScalarType(aligned[3]);
69}
70
71template<typename SrcScalarType, typename Order>
72inline void readUnormOrder (tcu::Vec4& dst, const int size, const void* ptr)
73{
74	const deUint32 range = (deUint32)((1ull << (sizeof(SrcScalarType)*8))-1);
75
76	SrcScalarType aligned[4];
77	deMemcpy(aligned, ptr, size * sizeof(SrcScalarType));
78
79				   dst[Order::T0] = float(aligned[0]) / float(range);
80	if (size >= 2) dst[Order::T1] = float(aligned[1]) / float(range);
81	if (size >= 3) dst[Order::T2] = float(aligned[2]) / float(range);
82	if (size >= 4) dst[Order::T3] = float(aligned[3]) / float(range);
83}
84
85template<typename SrcScalarType>
86inline void readSnormClamp (tcu::Vec4& dst, const int size, const void* ptr)
87{
88	// Clamped formats, GLES3-style conversion: max{c / (2^(b-1) - 1), -1 }
89	const deUint32 range = (deUint32)((1ull << (sizeof(SrcScalarType)*8-1))-1);
90
91	SrcScalarType aligned[4];
92	deMemcpy(aligned, ptr, size * sizeof(SrcScalarType));
93
94				   dst[0] = de::max(-1.0f, float(aligned[0]) / float(range));
95	if (size >= 2) dst[1] = de::max(-1.0f, float(aligned[1]) / float(range));
96	if (size >= 3) dst[2] = de::max(-1.0f, float(aligned[2]) / float(range));
97	if (size >= 4) dst[3] = de::max(-1.0f, float(aligned[3]) / float(range));
98}
99
100template<typename SrcScalarType>
101inline void readSnormScale (tcu::Vec4& dst, const int size, const void* ptr)
102{
103	// Scaled formats, GLES2-style conversion: (2c + 1) / (2^b - 1)
104	const deUint32 range = (deUint32)((1ull << (sizeof(SrcScalarType)*8))-1);
105
106	SrcScalarType aligned[4];
107	deMemcpy(aligned, ptr, size * sizeof(SrcScalarType));
108
109				   dst[0] = (float(aligned[0]) * 2.0f + 1.0f) / float(range);
110	if (size >= 2) dst[1] = (float(aligned[1]) * 2.0f + 1.0f) / float(range);
111	if (size >= 3) dst[2] = (float(aligned[2]) * 2.0f + 1.0f) / float(range);
112	if (size >= 4) dst[3] = (float(aligned[3]) * 2.0f + 1.0f) / float(range);
113}
114
115inline void readHalf (tcu::Vec4& dst, const int size, const void* ptr)
116{
117	deUint16 aligned[4];
118	deMemcpy(aligned, ptr, size * sizeof(deUint16));
119
120				   dst[0] = tcu::Float16(aligned[0]).asFloat();
121	if (size >= 2) dst[1] = tcu::Float16(aligned[1]).asFloat();
122	if (size >= 3) dst[2] = tcu::Float16(aligned[2]).asFloat();
123	if (size >= 4) dst[3] = tcu::Float16(aligned[3]).asFloat();
124}
125
126inline void readFixed (tcu::Vec4& dst, const int size, const void* ptr)
127{
128	deInt32 aligned[4];
129	deMemcpy(aligned, ptr, size * sizeof(deInt32));
130
131				   dst[0] = float(aligned[0]) / float(1 << 16);
132	if (size >= 2) dst[1] = float(aligned[1]) / float(1 << 16);
133	if (size >= 3) dst[2] = float(aligned[2]) / float(1 << 16);
134	if (size >= 4) dst[3] = float(aligned[3]) / float(1 << 16);
135}
136
137inline void readDouble (tcu::Vec4& dst, const int size, const void* ptr)
138{
139	double aligned[4];
140	deMemcpy(aligned, ptr, size * sizeof(double));
141
142				   dst[0] = float(aligned[0]);
143	if (size >= 2) dst[1] = float(aligned[1]);
144	if (size >= 3) dst[2] = float(aligned[2]);
145	if (size >= 4) dst[3] = float(aligned[3]);
146}
147
148template <int integerLen>
149inline deInt32 extendSign (deUint32 integer)
150{
151	return deUint32(0 - deInt32((integer & (1 << (integerLen - 1))) << 1)) | integer;
152}
153
154template<typename DstScalarType>
155inline void readUint2101010Rev (typename tcu::Vector<DstScalarType, 4>& dst, const int size, const void* ptr)
156{
157	deUint32 aligned;
158	deMemcpy(&aligned, ptr, sizeof(deUint32));
159
160				   dst[0] = DstScalarType((aligned >>  0) & ((1 << 10) - 1));
161	if (size >= 2) dst[1] = DstScalarType((aligned >> 10) & ((1 << 10) - 1));
162	if (size >= 3) dst[2] = DstScalarType((aligned >> 20) & ((1 << 10) - 1));
163	if (size >= 4) dst[3] = DstScalarType((aligned >> 30) & ((1 <<  2) - 1));
164}
165
166template<typename DstScalarType>
167inline void readInt2101010Rev (typename tcu::Vector<DstScalarType, 4>& dst, const int size, const void* ptr)
168{
169	deUint32 aligned;
170	deMemcpy(&aligned, ptr, sizeof(deUint32));
171
172				   dst[0] = (DstScalarType)extendSign<10>((aligned >>  0) & ((1 << 10) - 1));
173	if (size >= 2) dst[1] = (DstScalarType)extendSign<10>((aligned >> 10) & ((1 << 10) - 1));
174	if (size >= 3) dst[2] = (DstScalarType)extendSign<10>((aligned >> 20) & ((1 << 10) - 1));
175	if (size >= 4) dst[3] = (DstScalarType)extendSign< 2>((aligned >> 30) & ((1 <<  2) - 1));
176}
177
178template<typename Order>
179inline void readUnorm2101010RevOrder (tcu::Vec4& dst, const int size, const void* ptr)
180{
181	const deUint32 range10 = (deUint32)((1ull << 10)-1);
182	const deUint32 range2 = (deUint32)((1ull <<  2)-1);
183
184	deUint32 aligned;
185	deMemcpy(&aligned, ptr, sizeof(deUint32));
186
187				   dst[Order::T0] = float((aligned >>  0) & ((1 << 10) - 1)) / float(range10);
188	if (size >= 2) dst[Order::T1] = float((aligned >> 10) & ((1 << 10) - 1)) / float(range10);
189	if (size >= 3) dst[Order::T2] = float((aligned >> 20) & ((1 << 10) - 1)) / float(range10);
190	if (size >= 4) dst[Order::T3] = float((aligned >> 30) & ((1 <<  2) - 1)) / float(range2);
191}
192
193template<typename Order>
194inline void readSnorm2101010RevClampOrder (tcu::Vec4& dst, const int size, const void* ptr)
195{
196	// Clamped formats, GLES3-style conversion: max{c / (2^(b-1) - 1), -1 }
197	const deUint32 range10 = (deUint32)((1ull << (10-1))-1);
198	const deUint32 range2  = (deUint32)((1ull << ( 2-1))-1);
199
200	deUint32 aligned;
201	deMemcpy(&aligned, ptr, sizeof(deUint32));
202
203				   dst[Order::T0] = de::max(-1.0f, float(extendSign<10>((aligned >>  0) & ((1 << 10) - 1))) / float(range10));
204	if (size >= 2) dst[Order::T1] = de::max(-1.0f, float(extendSign<10>((aligned >> 10) & ((1 << 10) - 1))) / float(range10));
205	if (size >= 3) dst[Order::T2] = de::max(-1.0f, float(extendSign<10>((aligned >> 20) & ((1 << 10) - 1))) / float(range10));
206	if (size >= 4) dst[Order::T3] = de::max(-1.0f, float(extendSign< 2>((aligned >> 30) & ((1 <<  2) - 1))) / float(range2));
207}
208
209template<typename Order>
210inline void readSnorm2101010RevScaleOrder (tcu::Vec4& dst, const int size, const void* ptr)
211{
212	// Scaled formats, GLES2-style conversion: (2c + 1) / (2^b - 1)
213	const deUint32 range10 = (deUint32)((1ull << 10)-1);
214	const deUint32 range2  = (deUint32)((1ull <<  2)-1);
215
216	deUint32 aligned;
217	deMemcpy(&aligned, ptr, sizeof(deUint32));
218
219				   dst[Order::T0] = (float(extendSign<10>((aligned >>  0) & ((1 << 10) - 1))) * 2.0f + 1.0f) / float(range10);
220	if (size >= 2) dst[Order::T1] = (float(extendSign<10>((aligned >> 10) & ((1 << 10) - 1))) * 2.0f + 1.0f) / float(range10);
221	if (size >= 3) dst[Order::T2] = (float(extendSign<10>((aligned >> 20) & ((1 << 10) - 1))) * 2.0f + 1.0f) / float(range10);
222	if (size >= 4) dst[Order::T3] = (float(extendSign< 2>((aligned >> 30) & ((1 <<  2) - 1))) * 2.0f + 1.0f) / float(range2);
223}
224
225// ordered readers
226
227template<typename SrcScalarType, typename DstScalarType>
228inline void read (typename tcu::Vector<DstScalarType, 4>& dst, const int size, const void* ptr)
229{
230	readOrder<SrcScalarType, DstScalarType, NormalOrder>(dst, size, ptr);
231}
232
233template<typename SrcScalarType>
234inline void readUnorm (tcu::Vec4& dst, const int size, const void* ptr)
235{
236	readUnormOrder<SrcScalarType, NormalOrder>(dst, size, ptr);
237}
238
239template<typename SrcScalarType>
240inline void readUnormBGRA (tcu::Vec4& dst, const int size, const void* ptr)
241{
242	readUnormOrder<SrcScalarType, BGRAOrder>(dst, size, ptr);
243}
244
245inline void readUnorm2101010Rev (tcu::Vec4& dst, const int size, const void* ptr)
246{
247	readUnorm2101010RevOrder<NormalOrder>(dst, size, ptr);
248}
249
250inline void readUnorm2101010RevBGRA (tcu::Vec4& dst, const int size, const void* ptr)
251{
252	readUnorm2101010RevOrder<BGRAOrder>(dst, size, ptr);
253}
254
255inline void readSnorm2101010RevClamp (tcu::Vec4& dst, const int size, const void* ptr)
256{
257	readSnorm2101010RevClampOrder<NormalOrder>(dst, size, ptr);
258}
259
260inline void readSnorm2101010RevClampBGRA (tcu::Vec4& dst, const int size, const void* ptr)
261{
262	readSnorm2101010RevClampOrder<BGRAOrder>(dst, size, ptr);
263}
264
265inline void readSnorm2101010RevScale (tcu::Vec4& dst, const int size, const void* ptr)
266{
267	readSnorm2101010RevScaleOrder<NormalOrder>(dst, size, ptr);
268}
269
270inline void readSnorm2101010RevScaleBGRA (tcu::Vec4& dst, const int size, const void* ptr)
271{
272	readSnorm2101010RevScaleOrder<BGRAOrder>(dst, size, ptr);
273}
274
275// utils
276
277void readFloat (tcu::Vec4& dst, const VertexAttribType type, const int size, const void* ptr)
278{
279	switch (type)
280	{
281		case VERTEXATTRIBTYPE_FLOAT:									read<float>					(dst, size, ptr);	break;
282		case VERTEXATTRIBTYPE_HALF:										readHalf					(dst, size, ptr);	break;
283		case VERTEXATTRIBTYPE_FIXED:									readFixed					(dst, size, ptr);	break;
284		case VERTEXATTRIBTYPE_DOUBLE:									readDouble					(dst, size, ptr);	break;
285		case VERTEXATTRIBTYPE_NONPURE_UNORM8:							readUnorm<deUint8>			(dst, size, ptr);	break;
286		case VERTEXATTRIBTYPE_NONPURE_UNORM16:							readUnorm<deUint16>			(dst, size, ptr);	break;
287		case VERTEXATTRIBTYPE_NONPURE_UNORM32:							readUnorm<deUint32>			(dst, size, ptr);	break;
288		case VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV:				readUnorm2101010Rev			(dst, size, ptr);	break;
289		case VERTEXATTRIBTYPE_NONPURE_SNORM8_CLAMP:						readSnormClamp<deInt8>		(dst, size, ptr);	break;
290		case VERTEXATTRIBTYPE_NONPURE_SNORM16_CLAMP:					readSnormClamp<deInt16>		(dst, size, ptr);	break;
291		case VERTEXATTRIBTYPE_NONPURE_SNORM32_CLAMP:					readSnormClamp<deInt32>		(dst, size, ptr);	break;
292		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP:		readSnorm2101010RevClamp	(dst, size, ptr);	break;
293		case VERTEXATTRIBTYPE_NONPURE_SNORM8_SCALE:						readSnormScale<deInt8>		(dst, size, ptr);	break;
294		case VERTEXATTRIBTYPE_NONPURE_SNORM16_SCALE:					readSnormScale<deInt16>		(dst, size, ptr);	break;
295		case VERTEXATTRIBTYPE_NONPURE_SNORM32_SCALE:					readSnormScale<deInt32>		(dst, size, ptr);	break;
296		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE:		readSnorm2101010RevScale	(dst, size, ptr);	break;
297		case VERTEXATTRIBTYPE_NONPURE_UINT8:							read<deUint8>				(dst, size, ptr);	break;
298		case VERTEXATTRIBTYPE_NONPURE_UINT16:							read<deUint16>				(dst, size, ptr);	break;
299		case VERTEXATTRIBTYPE_NONPURE_UINT32:							read<deUint32>				(dst, size, ptr);	break;
300		case VERTEXATTRIBTYPE_NONPURE_INT8:								read<deInt8>				(dst, size, ptr);	break;
301		case VERTEXATTRIBTYPE_NONPURE_INT16:							read<deInt16>				(dst, size, ptr);	break;
302		case VERTEXATTRIBTYPE_NONPURE_INT32:							read<deInt32>				(dst, size, ptr);	break;
303		case VERTEXATTRIBTYPE_NONPURE_UINT_2_10_10_10_REV:				readUint2101010Rev			(dst, size, ptr);	break;
304		case VERTEXATTRIBTYPE_NONPURE_INT_2_10_10_10_REV:				readInt2101010Rev			(dst, size, ptr);	break;
305		case VERTEXATTRIBTYPE_NONPURE_UNORM8_BGRA:						readUnormBGRA<deUint8>		(dst, size, ptr);	break;
306		case VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV_BGRA:		readUnorm2101010RevBGRA		(dst, size, ptr);	break;
307		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA:	readSnorm2101010RevClampBGRA(dst, size, ptr);	break;
308		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA:	readSnorm2101010RevScaleBGRA(dst, size, ptr);	break;
309
310		case VERTEXATTRIBTYPE_PURE_UINT8:
311		case VERTEXATTRIBTYPE_PURE_UINT16:
312		case VERTEXATTRIBTYPE_PURE_UINT32:
313		case VERTEXATTRIBTYPE_PURE_INT8:
314		case VERTEXATTRIBTYPE_PURE_INT16:
315		case VERTEXATTRIBTYPE_PURE_INT32:
316			DE_FATAL("Invalid read");
317
318		default:
319			DE_ASSERT(false);
320	}
321}
322
323void readInt (tcu::IVec4& dst, const VertexAttribType type, const int size, const void* ptr)
324{
325	switch (type)
326	{
327		case VERTEXATTRIBTYPE_PURE_INT8:				read<deInt8>		(dst, size, ptr);	break;
328		case VERTEXATTRIBTYPE_PURE_INT16:				read<deInt16>		(dst, size, ptr);	break;
329		case VERTEXATTRIBTYPE_PURE_INT32:				read<deInt32>		(dst, size, ptr);	break;
330
331		case VERTEXATTRIBTYPE_FLOAT:
332		case VERTEXATTRIBTYPE_HALF:
333		case VERTEXATTRIBTYPE_FIXED:
334		case VERTEXATTRIBTYPE_DOUBLE:
335		case VERTEXATTRIBTYPE_NONPURE_UNORM8:
336		case VERTEXATTRIBTYPE_NONPURE_UNORM16:
337		case VERTEXATTRIBTYPE_NONPURE_UNORM32:
338		case VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV:
339		case VERTEXATTRIBTYPE_NONPURE_SNORM8_CLAMP:
340		case VERTEXATTRIBTYPE_NONPURE_SNORM16_CLAMP:
341		case VERTEXATTRIBTYPE_NONPURE_SNORM32_CLAMP:
342		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP:
343		case VERTEXATTRIBTYPE_NONPURE_SNORM8_SCALE:
344		case VERTEXATTRIBTYPE_NONPURE_SNORM16_SCALE:
345		case VERTEXATTRIBTYPE_NONPURE_SNORM32_SCALE:
346		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE:
347		case VERTEXATTRIBTYPE_NONPURE_UINT8:
348		case VERTEXATTRIBTYPE_NONPURE_UINT16:
349		case VERTEXATTRIBTYPE_NONPURE_UINT32:
350		case VERTEXATTRIBTYPE_NONPURE_INT8:
351		case VERTEXATTRIBTYPE_NONPURE_INT16:
352		case VERTEXATTRIBTYPE_NONPURE_INT32:
353		case VERTEXATTRIBTYPE_NONPURE_UINT_2_10_10_10_REV:
354		case VERTEXATTRIBTYPE_NONPURE_INT_2_10_10_10_REV:
355		case VERTEXATTRIBTYPE_PURE_UINT8:
356		case VERTEXATTRIBTYPE_PURE_UINT16:
357		case VERTEXATTRIBTYPE_PURE_UINT32:
358		case VERTEXATTRIBTYPE_NONPURE_UNORM8_BGRA:
359		case VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV_BGRA:
360		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA:
361		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA:
362			DE_FATAL("Invalid read");
363
364		default:
365			DE_ASSERT(false);
366	}
367}
368
369void readUint (tcu::UVec4& dst, const VertexAttribType type, const int size, const void* ptr)
370{
371	switch (type)
372	{
373		case VERTEXATTRIBTYPE_PURE_UINT8:				read<deUint8>		(dst, size, ptr);	break;
374		case VERTEXATTRIBTYPE_PURE_UINT16:				read<deUint16>		(dst, size, ptr);	break;
375		case VERTEXATTRIBTYPE_PURE_UINT32:				read<deUint32>		(dst, size, ptr);	break;
376
377		case VERTEXATTRIBTYPE_FLOAT:
378		case VERTEXATTRIBTYPE_HALF:
379		case VERTEXATTRIBTYPE_FIXED:
380		case VERTEXATTRIBTYPE_DOUBLE:
381		case VERTEXATTRIBTYPE_NONPURE_UNORM8:
382		case VERTEXATTRIBTYPE_NONPURE_UNORM16:
383		case VERTEXATTRIBTYPE_NONPURE_UNORM32:
384		case VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV:
385		case VERTEXATTRIBTYPE_NONPURE_SNORM8_CLAMP:
386		case VERTEXATTRIBTYPE_NONPURE_SNORM16_CLAMP:
387		case VERTEXATTRIBTYPE_NONPURE_SNORM32_CLAMP:
388		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP:
389		case VERTEXATTRIBTYPE_NONPURE_SNORM8_SCALE:
390		case VERTEXATTRIBTYPE_NONPURE_SNORM16_SCALE:
391		case VERTEXATTRIBTYPE_NONPURE_SNORM32_SCALE:
392		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE:
393		case VERTEXATTRIBTYPE_NONPURE_UINT8:
394		case VERTEXATTRIBTYPE_NONPURE_UINT16:
395		case VERTEXATTRIBTYPE_NONPURE_UINT32:
396		case VERTEXATTRIBTYPE_NONPURE_INT8:
397		case VERTEXATTRIBTYPE_NONPURE_INT16:
398		case VERTEXATTRIBTYPE_NONPURE_INT32:
399		case VERTEXATTRIBTYPE_NONPURE_UINT_2_10_10_10_REV:
400		case VERTEXATTRIBTYPE_NONPURE_INT_2_10_10_10_REV:
401		case VERTEXATTRIBTYPE_PURE_INT8:
402		case VERTEXATTRIBTYPE_PURE_INT16:
403		case VERTEXATTRIBTYPE_PURE_INT32:
404		case VERTEXATTRIBTYPE_NONPURE_UNORM8_BGRA:
405		case VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV_BGRA:
406		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA:
407		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA:
408			DE_FATAL("Invalid read");
409
410		default:
411			DE_ASSERT(false);
412	}
413}
414
415int getComponentSize (const VertexAttribType type)
416{
417	switch (type)
418	{
419		case VERTEXATTRIBTYPE_FLOAT:									return 4;
420		case VERTEXATTRIBTYPE_HALF:										return 2;
421		case VERTEXATTRIBTYPE_FIXED:									return 4;
422		case VERTEXATTRIBTYPE_DOUBLE:									return (int)sizeof(double);
423		case VERTEXATTRIBTYPE_NONPURE_UNORM8:							return 1;
424		case VERTEXATTRIBTYPE_NONPURE_UNORM16:							return 2;
425		case VERTEXATTRIBTYPE_NONPURE_UNORM32:							return 4;
426		case VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV:				return (int)sizeof(deUint32)/4;
427		case VERTEXATTRIBTYPE_NONPURE_SNORM8_CLAMP:						return 1;
428		case VERTEXATTRIBTYPE_NONPURE_SNORM16_CLAMP:					return 2;
429		case VERTEXATTRIBTYPE_NONPURE_SNORM32_CLAMP:					return 4;
430		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP:		return (int)sizeof(deUint32)/4;
431		case VERTEXATTRIBTYPE_NONPURE_SNORM8_SCALE:						return 1;
432		case VERTEXATTRIBTYPE_NONPURE_SNORM16_SCALE:					return 2;
433		case VERTEXATTRIBTYPE_NONPURE_SNORM32_SCALE:					return 4;
434		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE:		return (int)sizeof(deUint32)/4;
435		case VERTEXATTRIBTYPE_NONPURE_UINT8:							return 1;
436		case VERTEXATTRIBTYPE_NONPURE_UINT16:							return 2;
437		case VERTEXATTRIBTYPE_NONPURE_UINT32:							return 4;
438		case VERTEXATTRIBTYPE_NONPURE_INT8:								return 1;
439		case VERTEXATTRIBTYPE_NONPURE_INT16:							return 2;
440		case VERTEXATTRIBTYPE_NONPURE_INT32:							return 4;
441		case VERTEXATTRIBTYPE_NONPURE_UINT_2_10_10_10_REV:				return (int)sizeof(deUint32)/4;
442		case VERTEXATTRIBTYPE_NONPURE_INT_2_10_10_10_REV:				return (int)sizeof(deUint32)/4;
443		case VERTEXATTRIBTYPE_PURE_UINT8:								return 1;
444		case VERTEXATTRIBTYPE_PURE_UINT16:								return 2;
445		case VERTEXATTRIBTYPE_PURE_UINT32:								return 4;
446		case VERTEXATTRIBTYPE_PURE_INT8:								return 1;
447		case VERTEXATTRIBTYPE_PURE_INT16:								return 2;
448		case VERTEXATTRIBTYPE_PURE_INT32:								return 4;
449		case VERTEXATTRIBTYPE_NONPURE_UNORM8_BGRA:						return 1;
450		case VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV_BGRA:		return (int)sizeof(deUint32)/4;
451		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA:	return (int)sizeof(deUint32)/4;
452		case VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA:	return (int)sizeof(deUint32)/4;
453		default:
454			DE_ASSERT(false);
455			return 0;
456	}
457}
458
459} // anonymous
460
461bool isValidVertexAttrib (const VertexAttrib& vertexAttrib)
462{
463	// Trivial range checks.
464	if (!de::inBounds<int>(vertexAttrib.type, 0, VERTEXATTRIBTYPE_LAST) ||
465		!de::inRange(vertexAttrib.size, 0, 4) ||
466		vertexAttrib.instanceDivisor < 0)
467		return false;
468
469	// Generic attributes
470	if (!vertexAttrib.pointer && vertexAttrib.type != VERTEXATTRIBTYPE_DONT_CARE)
471		return false;
472
473	// Packed formats
474	if ((vertexAttrib.type == VERTEXATTRIBTYPE_NONPURE_INT_2_10_10_10_REV				||
475		 vertexAttrib.type == VERTEXATTRIBTYPE_NONPURE_UINT_2_10_10_10_REV				||
476		 vertexAttrib.type == VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV				||
477		 vertexAttrib.type == VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP		||
478		 vertexAttrib.type == VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE		||
479		 vertexAttrib.type == VERTEXATTRIBTYPE_NONPURE_UNORM_2_10_10_10_REV_BGRA		||
480		 vertexAttrib.type == VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_CLAMP_BGRA	||
481		 vertexAttrib.type == VERTEXATTRIBTYPE_NONPURE_SNORM_2_10_10_10_REV_SCALE_BGRA)	&&
482		vertexAttrib.size != 4)
483		return false;
484
485	return true;
486}
487
488void readVertexAttrib (tcu::Vec4& dst, const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx)
489{
490	DE_ASSERT(isValidVertexAttrib(vertexAttrib));
491
492	if (vertexAttrib.pointer)
493	{
494		const int	elementNdx		= (vertexAttrib.instanceDivisor != 0) ? (instanceNdx / vertexAttrib.instanceDivisor) : vertexNdx;
495		const int	compSize		= getComponentSize(vertexAttrib.type);
496		const int	stride			= (vertexAttrib.stride != 0) ? (vertexAttrib.stride) : (vertexAttrib.size*compSize);
497		const int	byteOffset		= elementNdx*stride;
498
499		dst = tcu::Vec4(0, 0, 0, 1); // defaults
500		readFloat(dst, vertexAttrib.type, vertexAttrib.size, (const deUint8*)vertexAttrib.pointer + byteOffset);
501	}
502	else
503	{
504		dst = vertexAttrib.generic.get<float>();
505	}
506}
507
508void readVertexAttrib (tcu::IVec4& dst, const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx)
509{
510	DE_ASSERT(isValidVertexAttrib(vertexAttrib));
511
512	if (vertexAttrib.pointer)
513	{
514		const int	elementNdx		= (vertexAttrib.instanceDivisor != 0) ? (instanceNdx / vertexAttrib.instanceDivisor) : vertexNdx;
515		const int	compSize		= getComponentSize(vertexAttrib.type);
516		const int	stride			= (vertexAttrib.stride != 0) ? (vertexAttrib.stride) : (vertexAttrib.size*compSize);
517		const int	byteOffset		= elementNdx*stride;
518
519		dst = tcu::IVec4(0, 0, 0, 1); // defaults
520		readInt(dst, vertexAttrib.type, vertexAttrib.size, (const deUint8*)vertexAttrib.pointer + byteOffset);
521	}
522	else
523	{
524		dst = vertexAttrib.generic.get<deInt32>();
525	}
526}
527
528void readVertexAttrib (tcu::UVec4& dst, const VertexAttrib& vertexAttrib, const int instanceNdx, const int vertexNdx)
529{
530	DE_ASSERT(isValidVertexAttrib(vertexAttrib));
531
532	if (vertexAttrib.pointer)
533	{
534		const int	elementNdx		= (vertexAttrib.instanceDivisor != 0) ? (instanceNdx / vertexAttrib.instanceDivisor) : vertexNdx;
535		const int	compSize		= getComponentSize(vertexAttrib.type);
536		const int	stride			= (vertexAttrib.stride != 0) ? (vertexAttrib.stride) : (vertexAttrib.size*compSize);
537		const int	byteOffset		= elementNdx*stride;
538
539		dst = tcu::UVec4(0, 0, 0, 1); // defaults
540		readUint(dst, vertexAttrib.type, vertexAttrib.size, (const deUint8*)vertexAttrib.pointer + byteOffset);
541	}
542	else
543	{
544		dst = vertexAttrib.generic.get<deUint32>();
545	}
546}
547
548} // rr
549