1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
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 Reference Texture Implementation.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuTexture.hpp"
25 #include "deInt32.h"
26 #include "deFloat16.h"
27 #include "deMath.h"
28 #include "deMemory.h"
29 #include "tcuTestLog.hpp"
30 #include "tcuSurface.hpp"
31 #include "tcuFloat.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "deStringUtil.hpp"
34 #include "deArrayUtil.hpp"
35 #include "tcuMatrix.hpp"
36
37 #include <limits>
38
39 namespace tcu
40 {
41
42 // \note No sign. Denorms are supported.
43 typedef Float<deUint32, 5, 6, 15, FLOAT_SUPPORT_DENORM> Float11;
44 typedef Float<deUint32, 5, 5, 15, FLOAT_SUPPORT_DENORM> Float10;
45
46 namespace
47 {
48
49 // Optimized getters for common formats.
50 // \todo [2012-11-14 pyry] Use intrinsics if available.
51
readRGBA8888Float(const deUint8 * ptr)52 inline Vec4 readRGBA8888Float (const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, ptr[3]/255.0f); }
readRGB888Float(const deUint8 * ptr)53 inline Vec4 readRGB888Float (const deUint8* ptr) { return Vec4(ptr[0]/255.0f, ptr[1]/255.0f, ptr[2]/255.0f, 1.0f); }
readRGBA8888Int(const deUint8 * ptr)54 inline IVec4 readRGBA8888Int (const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], ptr[3]); }
readRGB888Int(const deUint8 * ptr)55 inline IVec4 readRGB888Int (const deUint8* ptr) { return IVec4(ptr[0], ptr[1], ptr[2], 1); }
56
57 // Optimized setters.
58
writeRGBA8888Int(deUint8 * ptr,const IVec4 & val)59 inline void writeRGBA8888Int (deUint8* ptr, const IVec4& val)
60 {
61 ptr[0] = (deUint8)de::clamp(val[0], 0, 255);
62 ptr[1] = (deUint8)de::clamp(val[1], 0, 255);
63 ptr[2] = (deUint8)de::clamp(val[2], 0, 255);
64 ptr[3] = (deUint8)de::clamp(val[3], 0, 255);
65 }
66
writeRGB888Int(deUint8 * ptr,const IVec4 & val)67 inline void writeRGB888Int (deUint8* ptr, const IVec4& val)
68 {
69 ptr[0] = (deUint8)de::clamp(val[0], 0, 255);
70 ptr[1] = (deUint8)de::clamp(val[1], 0, 255);
71 ptr[2] = (deUint8)de::clamp(val[2], 0, 255);
72 }
73
writeRGBA8888Float(deUint8 * ptr,const Vec4 & val)74 inline void writeRGBA8888Float (deUint8* ptr, const Vec4& val)
75 {
76 ptr[0] = floatToU8(val[0]);
77 ptr[1] = floatToU8(val[1]);
78 ptr[2] = floatToU8(val[2]);
79 ptr[3] = floatToU8(val[3]);
80 }
81
writeRGB888Float(deUint8 * ptr,const Vec4 & val)82 inline void writeRGB888Float (deUint8* ptr, const Vec4& val)
83 {
84 ptr[0] = floatToU8(val[0]);
85 ptr[1] = floatToU8(val[1]);
86 ptr[2] = floatToU8(val[2]);
87 }
88
writeUint24(deUint8 * dst,deUint32 val)89 inline void writeUint24 (deUint8* dst, deUint32 val)
90 {
91 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
92 dst[0] = (deUint8)((val & 0x0000FFu) >> 0u);
93 dst[1] = (deUint8)((val & 0x00FF00u) >> 8u);
94 dst[2] = (deUint8)((val & 0xFF0000u) >> 16u);
95 #else
96 dst[0] = (deUint8)((val & 0xFF0000u) >> 16u);
97 dst[1] = (deUint8)((val & 0x00FF00u) >> 8u);
98 dst[2] = (deUint8)((val & 0x0000FFu) >> 0u);
99 #endif
100 }
101
readUint24(const deUint8 * src)102 inline deUint32 readUint24 (const deUint8* src)
103 {
104 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
105 return (((deUint32)src[0]) << 0u) |
106 (((deUint32)src[1]) << 8u) |
107 (((deUint32)src[2]) << 16u);
108 #else
109 return (((deUint32)src[0]) << 16u) |
110 (((deUint32)src[1]) << 8u) |
111 (((deUint32)src[2]) << 0u);
112 #endif
113 }
114
readUint32Low8(const deUint8 * src)115 inline deUint8 readUint32Low8 (const deUint8* src)
116 {
117 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
118 const deUint32 uint32ByteOffsetBits0To8 = 0; //!< least significant byte in the lowest address
119 #else
120 const deUint32 uint32ByteOffsetBits0To8 = 3; //!< least significant byte in the highest address
121 #endif
122
123 return src[uint32ByteOffsetBits0To8];
124 }
125
readUint32High8(const deUint8 * src)126 inline deUint8 readUint32High8 (const deUint8* src)
127 {
128 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
129 const deUint32 uint32ByteOffsetBits24To32 = 3;
130 #else
131 const deUint32 uint32ByteOffsetBits24To32 = 0;
132 #endif
133
134 return src[uint32ByteOffsetBits24To32];
135 }
136
writeUint32Low8(deUint8 * dst,deUint8 val)137 inline void writeUint32Low8 (deUint8* dst, deUint8 val)
138 {
139 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
140 const deUint32 uint32ByteOffsetBits0To8 = 0; //!< least significant byte in the lowest address
141 #else
142 const deUint32 uint32ByteOffsetBits0To8 = 3; //!< least significant byte in the highest address
143 #endif
144
145 dst[uint32ByteOffsetBits0To8] = val;
146 }
147
writeUint32High8(deUint8 * dst,deUint8 val)148 inline void writeUint32High8 (deUint8* dst, deUint8 val)
149 {
150 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
151 const deUint32 uint32ByteOffsetBits24To32 = 3;
152 #else
153 const deUint32 uint32ByteOffsetBits24To32 = 0;
154 #endif
155
156 dst[uint32ByteOffsetBits24To32] = val;
157 }
158
readUint32High16(const deUint8 * src)159 inline deUint32 readUint32High16 (const deUint8* src)
160 {
161 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
162 const deUint32 uint32ByteOffset16To32 = 2;
163 #else
164 const deUint32 uint32ByteOffset16To32 = 0;
165 #endif
166
167 return *(const deUint16*)(src + uint32ByteOffset16To32);
168 }
169
writeUint32High16(deUint8 * dst,deUint16 val)170 inline void writeUint32High16 (deUint8* dst, deUint16 val)
171 {
172 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
173 const deUint32 uint32ByteOffset16To32 = 2;
174 #else
175 const deUint32 uint32ByteOffset16To32 = 0;
176 #endif
177
178 *(deUint16*)(dst + uint32ByteOffset16To32) = val;
179 }
180
readUint32Low24(const deUint8 * src)181 inline deUint32 readUint32Low24 (const deUint8* src)
182 {
183 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
184 const deUint32 uint32ByteOffset0To24 = 0;
185 #else
186 const deUint32 uint32ByteOffset0To24 = 1;
187 #endif
188
189 return readUint24(src + uint32ByteOffset0To24);
190 }
191
readUint32High24(const deUint8 * src)192 inline deUint32 readUint32High24 (const deUint8* src)
193 {
194 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
195 const deUint32 uint32ByteOffset8To32 = 1;
196 #else
197 const deUint32 uint32ByteOffset8To32 = 0;
198 #endif
199
200 return readUint24(src + uint32ByteOffset8To32);
201 }
202
writeUint32Low24(deUint8 * dst,deUint32 val)203 inline void writeUint32Low24 (deUint8* dst, deUint32 val)
204 {
205 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
206 const deUint32 uint32ByteOffset0To24 = 0;
207 #else
208 const deUint32 uint32ByteOffset0To24 = 1;
209 #endif
210
211 writeUint24(dst + uint32ByteOffset0To24, val);
212 }
213
writeUint32High24(deUint8 * dst,deUint32 val)214 inline void writeUint32High24 (deUint8* dst, deUint32 val)
215 {
216 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
217 const deUint32 uint32ByteOffset8To32 = 1;
218 #else
219 const deUint32 uint32ByteOffset8To32 = 0;
220 #endif
221
222 writeUint24(dst + uint32ByteOffset8To32, val);
223 }
224
225 // \todo [2011-09-21 pyry] Move to tcutil?
226 template <typename T>
convertSatRte(float f)227 inline T convertSatRte (float f)
228 {
229 // \note Doesn't work for 64-bit types
230 DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
231 DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
232
233 deInt64 minVal = std::numeric_limits<T>::min();
234 deInt64 maxVal = std::numeric_limits<T>::max();
235 float q = deFloatFrac(f);
236 deInt64 intVal = (deInt64)(f-q);
237
238 // Rounding.
239 if (q == 0.5f)
240 {
241 if (intVal % 2 != 0)
242 intVal++;
243 }
244 else if (q > 0.5f)
245 intVal++;
246 // else Don't add anything
247
248 // Saturate.
249 intVal = de::max(minVal, de::min(maxVal, intVal));
250
251 return (T)intVal;
252 }
253
convertSatRteUint24(float f)254 inline deUint32 convertSatRteUint24 (float f)
255 {
256 const deUint32 rounded = convertSatRte<deUint32>(f);
257 const deUint32 maxUint24 = 0xFFFFFFu;
258 return de::min(rounded, maxUint24);
259 }
260
convertSatRteUint10(float f)261 inline deUint16 convertSatRteUint10 (float f)
262 {
263 const deUint16 rounded = convertSatRte<deUint16>(f);
264 const deUint16 maxUint10 = 0x3FFu;
265 return de::min(rounded, maxUint10);
266 }
267
convertSatRteUint12(float f)268 inline deUint16 convertSatRteUint12 (float f)
269 {
270 const deUint16 rounded = convertSatRte<deUint16>(f);
271 const deUint16 maxUint12 = 0xFFFu;
272 return de::min(rounded, maxUint12);
273 }
274
channelToFloat(const deUint8 * value,TextureFormat::ChannelType type)275 inline float channelToFloat (const deUint8* value, TextureFormat::ChannelType type)
276 {
277 // make sure this table is updated if format table is updated
278 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
279
280 switch (type)
281 {
282 case TextureFormat::SNORM_INT8: return de::max(-1.0f, (float)*((const deInt8*)value) / 127.0f);
283 case TextureFormat::SNORM_INT16: return de::max(-1.0f, (float)*((const deInt16*)value) / 32767.0f);
284 case TextureFormat::SNORM_INT32: return de::max(-1.0f, (float)*((const deInt32*)value) / 2147483647.0f);
285 case TextureFormat::UNORM_INT8: return (float)*((const deUint8*)value) / 255.0f;
286 case TextureFormat::UNORM_INT16: return (float)*((const deUint16*)value) / 65535.0f;
287 case TextureFormat::UNORM_INT24: return (float)readUint24(value) / 16777215.0f;
288 case TextureFormat::UNORM_INT32: return (float)*((const deUint32*)value) / 4294967295.0f;
289 case TextureFormat::SIGNED_INT8: return (float)*((const deInt8*)value);
290 case TextureFormat::SIGNED_INT16: return (float)*((const deInt16*)value);
291 case TextureFormat::SIGNED_INT32: return (float)*((const deInt32*)value);
292 case TextureFormat::SIGNED_INT64: return (float)*((const deInt64*)value);
293 case TextureFormat::UNSIGNED_INT8: return (float)*((const deUint8*)value);
294 case TextureFormat::UNSIGNED_INT16: return (float)*((const deUint16*)value);
295 case TextureFormat::UNSIGNED_INT24: return (float)readUint24(value);
296 case TextureFormat::UNSIGNED_INT32: return (float)*((const deUint32*)value);
297 case TextureFormat::UNSIGNED_INT64: return (float)*((const deUint64*)value);
298 case TextureFormat::HALF_FLOAT: return deFloat16To32(*(const deFloat16*)value);
299 case TextureFormat::FLOAT: return *((const float*)value);
300 case TextureFormat::FLOAT64: return (float)*((const double*)value);
301 case TextureFormat::UNORM_SHORT_10: return (float)((*((const deUint16*)value)) >> 6u) / 1023.0f;
302 case TextureFormat::UNORM_SHORT_12: return (float)((*((const deUint16*)value)) >> 4u) / 4095.0f;
303 case TextureFormat::USCALED_INT8: return (float)*((const deUint8*)value);
304 case TextureFormat::USCALED_INT16: return (float)*((const deUint16*)value);
305 case TextureFormat::SSCALED_INT8: return (float)*((const deInt8*)value);
306 case TextureFormat::SSCALED_INT16: return (float)*((const deInt16*)value);
307 default:
308 DE_ASSERT(DE_FALSE);
309 return 0.0f;
310 }
311 }
312
channelToInt(const deUint8 * value,TextureFormat::ChannelType type)313 inline int channelToInt (const deUint8* value, TextureFormat::ChannelType type)
314 {
315 // make sure this table is updated if format table is updated
316 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
317
318 switch (type)
319 {
320 case TextureFormat::SNORM_INT8: return (int)*((const deInt8*)value);
321 case TextureFormat::SNORM_INT16: return (int)*((const deInt16*)value);
322 case TextureFormat::SNORM_INT32: return (int)*((const deInt32*)value);
323 case TextureFormat::UNORM_INT8: return (int)*((const deUint8*)value);
324 case TextureFormat::UNORM_INT16: return (int)*((const deUint16*)value);
325 case TextureFormat::UNORM_INT24: return (int)readUint24(value);
326 case TextureFormat::UNORM_INT32: return (int)*((const deUint32*)value);
327 case TextureFormat::SIGNED_INT8: return (int)*((const deInt8*)value);
328 case TextureFormat::SIGNED_INT16: return (int)*((const deInt16*)value);
329 case TextureFormat::SIGNED_INT32: return (int)*((const deInt32*)value);
330 case TextureFormat::SIGNED_INT64: return (int)*((const deInt64*)value);
331 case TextureFormat::UNSIGNED_INT8: return (int)*((const deUint8*)value);
332 case TextureFormat::UNSIGNED_INT16: return (int)*((const deUint16*)value);
333 case TextureFormat::UNSIGNED_INT24: return (int)readUint24(value);
334 case TextureFormat::UNSIGNED_INT32: return (int)*((const deUint32*)value);
335 case TextureFormat::UNSIGNED_INT64: return (int)*((const deUint64*)value);
336 case TextureFormat::HALF_FLOAT: return (int)deFloat16To32(*(const deFloat16*)value);
337 case TextureFormat::FLOAT: return (int)*((const float*)value);
338 case TextureFormat::FLOAT64: return (int)*((const double*)value);
339 case TextureFormat::UNORM_SHORT_10: return (int)((*(((const deUint16*)value))) >> 6u);
340 case TextureFormat::UNORM_SHORT_12: return (int)((*(((const deUint16*)value))) >> 4u);
341 case TextureFormat::USCALED_INT8: return (int)*((const deUint8*)value);
342 case TextureFormat::USCALED_INT16: return (int)*((const deUint16*)value);
343 case TextureFormat::SSCALED_INT8: return (int)*((const deInt8*)value);
344 case TextureFormat::SSCALED_INT16: return (int)*((const deInt16*)value);
345 default:
346 DE_ASSERT(DE_FALSE);
347 return 0;
348 }
349 }
350
floatToChannel(deUint8 * dst,float src,TextureFormat::ChannelType type)351 void floatToChannel (deUint8* dst, float src, TextureFormat::ChannelType type)
352 {
353 // make sure this table is updated if format table is updated
354 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
355
356 switch (type)
357 {
358 case TextureFormat::SNORM_INT8: *((deInt8*)dst) = convertSatRte<deInt8> (src * 127.0f); break;
359 case TextureFormat::SNORM_INT16: *((deInt16*)dst) = convertSatRte<deInt16> (src * 32767.0f); break;
360 case TextureFormat::SNORM_INT32: *((deInt32*)dst) = convertSatRte<deInt32> (src * 2147483647.0f); break;
361 case TextureFormat::UNORM_INT8: *((deUint8*)dst) = convertSatRte<deUint8> (src * 255.0f); break;
362 case TextureFormat::UNORM_INT16: *((deUint16*)dst) = convertSatRte<deUint16> (src * 65535.0f); break;
363 case TextureFormat::UNORM_INT24: writeUint24(dst, convertSatRteUint24 (src * 16777215.0f)); break;
364 case TextureFormat::UNORM_INT32: *((deUint32*)dst) = convertSatRte<deUint32> (src * 4294967295.0f); break;
365 case TextureFormat::SIGNED_INT8: *((deInt8*)dst) = convertSatRte<deInt8> (src); break;
366 case TextureFormat::SIGNED_INT16: *((deInt16*)dst) = convertSatRte<deInt16> (src); break;
367 case TextureFormat::SIGNED_INT32: *((deInt32*)dst) = convertSatRte<deInt32> (src); break;
368 case TextureFormat::UNSIGNED_INT8: *((deUint8*)dst) = convertSatRte<deUint8> (src); break;
369 case TextureFormat::UNSIGNED_INT16: *((deUint16*)dst) = convertSatRte<deUint16> (src); break;
370 case TextureFormat::UNSIGNED_INT24: writeUint24(dst, convertSatRteUint24 (src)); break;
371 case TextureFormat::UNSIGNED_INT32: *((deUint32*)dst) = convertSatRte<deUint32> (src); break;
372 case TextureFormat::HALF_FLOAT: *((deFloat16*)dst) = deFloat32To16 (src); break;
373 case TextureFormat::FLOAT: *((float*)dst) = src; break;
374 case TextureFormat::FLOAT64: *((double*)dst) = (double)src; break;
375 case TextureFormat::UNORM_SHORT_10: *((deUint16*)dst) = (deUint16)(convertSatRteUint10(src * 1023.0f) << 6u); break;
376 case TextureFormat::UNORM_SHORT_12: *((deUint16*)dst) = (deUint16)(convertSatRteUint12(src * 4095.0f) << 4u); break;
377 case TextureFormat::USCALED_INT8: *((deUint8*)dst) = convertSatRte<deUint8> (src); break;
378 case TextureFormat::USCALED_INT16: *((deUint16*)dst) = convertSatRte<deUint16> (src); break;
379 case TextureFormat::SSCALED_INT8: *((deInt8*)dst) = convertSatRte<deInt8> (src); break;
380 case TextureFormat::SSCALED_INT16: *((deInt16*)dst) = convertSatRte<deInt16> (src); break;
381 default:
382 DE_ASSERT(DE_FALSE);
383 }
384 }
385
386 template <typename T, typename S>
convertSat(S src)387 static inline T convertSat (S src)
388 {
389 S min = (S)std::numeric_limits<T>::min();
390 S max = (S)std::numeric_limits<T>::max();
391
392 if (src < min)
393 return (T)min;
394 else if (src > max)
395 return (T)max;
396 else
397 return (T)src;
398 }
399
400 template <typename S>
convertSatUint24(S src)401 static inline deUint32 convertSatUint24 (S src)
402 {
403 S min = (S)0u;
404 S max = (S)0xFFFFFFu;
405
406 if (src < min)
407 return (deUint32)min;
408 else if (src > max)
409 return (deUint32)max;
410 else
411 return (deUint32)src;
412 }
413
414 template <typename S>
convertSatUint10(S src)415 static inline deUint16 convertSatUint10 (S src)
416 {
417 S min = (S)0u;
418 S max = (S)0x3FFu;
419
420 if (src < min)
421 return (deUint16)min;
422 else if (src > max)
423 return (deUint16)max;
424 else
425 return (deUint16)src;
426 }
427
428 template <typename S>
convertSatUint12(S src)429 static inline deUint16 convertSatUint12 (S src)
430 {
431 S min = (S)0u;
432 S max = (S)0xFFFu;
433
434 if (src < min)
435 return (deUint16)min;
436 else if (src > max)
437 return (deUint16)max;
438 else
439 return (deUint16)src;
440 }
441
intToChannel(deUint8 * dst,int src,TextureFormat::ChannelType type)442 void intToChannel (deUint8* dst, int src, TextureFormat::ChannelType type)
443 {
444 // make sure this table is updated if format table is updated
445 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
446
447 switch (type)
448 {
449 case TextureFormat::SNORM_INT8: *((deInt8*)dst) = convertSat<deInt8> (src); break;
450 case TextureFormat::SNORM_INT16: *((deInt16*)dst) = convertSat<deInt16> (src); break;
451 case TextureFormat::UNORM_INT8: *((deUint8*)dst) = convertSat<deUint8> (src); break;
452 case TextureFormat::UNORM_INT16: *((deUint16*)dst) = convertSat<deUint16> (src); break;
453 case TextureFormat::UNORM_INT24: writeUint24(dst, convertSatUint24 (src)); break;
454 case TextureFormat::SIGNED_INT8: *((deInt8*)dst) = convertSat<deInt8> (src); break;
455 case TextureFormat::SIGNED_INT16: *((deInt16*)dst) = convertSat<deInt16> (src); break;
456 case TextureFormat::SIGNED_INT32: *((deInt32*)dst) = convertSat<deInt32> (src); break;
457 case TextureFormat::SIGNED_INT64: *((deInt64*)dst) = convertSat<deInt64> ((deInt64)src); break;
458 case TextureFormat::UNSIGNED_INT8: *((deUint8*)dst) = convertSat<deUint8> ((deUint32)src); break;
459 case TextureFormat::UNSIGNED_INT16: *((deUint16*)dst) = convertSat<deUint16> ((deUint32)src); break;
460 case TextureFormat::UNSIGNED_INT24: writeUint24(dst, convertSatUint24 ((deUint32)src)); break;
461 case TextureFormat::UNSIGNED_INT32: *((deUint32*)dst) = convertSat<deUint32> ((deUint32)src); break;
462 case TextureFormat::UNSIGNED_INT64: *((deUint64*)dst) = convertSat<deUint64> ((deUint64)src); break;
463 case TextureFormat::HALF_FLOAT: *((deFloat16*)dst) = deFloat32To16((float)src); break;
464 case TextureFormat::FLOAT: *((float*)dst) = (float)src; break;
465 case TextureFormat::FLOAT64: *((double*)dst) = (double)src; break;
466 case TextureFormat::UNORM_SHORT_10: *((deUint16*)dst) = (deUint16)(convertSatUint10(src) << 6u); break;
467 case TextureFormat::UNORM_SHORT_12: *((deUint16*)dst) = (deUint16)(convertSatUint12(src) << 4u); break;
468 case TextureFormat::USCALED_INT8: *((deUint8*)dst) = convertSat<deUint8> ((deUint32)src); break;
469 case TextureFormat::USCALED_INT16: *((deUint16*)dst) = convertSat<deUint16> ((deUint32)src); break;
470 case TextureFormat::SSCALED_INT8: *((deInt8*)dst) = convertSat<deInt8> (src); break;
471 case TextureFormat::SSCALED_INT16: *((deInt16*)dst) = convertSat<deInt16> (src); break;
472 default:
473 DE_ASSERT(DE_FALSE);
474 }
475 }
476
channelToUnormFloat(deUint32 src,int bits)477 inline float channelToUnormFloat (deUint32 src, int bits)
478 {
479 const deUint32 maxVal = (1u << bits) - 1;
480
481 // \note Will lose precision if bits > 23
482 return (float)src / (float)maxVal;
483 }
484
485 //! Extend < 32b signed integer to 32b
signExtend(deUint32 src,int bits)486 inline deInt32 signExtend (deUint32 src, int bits)
487 {
488 const deUint32 signBit = 1u << (bits-1);
489
490 src |= ~((src & signBit) - 1);
491
492 return (deInt32)src;
493 }
494
channelToSnormFloat(deUint32 src,int bits)495 inline float channelToSnormFloat (deUint32 src, int bits)
496 {
497 const deUint32 range = (1u << (bits-1)) - 1;
498
499 // \note Will lose precision if bits > 24
500 return de::max(-1.0f, (float)signExtend(src, bits) / (float)range);
501 }
502
unormFloatToChannel(float src,int bits)503 inline deUint32 unormFloatToChannel (float src, int bits)
504 {
505 const deUint32 maxVal = (1u << bits) - 1;
506 const deUint32 intVal = convertSatRte<deUint32>(src * (float)maxVal);
507
508 return de::min(intVal, maxVal);
509 }
510
snormFloatToChannel(float src,int bits)511 inline deUint32 snormFloatToChannel (float src, int bits)
512 {
513 const deInt32 range = (deInt32)((1u << (bits-1)) - 1u);
514 const deUint32 mask = (1u << bits) - 1;
515 const deInt32 intVal = convertSatRte<deInt32>(src * (float)range);
516
517 return (deUint32)de::clamp(intVal, -range, range) & mask;
518 }
519
uintToChannel(deUint32 src,int bits)520 inline deUint32 uintToChannel (deUint32 src, int bits)
521 {
522 const deUint32 maxVal = (1u << bits) - 1;
523 return de::min(src, maxVal);
524 }
525
intToChannel(deInt32 src,int bits)526 inline deUint32 intToChannel (deInt32 src, int bits)
527 {
528 const deInt32 minVal = -(deInt32)(1u << (bits-1));
529 const deInt32 maxVal = (deInt32)((1u << (bits-1)) - 1u);
530 const deUint32 mask = (1u << bits) - 1;
531
532 return (deUint32)de::clamp(src, minVal, maxVal) & mask;
533 }
534
unpackRGB999E5(deUint32 color)535 tcu::Vec4 unpackRGB999E5 (deUint32 color)
536 {
537 const int mBits = 9;
538 const int eBias = 15;
539
540 deUint32 exp = color >> 27;
541 deUint32 bs = (color >> 18) & ((1<<9)-1);
542 deUint32 gs = (color >> 9) & ((1<<9)-1);
543 deUint32 rs = color & ((1<<9)-1);
544
545 float e = deFloatPow(2.0f, (float)((int)exp - eBias - mBits));
546 float r = (float)rs * e;
547 float g = (float)gs * e;
548 float b = (float)bs * e;
549
550 return tcu::Vec4(r, g, b, 1.0f);
551 }
552
isColorOrder(TextureFormat::ChannelOrder order)553 bool isColorOrder (TextureFormat::ChannelOrder order)
554 {
555 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
556
557 switch (order)
558 {
559 case TextureFormat::R:
560 case TextureFormat::A:
561 case TextureFormat::I:
562 case TextureFormat::L:
563 case TextureFormat::LA:
564 case TextureFormat::RG:
565 case TextureFormat::RA:
566 case TextureFormat::RGB:
567 case TextureFormat::RGBA:
568 case TextureFormat::ARGB:
569 case TextureFormat::ABGR:
570 case TextureFormat::BGR:
571 case TextureFormat::BGRA:
572 case TextureFormat::sR:
573 case TextureFormat::sRG:
574 case TextureFormat::sRGB:
575 case TextureFormat::sRGBA:
576 case TextureFormat::sBGR:
577 case TextureFormat::sBGRA:
578 return true;
579
580 default:
581 return false;
582 }
583 }
584
585 } // anonymous
586
isValid(TextureFormat format)587 bool isValid (TextureFormat format)
588 {
589 const bool isColor = isColorOrder(format.order);
590
591 switch (format.type)
592 {
593 case TextureFormat::SNORM_INT8:
594 case TextureFormat::SNORM_INT16:
595 case TextureFormat::SNORM_INT32:
596 return isColor;
597
598 case TextureFormat::UNORM_INT8:
599 case TextureFormat::UNORM_INT16:
600 case TextureFormat::UNORM_INT24:
601 case TextureFormat::UNORM_INT32:
602 return isColor || format.order == TextureFormat::D;
603
604 case TextureFormat::UNORM_BYTE_44:
605 case TextureFormat::UNSIGNED_BYTE_44:
606 return format.order == TextureFormat::RG;
607
608 case TextureFormat::UNORM_SHORT_565:
609 case TextureFormat::UNORM_SHORT_555:
610 case TextureFormat::UNSIGNED_SHORT_565:
611 return format.order == TextureFormat::RGB || format.order == TextureFormat::BGR;
612
613 case TextureFormat::UNORM_SHORT_4444:
614 case TextureFormat::UNORM_SHORT_5551:
615 case TextureFormat::UNSIGNED_SHORT_4444:
616 case TextureFormat::UNSIGNED_SHORT_5551:
617 return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA
618 || format.order == TextureFormat::ARGB || format.order == TextureFormat::ABGR;
619
620 case TextureFormat::UNORM_SHORT_1555:
621 return format.order == TextureFormat::ARGB;
622
623 case TextureFormat::UNORM_INT_101010:
624 return format.order == TextureFormat::RGB;
625
626 case TextureFormat::SNORM_INT_1010102_REV:
627 case TextureFormat::UNORM_INT_1010102_REV:
628 case TextureFormat::SIGNED_INT_1010102_REV:
629 case TextureFormat::UNSIGNED_INT_1010102_REV:
630 case TextureFormat::USCALED_INT_1010102_REV:
631 case TextureFormat::SSCALED_INT_1010102_REV:
632 return format.order == TextureFormat::RGBA || format.order == TextureFormat::BGRA;
633
634 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
635 case TextureFormat::UNSIGNED_INT_999_E5_REV:
636 return format.order == TextureFormat::RGB;
637
638 case TextureFormat::UNSIGNED_INT_16_8_8:
639 return format.order == TextureFormat::DS;
640
641 case TextureFormat::UNSIGNED_INT_24_8:
642 case TextureFormat::UNSIGNED_INT_24_8_REV:
643 return format.order == TextureFormat::D || format.order == TextureFormat::DS;
644
645 case TextureFormat::SIGNED_INT8:
646 case TextureFormat::SIGNED_INT16:
647 case TextureFormat::SIGNED_INT32:
648 case TextureFormat::SSCALED_INT8:
649 case TextureFormat::SSCALED_INT16:
650 case TextureFormat::SIGNED_INT64:
651 return isColor;
652
653 case TextureFormat::UNSIGNED_INT8:
654 case TextureFormat::UNSIGNED_INT16:
655 case TextureFormat::UNSIGNED_INT24:
656 case TextureFormat::UNSIGNED_INT32:
657 case TextureFormat::USCALED_INT8:
658 case TextureFormat::USCALED_INT16:
659 case TextureFormat::UNSIGNED_INT64:
660 return isColor || format.order == TextureFormat::S;
661
662 case TextureFormat::HALF_FLOAT:
663 case TextureFormat::FLOAT:
664 case TextureFormat::FLOAT64:
665 return isColor || format.order == TextureFormat::D;
666
667 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
668 return format.order == TextureFormat::DS;
669
670 case TextureFormat::UNORM_SHORT_10:
671 case TextureFormat::UNORM_SHORT_12:
672 return isColor;
673
674 default:
675 DE_FATAL("Unknown format");
676 return 0u;
677 }
678
679 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
680 }
681
getNumUsedChannels(TextureFormat::ChannelOrder order)682 int getNumUsedChannels (TextureFormat::ChannelOrder order)
683 {
684 // make sure this table is updated if type table is updated
685 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
686
687 switch (order)
688 {
689 case TextureFormat::R: return 1;
690 case TextureFormat::A: return 1;
691 case TextureFormat::I: return 1;
692 case TextureFormat::L: return 1;
693 case TextureFormat::LA: return 2;
694 case TextureFormat::RG: return 2;
695 case TextureFormat::RA: return 2;
696 case TextureFormat::RGB: return 3;
697 case TextureFormat::RGBA: return 4;
698 case TextureFormat::ARGB: return 4;
699 case TextureFormat::ABGR: return 4;
700 case TextureFormat::BGR: return 3;
701 case TextureFormat::BGRA: return 4;
702 case TextureFormat::sR: return 1;
703 case TextureFormat::sRG: return 2;
704 case TextureFormat::sRGB: return 3;
705 case TextureFormat::sRGBA: return 4;
706 case TextureFormat::sBGR: return 3;
707 case TextureFormat::sBGRA: return 4;
708 case TextureFormat::D: return 1;
709 case TextureFormat::S: return 1;
710 case TextureFormat::DS: return 2;
711 default:
712 DE_ASSERT(DE_FALSE);
713 return 0;
714 }
715 }
716
getChannelSize(TextureFormat::ChannelType type)717 int getChannelSize (TextureFormat::ChannelType type)
718 {
719 // make sure this table is updated if format table is updated
720 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
721
722 switch (type)
723 {
724 case TextureFormat::SNORM_INT8: return 1;
725 case TextureFormat::SNORM_INT16: return 2;
726 case TextureFormat::SNORM_INT32: return 4;
727 case TextureFormat::UNORM_INT8: return 1;
728 case TextureFormat::UNORM_INT16: return 2;
729 case TextureFormat::UNORM_INT24: return 3;
730 case TextureFormat::UNORM_INT32: return 4;
731 case TextureFormat::SIGNED_INT8: return 1;
732 case TextureFormat::SIGNED_INT16: return 2;
733 case TextureFormat::SIGNED_INT32: return 4;
734 case TextureFormat::SIGNED_INT64: return 8;
735 case TextureFormat::UNSIGNED_INT8: return 1;
736 case TextureFormat::UNSIGNED_INT16: return 2;
737 case TextureFormat::UNSIGNED_INT24: return 3;
738 case TextureFormat::UNSIGNED_INT32: return 4;
739 case TextureFormat::UNSIGNED_INT64: return 8;
740 case TextureFormat::HALF_FLOAT: return 2;
741 case TextureFormat::FLOAT: return 4;
742 case TextureFormat::FLOAT64: return 8;
743 case TextureFormat::UNORM_SHORT_10: return 2;
744 case TextureFormat::UNORM_SHORT_12: return 2;
745 case TextureFormat::USCALED_INT8: return 1;
746 case TextureFormat::USCALED_INT16: return 2;
747 case TextureFormat::SSCALED_INT8: return 1;
748 case TextureFormat::SSCALED_INT16: return 2;
749 default:
750 DE_ASSERT(DE_FALSE);
751 return 0;
752 }
753 }
754
755 /** Get pixel size in bytes. */
getPixelSize(TextureFormat format)756 int getPixelSize (TextureFormat format)
757 {
758 const TextureFormat::ChannelOrder order = format.order;
759 const TextureFormat::ChannelType type = format.type;
760
761 DE_ASSERT(isValid(format));
762
763 // make sure this table is updated if format table is updated
764 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
765
766 switch (type)
767 {
768 case TextureFormat::UNORM_BYTE_44:
769 case TextureFormat::UNSIGNED_BYTE_44:
770 return 1;
771
772 case TextureFormat::UNORM_SHORT_565:
773 case TextureFormat::UNORM_SHORT_555:
774 case TextureFormat::UNORM_SHORT_4444:
775 case TextureFormat::UNORM_SHORT_5551:
776 case TextureFormat::UNORM_SHORT_1555:
777 case TextureFormat::UNSIGNED_SHORT_565:
778 case TextureFormat::UNSIGNED_SHORT_4444:
779 case TextureFormat::UNSIGNED_SHORT_5551:
780 return 2;
781
782 case TextureFormat::UNORM_INT_101010:
783 case TextureFormat::UNSIGNED_INT_999_E5_REV:
784 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
785 case TextureFormat::SNORM_INT_1010102_REV:
786 case TextureFormat::UNORM_INT_1010102_REV:
787 case TextureFormat::SIGNED_INT_1010102_REV:
788 case TextureFormat::UNSIGNED_INT_1010102_REV:
789 case TextureFormat::UNSIGNED_INT_24_8:
790 case TextureFormat::UNSIGNED_INT_24_8_REV:
791 case TextureFormat::UNSIGNED_INT_16_8_8:
792 case TextureFormat::USCALED_INT_1010102_REV:
793 case TextureFormat::SSCALED_INT_1010102_REV:
794 return 4;
795
796 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
797 return 8;
798
799 default:
800 return getNumUsedChannels(order) * getChannelSize(type);
801 }
802 }
803
getPixelSize(void) const804 int TextureFormat::getPixelSize (void) const
805 {
806 return ::tcu::getPixelSize(*this);
807 }
808
getChannelReadSwizzle(TextureFormat::ChannelOrder order)809 const TextureSwizzle& getChannelReadSwizzle (TextureFormat::ChannelOrder order)
810 {
811 // make sure to update these tables when channel orders are updated
812 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
813
814 static const TextureSwizzle INV = {{ TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
815 static const TextureSwizzle R = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
816 static const TextureSwizzle A = {{ TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_0 }};
817 static const TextureSwizzle I = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0 }};
818 static const TextureSwizzle L = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ONE }};
819 static const TextureSwizzle LA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1 }};
820 static const TextureSwizzle RG = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
821 static const TextureSwizzle RA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_1 }};
822 static const TextureSwizzle RGB = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_ONE }};
823 static const TextureSwizzle RGBA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3 }};
824 static const TextureSwizzle BGR = {{ TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ONE }};
825 static const TextureSwizzle BGRA = {{ TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3 }};
826 static const TextureSwizzle ARGB = {{ TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_0 }};
827 static const TextureSwizzle ABGR = {{ TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0 }};
828 static const TextureSwizzle D = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
829 static const TextureSwizzle S = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
830
831 switch (order)
832 {
833 case TextureFormat::R: return R;
834 case TextureFormat::A: return A;
835 case TextureFormat::I: return I;
836 case TextureFormat::L: return L;
837 case TextureFormat::LA: return LA;
838 case TextureFormat::RG: return RG;
839 case TextureFormat::RA: return RA;
840 case TextureFormat::RGB: return RGB;
841 case TextureFormat::RGBA: return RGBA;
842 case TextureFormat::ARGB: return ARGB;
843 case TextureFormat::ABGR: return ABGR;
844 case TextureFormat::BGR: return BGR;
845 case TextureFormat::BGRA: return BGRA;
846 case TextureFormat::sR: return R;
847 case TextureFormat::sRG: return RG;
848 case TextureFormat::sRGB: return RGB;
849 case TextureFormat::sRGBA: return RGBA;
850 case TextureFormat::sBGR: return BGR;
851 case TextureFormat::sBGRA: return BGRA;
852 case TextureFormat::D: return D;
853 case TextureFormat::S: return S;
854
855 case TextureFormat::DS:
856 DE_ASSERT(false); // combined formats cannot be read from
857 return INV;
858
859 default:
860 DE_ASSERT(DE_FALSE);
861 return INV;
862 }
863 }
864
getChannelWriteSwizzle(TextureFormat::ChannelOrder order)865 const TextureSwizzle& getChannelWriteSwizzle (TextureFormat::ChannelOrder order)
866 {
867 // make sure to update these tables when channel orders are updated
868 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 22);
869
870 static const TextureSwizzle INV = {{ TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
871 static const TextureSwizzle R = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
872 static const TextureSwizzle A = {{ TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
873 static const TextureSwizzle I = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
874 static const TextureSwizzle L = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
875 static const TextureSwizzle LA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
876 static const TextureSwizzle RG = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
877 static const TextureSwizzle RA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
878 static const TextureSwizzle RGB = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_LAST }};
879 static const TextureSwizzle RGBA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3 }};
880 static const TextureSwizzle BGR = {{ TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST }};
881 static const TextureSwizzle BGRA = {{ TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3 }};
882 static const TextureSwizzle ARGB = {{ TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2 }};
883 static const TextureSwizzle ABGR = {{ TextureSwizzle::CHANNEL_3, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_0 }};
884 static const TextureSwizzle D = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
885 static const TextureSwizzle S = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST, TextureSwizzle::CHANNEL_LAST }};
886
887 switch (order)
888 {
889 case TextureFormat::R: return R;
890 case TextureFormat::A: return A;
891 case TextureFormat::I: return I;
892 case TextureFormat::L: return L;
893 case TextureFormat::LA: return LA;
894 case TextureFormat::RG: return RG;
895 case TextureFormat::RA: return RA;
896 case TextureFormat::RGB: return RGB;
897 case TextureFormat::RGBA: return RGBA;
898 case TextureFormat::ARGB: return ARGB;
899 case TextureFormat::ABGR: return ABGR;
900 case TextureFormat::BGR: return BGR;
901 case TextureFormat::BGRA: return BGRA;
902 case TextureFormat::sR: return R;
903 case TextureFormat::sRG: return RG;
904 case TextureFormat::sRGB: return RGB;
905 case TextureFormat::sRGBA: return RGBA;
906 case TextureFormat::sBGR: return BGR;
907 case TextureFormat::sBGRA: return BGRA;
908 case TextureFormat::D: return D;
909 case TextureFormat::S: return S;
910
911 case TextureFormat::DS:
912 DE_ASSERT(false); // combined formats cannot be written to
913 return INV;
914
915 default:
916 DE_ASSERT(DE_FALSE);
917 return INV;
918 }
919 }
920
calculatePackedPitch(const TextureFormat & format,const IVec3 & size)921 IVec3 calculatePackedPitch (const TextureFormat& format, const IVec3& size)
922 {
923 const int pixelSize = format.getPixelSize();
924 const int rowPitch = pixelSize * size.x();
925 const int slicePitch = rowPitch * size.y();
926
927 return IVec3(pixelSize, rowPitch, slicePitch);
928 }
929
ConstPixelBufferAccess(void)930 ConstPixelBufferAccess::ConstPixelBufferAccess (void)
931 : m_size (0)
932 , m_pitch (0)
933 , m_divider (1,1,1)
934 , m_data (DE_NULL)
935 {
936 }
937
ConstPixelBufferAccess(const TextureFormat & format,int width,int height,int depth,const void * data)938 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, const void* data)
939 : m_format (format)
940 , m_size (width, height, depth)
941 , m_pitch (calculatePackedPitch(m_format, m_size))
942 , m_divider (1,1,1)
943 , m_data ((void*)data)
944 {
945 DE_ASSERT(isValid(format));
946 }
947
ConstPixelBufferAccess(const TextureFormat & format,const IVec3 & size,const void * data)948 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, const IVec3& size, const void* data)
949 : m_format (format)
950 , m_size (size)
951 , m_pitch (calculatePackedPitch(m_format, m_size))
952 , m_divider (1,1,1)
953 , m_data ((void*)data)
954 {
955 DE_ASSERT(isValid(format));
956 }
957
ConstPixelBufferAccess(const TextureFormat & format,int width,int height,int depth,int rowPitch,int slicePitch,const void * data)958 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, const void* data)
959 : m_format (format)
960 , m_size (width, height, depth)
961 , m_pitch (format.getPixelSize(), rowPitch, slicePitch)
962 , m_divider (1,1,1)
963 , m_data ((void*)data)
964 {
965 DE_ASSERT(isValid(format));
966 }
967
ConstPixelBufferAccess(const TextureFormat & format,const IVec3 & size,const IVec3 & pitch,const void * data)968 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, const void* data)
969 : m_format (format)
970 , m_size (size)
971 , m_pitch (pitch)
972 , m_divider (1,1,1)
973 , m_data ((void*)data)
974 {
975 DE_ASSERT(isValid(format));
976 DE_ASSERT(m_format.getPixelSize() <= m_pitch.x());
977 }
978
ConstPixelBufferAccess(const TextureFormat & format,const IVec3 & size,const IVec3 & pitch,const IVec3 & block,const void * data)979 ConstPixelBufferAccess::ConstPixelBufferAccess(const TextureFormat& format, const IVec3& size, const IVec3& pitch, const IVec3& block, const void* data)
980 : m_format (format)
981 , m_size (size)
982 , m_pitch (pitch)
983 , m_divider (block)
984 , m_data ((void*)data)
985 {
986 DE_ASSERT(isValid(format));
987 DE_ASSERT(m_format.getPixelSize() <= m_pitch.x());
988 }
989
ConstPixelBufferAccess(const TextureLevel & level)990 ConstPixelBufferAccess::ConstPixelBufferAccess (const TextureLevel& level)
991 : m_format (level.getFormat())
992 , m_size (level.getSize())
993 , m_pitch (calculatePackedPitch(m_format, m_size))
994 , m_divider (1,1,1)
995 , m_data ((void*)level.getPtr())
996 {
997 }
998
PixelBufferAccess(const TextureFormat & format,int width,int height,int depth,void * data)999 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, void* data)
1000 : ConstPixelBufferAccess(format, width, height, depth, data)
1001 {
1002 }
1003
PixelBufferAccess(const TextureFormat & format,const IVec3 & size,void * data)1004 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, void* data)
1005 : ConstPixelBufferAccess(format, size, data)
1006 {
1007 }
1008
PixelBufferAccess(const TextureFormat & format,int width,int height,int depth,int rowPitch,int slicePitch,void * data)1009 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, int width, int height, int depth, int rowPitch, int slicePitch, void* data)
1010 : ConstPixelBufferAccess(format, width, height, depth, rowPitch, slicePitch, data)
1011 {
1012 }
1013
PixelBufferAccess(const TextureFormat & format,const IVec3 & size,const IVec3 & pitch,void * data)1014 PixelBufferAccess::PixelBufferAccess (const TextureFormat& format, const IVec3& size, const IVec3& pitch, void* data)
1015 : ConstPixelBufferAccess(format, size, pitch, data)
1016 {
1017 }
1018
PixelBufferAccess(const TextureFormat & format,const IVec3 & size,const IVec3 & pitch,const IVec3 & block,void * data)1019 PixelBufferAccess::PixelBufferAccess(const TextureFormat& format, const IVec3& size, const IVec3& pitch, const IVec3& block, void* data)
1020 : ConstPixelBufferAccess(format, size, pitch, block, data)
1021 {
1022 }
1023
1024
PixelBufferAccess(TextureLevel & level)1025 PixelBufferAccess::PixelBufferAccess (TextureLevel& level)
1026 : ConstPixelBufferAccess(level)
1027 {
1028 }
1029
1030 //! Swizzle generally based on channel order.
1031 template<typename T>
swizzleGe(const Vector<T,4> & v,TextureFormat::ChannelOrder src,TextureFormat::ChannelOrder dst)1032 Vector<T, 4> swizzleGe (const Vector<T, 4>& v, TextureFormat::ChannelOrder src, TextureFormat::ChannelOrder dst)
1033 {
1034 if (src == dst)
1035 return v;
1036 else
1037 {
1038 if ((src == TextureFormat::RGBA && dst == TextureFormat::ARGB) ||
1039 (src == TextureFormat::BGRA && dst == TextureFormat::ABGR))
1040 return v.swizzle(3, 0, 1, 2);
1041
1042 if ((src == TextureFormat::ARGB && dst == TextureFormat::RGBA) ||
1043 (src == TextureFormat::ABGR && dst == TextureFormat::BGRA))
1044 return v.swizzle(1, 2, 3, 0);
1045
1046 if ((src == TextureFormat::BGRA && dst == TextureFormat::ARGB) ||
1047 (src == TextureFormat::ABGR && dst == TextureFormat::RGBA) ||
1048 (src == TextureFormat::RGBA && dst == TextureFormat::ABGR) ||
1049 (src == TextureFormat::ARGB && dst == TextureFormat::BGRA))
1050 return v.swizzle(3, 2, 1, 0);
1051
1052 if ((src == TextureFormat::RGB && dst == TextureFormat::BGR) ||
1053 (src == TextureFormat::BGR && dst == TextureFormat::RGB) ||
1054 (src == TextureFormat::RGBA && dst == TextureFormat::BGRA) ||
1055 (src == TextureFormat::BGRA && dst == TextureFormat::RGBA))
1056 return v.swizzle(2,1,0,3);
1057
1058 DE_ASSERT(false);
1059 return v;
1060 }
1061 }
1062
getPixel(int x,int y,int z) const1063 Vec4 ConstPixelBufferAccess::getPixel (int x, int y, int z) const
1064 {
1065 DE_ASSERT(de::inBounds(x, 0, m_size.x()));
1066 DE_ASSERT(de::inBounds(y, 0, m_size.y()));
1067 DE_ASSERT(de::inBounds(z, 0, m_size.z()));
1068 DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1069 DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1070
1071 const deUint8* pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1072
1073 // Optimized fomats.
1074 if (m_format.type == TextureFormat::UNORM_INT8)
1075 {
1076 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1077 return readRGBA8888Float(pixelPtr);
1078 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1079 return readRGB888Float(pixelPtr);
1080 }
1081
1082 #define UI8(OFFS, COUNT) ((*((const deUint8*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1083 #define UI16(OFFS, COUNT) ((*((const deUint16*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1084 #define UI32(OFFS, COUNT) ((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1085 #define SI32(OFFS, COUNT) signExtend(UI32(OFFS, COUNT), (COUNT))
1086 #define UN8(OFFS, COUNT) channelToUnormFloat(UI8 (OFFS, COUNT), (COUNT))
1087 #define UN16(OFFS, COUNT) channelToUnormFloat(UI16(OFFS, COUNT), (COUNT))
1088 #define UN32(OFFS, COUNT) channelToUnormFloat(UI32(OFFS, COUNT), (COUNT))
1089 #define SN32(OFFS, COUNT) channelToSnormFloat(UI32(OFFS, COUNT), (COUNT))
1090
1091 // Packed formats.
1092 switch (m_format.type)
1093 {
1094 case TextureFormat::UNORM_BYTE_44: return Vec4(UN8 (4, 4), UN8 ( 0, 4), 0.0f, 1.0f);
1095 case TextureFormat::UNSIGNED_BYTE_44: return UVec4(UI8 (4, 4), UI8 ( 0, 4), 0u, 1u).cast<float>();
1096 case TextureFormat::UNORM_SHORT_565: return swizzleGe( Vec4(UN16(11, 5), UN16( 5, 6), UN16( 0, 5), 1.0f), m_format.order, TextureFormat::RGB);
1097 case TextureFormat::UNSIGNED_SHORT_565: return swizzleGe(UVec4(UI16(11, 5), UI16( 5, 6), UI16( 0, 5), 1u), m_format.order, TextureFormat::RGB).cast<float>();
1098 case TextureFormat::UNORM_SHORT_555: return swizzleGe( Vec4(UN16(10, 5), UN16( 5, 5), UN16( 0, 5), 1.0f), m_format.order, TextureFormat::RGB);
1099 case TextureFormat::UNORM_SHORT_4444: return swizzleGe( Vec4(UN16(12, 4), UN16( 8, 4), UN16( 4, 4), UN16( 0, 4)), m_format.order, TextureFormat::RGBA);
1100 case TextureFormat::UNSIGNED_SHORT_4444: return swizzleGe(UVec4(UI16(12, 4), UI16( 8, 4), UI16( 4, 4), UI16( 0, 4)), m_format.order, TextureFormat::RGBA).cast<float>();
1101 case TextureFormat::UNORM_SHORT_5551: return swizzleGe( Vec4(UN16(11, 5), UN16( 6, 5), UN16( 1, 5), UN16( 0, 1)), m_format.order, TextureFormat::RGBA);
1102 case TextureFormat::UNSIGNED_SHORT_5551: return swizzleGe(UVec4(UI16(11, 5), UI16( 6, 5), UI16( 1, 5), UI16( 0, 1)), m_format.order, TextureFormat::RGBA).cast<float>();
1103 case TextureFormat::UNORM_INT_101010: return Vec4(UN32(22, 10), UN32(12, 10), UN32( 2, 10), 1.0f);
1104 case TextureFormat::UNORM_INT_1010102_REV: return swizzleGe( Vec4(UN32( 0, 10), UN32(10, 10), UN32(20, 10), UN32(30, 2)), m_format.order, TextureFormat::RGBA);
1105 case TextureFormat::SNORM_INT_1010102_REV: return swizzleGe( Vec4(SN32( 0, 10), SN32(10, 10), SN32(20, 10), SN32(30, 2)), m_format.order, TextureFormat::RGBA);
1106 case TextureFormat::USCALED_INT_1010102_REV:
1107 case TextureFormat::UNSIGNED_INT_1010102_REV: return swizzleGe( UVec4(UI32(0, 10), UI32(10, 10), UI32(20, 10), UI32(30, 2)), m_format.order, TextureFormat::RGBA).cast<float>();
1108 case TextureFormat::SSCALED_INT_1010102_REV:
1109 case TextureFormat::SIGNED_INT_1010102_REV: return swizzleGe( UVec4(SI32(0, 10), SI32(10, 10), SI32(20, 10), SI32(30, 2)), m_format.order, TextureFormat::RGBA).cast<float>();
1110 case TextureFormat::UNSIGNED_INT_999_E5_REV: return unpackRGB999E5(*((const deUint32*)pixelPtr));
1111
1112 case TextureFormat::UNORM_SHORT_1555:
1113 DE_ASSERT(m_format.order == TextureFormat::ARGB);
1114 return Vec4(UN16(15, 1), UN16(10, 5), UN16(5, 5), UN16(0, 5)).swizzle(1,2,3,0); // ARGB -> RGBA
1115
1116 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
1117 return Vec4(Float11(UI32(0, 11)).asFloat(), Float11(UI32(11, 11)).asFloat(), Float10(UI32(22, 10)).asFloat(), 1.0f);
1118
1119 default:
1120 break;
1121 }
1122
1123 #undef UN8
1124 #undef UN16
1125 #undef UN32
1126 #undef SN32
1127 #undef SI32
1128 #undef UI8
1129 #undef UI16
1130 #undef UI32
1131
1132 // Generic path.
1133 Vec4 result;
1134 const TextureSwizzle::Channel* channelMap = getChannelReadSwizzle(m_format.order).components;
1135 int channelSize = getChannelSize(m_format.type);
1136
1137 for (int c = 0; c < 4; c++)
1138 {
1139 switch (channelMap[c])
1140 {
1141 case TextureSwizzle::CHANNEL_0:
1142 case TextureSwizzle::CHANNEL_1:
1143 case TextureSwizzle::CHANNEL_2:
1144 case TextureSwizzle::CHANNEL_3:
1145 result[c] = channelToFloat(pixelPtr + channelSize*((int)channelMap[c]), m_format.type);
1146 break;
1147
1148 case TextureSwizzle::CHANNEL_ZERO:
1149 result[c] = 0.0f;
1150 break;
1151
1152 case TextureSwizzle::CHANNEL_ONE:
1153 result[c] = 1.0f;
1154 break;
1155
1156 default:
1157 DE_ASSERT(false);
1158 }
1159 }
1160
1161 return result;
1162 }
1163
getPixelInt(int x,int y,int z) const1164 IVec4 ConstPixelBufferAccess::getPixelInt (int x, int y, int z) const
1165 {
1166 DE_ASSERT(de::inBounds(x, 0, m_size.x()));
1167 DE_ASSERT(de::inBounds(y, 0, m_size.y()));
1168 DE_ASSERT(de::inBounds(z, 0, m_size.z()));
1169 DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1170 DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1171
1172 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1173 IVec4 result;
1174
1175 // Optimized fomats.
1176 if (m_format.type == TextureFormat::UNORM_INT8)
1177 {
1178 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1179 return readRGBA8888Int(pixelPtr);
1180 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1181 return readRGB888Int(pixelPtr);
1182 }
1183
1184 #define U8(OFFS, COUNT) ((*((const deUint8* )pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1185 #define U16(OFFS, COUNT) ((*((const deUint16*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1186 #define U32(OFFS, COUNT) ((*((const deUint32*)pixelPtr) >> (OFFS)) & ((1<<(COUNT))-1))
1187 #define S32(OFFS, COUNT) signExtend(U32(OFFS, COUNT), (COUNT))
1188
1189 switch (m_format.type)
1190 {
1191 case TextureFormat::UNSIGNED_BYTE_44: // Fall-through
1192 case TextureFormat::UNORM_BYTE_44: return UVec4(U8 ( 4, 4), U8 ( 0, 4), 0u, 1u).cast<int>();
1193 case TextureFormat::UNSIGNED_SHORT_565: // Fall-through
1194 case TextureFormat::UNORM_SHORT_565: return swizzleGe(UVec4(U16(11, 5), U16( 5, 6), U16( 0, 5), 1).cast<int>(), m_format.order, TextureFormat::RGB);
1195 case TextureFormat::UNORM_SHORT_555: return swizzleGe(UVec4(U16(10, 5), U16( 5, 5), U16( 0, 5), 1).cast<int>(), m_format.order, TextureFormat::RGB);
1196 case TextureFormat::UNSIGNED_SHORT_4444: // Fall-through
1197 case TextureFormat::UNORM_SHORT_4444: return swizzleGe(UVec4(U16(12, 4), U16( 8, 4), U16( 4, 4), U16( 0, 4)).cast<int>(), m_format.order, TextureFormat::RGBA);
1198 case TextureFormat::UNSIGNED_SHORT_5551: // Fall-through
1199 case TextureFormat::UNORM_SHORT_5551: return swizzleGe(UVec4(U16(11, 5), U16( 6, 5), U16( 1, 5), U16( 0, 1)).cast<int>(), m_format.order, TextureFormat::RGBA);
1200 case TextureFormat::UNORM_INT_101010: return UVec4(U32(22, 10), U32(12, 10), U32( 2, 10), 1).cast<int>();
1201 case TextureFormat::UNORM_INT_1010102_REV: // Fall-through
1202 case TextureFormat::USCALED_INT_1010102_REV: // Fall-through
1203 case TextureFormat::UNSIGNED_INT_1010102_REV: return swizzleGe(UVec4(U32( 0, 10), U32(10, 10), U32(20, 10), U32(30, 2)), m_format.order, TextureFormat::RGBA).cast<int>();
1204 case TextureFormat::SNORM_INT_1010102_REV: // Fall-through
1205 case TextureFormat::SSCALED_INT_1010102_REV: // Fall-through
1206 case TextureFormat::SIGNED_INT_1010102_REV: return swizzleGe(IVec4(S32( 0, 10), S32(10, 10), S32(20, 10), S32(30, 2)), m_format.order, TextureFormat::RGBA);
1207
1208 case TextureFormat::UNORM_SHORT_1555:
1209 DE_ASSERT(m_format.order == TextureFormat::ARGB);
1210 return UVec4(U16(15, 1), U16(10, 5), U16(5, 5), U16(0, 5)).cast<int>().swizzle(1,2,3,0); // ARGB -> RGBA
1211
1212 default:
1213 break; // To generic path.
1214 }
1215
1216 #undef U8
1217 #undef U16
1218 #undef U32
1219 #undef S32
1220
1221 // Generic path.
1222 const TextureSwizzle::Channel* channelMap = getChannelReadSwizzle(m_format.order).components;
1223 int channelSize = getChannelSize(m_format.type);
1224
1225 for (int c = 0; c < 4; c++)
1226 {
1227 switch (channelMap[c])
1228 {
1229 case TextureSwizzle::CHANNEL_0:
1230 case TextureSwizzle::CHANNEL_1:
1231 case TextureSwizzle::CHANNEL_2:
1232 case TextureSwizzle::CHANNEL_3:
1233 result[c] = channelToInt(pixelPtr + channelSize*((int)channelMap[c]), m_format.type);
1234 break;
1235
1236 case TextureSwizzle::CHANNEL_ZERO:
1237 result[c] = 0;
1238 break;
1239
1240 case TextureSwizzle::CHANNEL_ONE:
1241 result[c] = 1;
1242 break;
1243
1244 default:
1245 DE_ASSERT(false);
1246 }
1247 }
1248
1249 return result;
1250 }
1251
1252 template<>
getPixelT(int x,int y,int z) const1253 Vec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1254 {
1255 return getPixel(x, y, z);
1256 }
1257
1258 template<>
getPixelT(int x,int y,int z) const1259 IVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1260 {
1261 return getPixelInt(x, y, z);
1262 }
1263
1264 template<>
getPixelT(int x,int y,int z) const1265 UVec4 ConstPixelBufferAccess::getPixelT (int x, int y, int z) const
1266 {
1267 return getPixelUint(x, y, z);
1268 }
1269
getPixDepth(int x,int y,int z) const1270 float ConstPixelBufferAccess::getPixDepth (int x, int y, int z) const
1271 {
1272 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1273 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1274 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1275
1276 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1277
1278 switch (m_format.type)
1279 {
1280 case TextureFormat::UNSIGNED_INT_16_8_8:
1281 DE_ASSERT(m_format.order == TextureFormat::DS);
1282 return (float)readUint32High16(pixelPtr) / 65535.0f;
1283
1284 case TextureFormat::UNSIGNED_INT_24_8:
1285 DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1286 return (float)readUint32High24(pixelPtr) / 16777215.0f;
1287
1288 case TextureFormat::UNSIGNED_INT_24_8_REV:
1289 DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1290 return (float)readUint32Low24(pixelPtr) / 16777215.0f;
1291
1292 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1293 DE_ASSERT(m_format.order == TextureFormat::DS);
1294 return *((const float*)pixelPtr);
1295
1296 default:
1297 DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
1298 return channelToFloat(pixelPtr, m_format.type);
1299 }
1300 }
1301
getPixStencil(int x,int y,int z) const1302 int ConstPixelBufferAccess::getPixStencil (int x, int y, int z) const
1303 {
1304 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1305 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1306 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1307
1308 const deUint8* const pixelPtr = (const deUint8*)getPixelPtr(x, y, z);
1309
1310 switch (m_format.type)
1311 {
1312 case TextureFormat::UNSIGNED_INT_24_8_REV:
1313 DE_ASSERT(m_format.order == TextureFormat::DS);
1314 return (int)readUint32High8(pixelPtr);
1315
1316 case TextureFormat::UNSIGNED_INT_16_8_8:
1317 case TextureFormat::UNSIGNED_INT_24_8:
1318 DE_ASSERT(m_format.order == TextureFormat::DS);
1319 return (int)readUint32Low8(pixelPtr);
1320
1321 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1322 DE_ASSERT(m_format.order == TextureFormat::DS);
1323 return (int)readUint32Low8(pixelPtr + 4);
1324
1325 default:
1326 {
1327 DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
1328 return channelToInt(pixelPtr, m_format.type);
1329 }
1330 }
1331 }
1332
setPixel(const Vec4 & color,int x,int y,int z) const1333 void PixelBufferAccess::setPixel (const Vec4& color, int x, int y, int z) const
1334 {
1335 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1336 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1337 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1338 DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1339 DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1340
1341 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1342
1343 // Optimized fomats.
1344 if (m_format.type == TextureFormat::UNORM_INT8)
1345 {
1346 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1347 {
1348 writeRGBA8888Float(pixelPtr, color);
1349 return;
1350 }
1351 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1352 {
1353 writeRGB888Float(pixelPtr, color);
1354 return;
1355 }
1356 }
1357
1358 #define PN(VAL, OFFS, BITS) (unormFloatToChannel((VAL), (BITS)) << (OFFS))
1359 #define PS(VAL, OFFS, BITS) (snormFloatToChannel((VAL), (BITS)) << (OFFS))
1360 #define PU(VAL, OFFS, BITS) (uintToChannel((VAL), (BITS)) << (OFFS))
1361 #define PI(VAL, OFFS, BITS) (intToChannel((VAL), (BITS)) << (OFFS))
1362
1363 switch (m_format.type)
1364 {
1365 case TextureFormat::UNORM_BYTE_44: *((deUint8 *)pixelPtr) = (deUint8)(PN(color[0], 4, 4) | PN(color[1], 0, 4)); break;
1366 case TextureFormat::UNSIGNED_BYTE_44: *((deUint8 *)pixelPtr) = (deUint8)(PU((deUint32)color[0], 4, 4) | PU((deUint32)color[1], 0, 4)); break;
1367 case TextureFormat::UNORM_INT_101010: *((deUint32*)pixelPtr) = PN(color[0], 22, 10) | PN(color[1], 12, 10) | PN(color[2], 2, 10); break;
1368
1369 case TextureFormat::UNORM_SHORT_565:
1370 {
1371 const Vec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
1372 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 11, 5) | PN(swizzled[1], 5, 6) | PN(swizzled[2], 0, 5));
1373 break;
1374 }
1375
1376 case TextureFormat::UNSIGNED_SHORT_565:
1377 {
1378 const UVec4 swizzled = swizzleGe(color.cast<deUint32>(), TextureFormat::RGB, m_format.order);
1379 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 5, 6) | PU(swizzled[2], 0, 5));
1380 break;
1381 }
1382
1383 case TextureFormat::UNORM_SHORT_555:
1384 {
1385 const Vec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
1386 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 10, 5) | PN(swizzled[1], 5, 5) | PN(swizzled[2], 0, 5));
1387 break;
1388 }
1389
1390 case TextureFormat::UNORM_SHORT_4444:
1391 {
1392 const Vec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1393 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 12, 4) | PN(swizzled[1], 8, 4) | PN(swizzled[2], 4, 4) | PN(swizzled[3], 0, 4));
1394 break;
1395 }
1396
1397 case TextureFormat::UNSIGNED_SHORT_4444:
1398 {
1399 const UVec4 swizzled = swizzleGe(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1400 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 12, 4) | PU(swizzled[1], 8, 4) | PU(swizzled[2], 4, 4) | PU(swizzled[3], 0, 4));
1401 break;
1402 }
1403
1404 case TextureFormat::UNORM_SHORT_5551:
1405 {
1406 const Vec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1407 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 11, 5) | PN(swizzled[1], 6, 5) | PN(swizzled[2], 1, 5) | PN(swizzled[3], 0, 1));
1408 break;
1409 }
1410
1411 case TextureFormat::UNORM_SHORT_1555:
1412 {
1413 const Vec4 swizzled = color.swizzle(3,0,1,2); // RGBA -> ARGB
1414 *((deUint16*)pixelPtr) = (deUint16)(PN(swizzled[0], 15, 1) | PN(swizzled[1], 10, 5) | PN(swizzled[2], 5, 5) | PN(swizzled[3], 0, 5));
1415 break;
1416 }
1417
1418 case TextureFormat::UNSIGNED_SHORT_5551:
1419 {
1420 const UVec4 swizzled = swizzleGe(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1421 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 6, 5) | PU(swizzled[2], 1, 5) | PU(swizzled[3], 0, 1));
1422 break;
1423 }
1424
1425 case TextureFormat::UNORM_INT_1010102_REV:
1426 {
1427 const Vec4 u = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1428 *((deUint32*)pixelPtr) = PN(u[0], 0, 10) | PN(u[1], 10, 10) | PN(u[2], 20, 10) | PN(u[3], 30, 2);
1429 break;
1430 }
1431
1432 case TextureFormat::SNORM_INT_1010102_REV:
1433 {
1434 const Vec4 u = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1435 *((deUint32*)pixelPtr) = PS(u[0], 0, 10) | PS(u[1], 10, 10) | PS(u[2], 20, 10) | PS(u[3], 30, 2);
1436 break;
1437 }
1438
1439 case TextureFormat::UNSIGNED_INT_1010102_REV:
1440 case TextureFormat::USCALED_INT_1010102_REV:
1441 {
1442 const UVec4 u = swizzleGe(color.cast<deUint32>(), TextureFormat::RGBA, m_format.order);
1443 *((deUint32*)pixelPtr) = PU(u[0], 0, 10) | PU(u[1], 10, 10) | PU(u[2], 20, 10) | PU(u[3], 30, 2);
1444 break;
1445 }
1446
1447 case TextureFormat::SIGNED_INT_1010102_REV:
1448 case TextureFormat::SSCALED_INT_1010102_REV:
1449 {
1450 const IVec4 u = swizzleGe(color.cast<deInt32>(), TextureFormat::RGBA, m_format.order);
1451 *((deUint32*)pixelPtr) = PI(u[0], 0, 10) | PI(u[1], 10, 10) | PI(u[2], 20, 10) | PI(u[3], 30, 2);
1452 break;
1453 }
1454
1455 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
1456 *((deUint32*)pixelPtr) = Float11(color[0]).bits() | (Float11(color[1]).bits() << 11) | (Float10(color[2]).bits() << 22);
1457 break;
1458
1459 case TextureFormat::UNSIGNED_INT_999_E5_REV:
1460 *((deUint32*)pixelPtr) = packRGB999E5(color);
1461 break;
1462
1463 default:
1464 {
1465 // Generic path.
1466 int numChannels = getNumUsedChannels(m_format.order);
1467 const TextureSwizzle::Channel* map = getChannelWriteSwizzle(m_format.order).components;
1468 int channelSize = getChannelSize(m_format.type);
1469
1470 for (int c = 0; c < numChannels; c++)
1471 {
1472 DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
1473 floatToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
1474 }
1475 break;
1476 }
1477 }
1478
1479 #undef PN
1480 #undef PS
1481 #undef PU
1482 #undef PI
1483 }
1484
setPixel(const IVec4 & color,int x,int y,int z) const1485 void PixelBufferAccess::setPixel (const IVec4& color, int x, int y, int z) const
1486 {
1487 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1488 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1489 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1490 DE_ASSERT(!isCombinedDepthStencilType(m_format.type)); // combined types cannot be accessed directly
1491 DE_ASSERT(m_format.order != TextureFormat::DS); // combined formats cannot be accessed directly
1492
1493 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1494
1495 // Optimized fomats.
1496 if (m_format.type == TextureFormat::UNORM_INT8)
1497 {
1498 if (m_format.order == TextureFormat::RGBA || m_format.order == TextureFormat::sRGBA)
1499 {
1500 writeRGBA8888Int(pixelPtr, color);
1501 return;
1502 }
1503 else if (m_format.order == TextureFormat::RGB || m_format.order == TextureFormat::sRGB)
1504 {
1505 writeRGB888Int(pixelPtr, color);
1506 return;
1507 }
1508 }
1509
1510 #define PU(VAL, OFFS, BITS) (uintToChannel((deUint32)(VAL), (BITS)) << (OFFS))
1511 #define PI(VAL, OFFS, BITS) (intToChannel((deUint32)(VAL), (BITS)) << (OFFS))
1512
1513 switch (m_format.type)
1514 {
1515 case TextureFormat::UNSIGNED_BYTE_44: // Fall-through
1516 case TextureFormat::UNORM_BYTE_44: *((deUint8 *)pixelPtr) = (deUint8 )(PU(color[0], 4, 4) | PU(color[1], 0, 4)); break;
1517 case TextureFormat::UNORM_INT_101010: *((deUint32*)pixelPtr) = PU(color[0], 22, 10) | PU(color[1], 12, 10) | PU(color[2], 2, 10); break;
1518
1519 case TextureFormat::UNORM_SHORT_565:
1520 case TextureFormat::UNSIGNED_SHORT_565:
1521 {
1522 const IVec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
1523 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 5, 6) | PU(swizzled[2], 0, 5));
1524 break;
1525 }
1526
1527 case TextureFormat::UNORM_SHORT_555:
1528 {
1529 const IVec4 swizzled = swizzleGe(color, TextureFormat::RGB, m_format.order);
1530 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 10, 5) | PU(swizzled[1], 5, 5) | PU(swizzled[2], 0, 5));
1531 break;
1532 }
1533
1534 case TextureFormat::UNORM_SHORT_4444:
1535 case TextureFormat::UNSIGNED_SHORT_4444:
1536 {
1537 const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1538 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 12, 4) | PU(swizzled[1], 8, 4) | PU(swizzled[2], 4, 4) | PU(swizzled[3], 0, 4));
1539 break;
1540 }
1541
1542 case TextureFormat::UNORM_SHORT_5551:
1543 case TextureFormat::UNSIGNED_SHORT_5551:
1544 {
1545 const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1546 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 11, 5) | PU(swizzled[1], 6, 5) | PU(swizzled[2], 1, 5) | PU(swizzled[3], 0, 1));
1547 break;
1548 }
1549
1550 case TextureFormat::UNORM_SHORT_1555:
1551 {
1552 const IVec4 swizzled = color.swizzle(3,0,1,2); // RGBA -> ARGB
1553 *((deUint16*)pixelPtr) = (deUint16)(PU(swizzled[0], 15, 1) | PU(swizzled[1], 10, 5) | PU(swizzled[2], 5, 5) | PU(swizzled[3], 0, 5));
1554 break;
1555 }
1556
1557 case TextureFormat::UNORM_INT_1010102_REV:
1558 case TextureFormat::UNSIGNED_INT_1010102_REV:
1559 case TextureFormat::USCALED_INT_1010102_REV:
1560 {
1561 const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1562 *((deUint32*)pixelPtr) = PU(swizzled[0], 0, 10) | PU(swizzled[1], 10, 10) | PU(swizzled[2], 20, 10) | PU(swizzled[3], 30, 2);
1563 break;
1564 }
1565
1566 case TextureFormat::SNORM_INT_1010102_REV:
1567 case TextureFormat::SIGNED_INT_1010102_REV:
1568 case TextureFormat::SSCALED_INT_1010102_REV:
1569 {
1570 const IVec4 swizzled = swizzleGe(color, TextureFormat::RGBA, m_format.order);
1571 *((deUint32*)pixelPtr) = PI(swizzled[0], 0, 10) | PI(swizzled[1], 10, 10) | PI(swizzled[2], 20, 10) | PI(swizzled[3], 30, 2);
1572 break;
1573 }
1574
1575 default:
1576 {
1577 // Generic path.
1578 int numChannels = getNumUsedChannels(m_format.order);
1579 const TextureSwizzle::Channel* map = getChannelWriteSwizzle(m_format.order).components;
1580 int channelSize = getChannelSize(m_format.type);
1581
1582 for (int c = 0; c < numChannels; c++)
1583 {
1584 DE_ASSERT(deInRange32(map[c], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3));
1585 intToChannel(pixelPtr + channelSize*c, color[map[c]], m_format.type);
1586 }
1587 break;
1588 }
1589 }
1590
1591 #undef PU
1592 #undef PI
1593 }
1594
setPixDepth(float depth,int x,int y,int z) const1595 void PixelBufferAccess::setPixDepth (float depth, int x, int y, int z) const
1596 {
1597 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1598 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1599 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1600
1601 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1602
1603 switch (m_format.type)
1604 {
1605 case TextureFormat::UNSIGNED_INT_16_8_8:
1606 DE_ASSERT(m_format.order == TextureFormat::DS);
1607 writeUint32High16(pixelPtr, convertSatRte<deUint16>(depth * 65535.0f));
1608 break;
1609
1610 case TextureFormat::UNSIGNED_INT_24_8:
1611 DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1612 writeUint32High24(pixelPtr, convertSatRteUint24(depth * 16777215.0f));
1613 break;
1614
1615 case TextureFormat::UNSIGNED_INT_24_8_REV:
1616 DE_ASSERT(m_format.order == TextureFormat::D || m_format.order == TextureFormat::DS);
1617 writeUint32Low24(pixelPtr, convertSatRteUint24(depth * 16777215.0f));
1618 break;
1619
1620 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1621 DE_ASSERT(m_format.order == TextureFormat::DS);
1622 *((float*)pixelPtr) = depth;
1623 break;
1624
1625 default:
1626 DE_ASSERT(m_format.order == TextureFormat::D); // no other combined depth stencil types
1627 floatToChannel(pixelPtr, depth, m_format.type);
1628 break;
1629 }
1630 }
1631
setPixStencil(int stencil,int x,int y,int z) const1632 void PixelBufferAccess::setPixStencil (int stencil, int x, int y, int z) const
1633 {
1634 DE_ASSERT(de::inBounds(x, 0, getWidth()));
1635 DE_ASSERT(de::inBounds(y, 0, getHeight()));
1636 DE_ASSERT(de::inBounds(z, 0, getDepth()));
1637
1638 deUint8* const pixelPtr = (deUint8*)getPixelPtr(x, y, z);
1639
1640 switch (m_format.type)
1641 {
1642 case TextureFormat::UNSIGNED_INT_16_8_8:
1643 case TextureFormat::UNSIGNED_INT_24_8:
1644 DE_ASSERT(m_format.order == TextureFormat::DS);
1645 writeUint32Low8(pixelPtr, convertSat<deUint8>((deUint32)stencil));
1646 break;
1647
1648 case TextureFormat::UNSIGNED_INT_24_8_REV:
1649 DE_ASSERT(m_format.order == TextureFormat::DS);
1650 writeUint32High8(pixelPtr, convertSat<deUint8>((deUint32)stencil));
1651 break;
1652
1653 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1654 DE_ASSERT(m_format.order == TextureFormat::DS);
1655 writeUint32Low8(pixelPtr + 4, convertSat<deUint8>((deUint32)stencil));
1656 break;
1657
1658 default:
1659 DE_ASSERT(m_format.order == TextureFormat::S); // no other combined depth stencil types
1660 intToChannel(pixelPtr, stencil, m_format.type);
1661 break;
1662 }
1663 }
1664
imod(int a,int b)1665 static inline int imod (int a, int b)
1666 {
1667 int m = a % b;
1668 return m < 0 ? m + b : m;
1669 }
1670
mirror(int a)1671 static inline int mirror (int a)
1672 {
1673 return a >= 0 ? a : -(1 + a);
1674 }
1675
1676 // Nearest-even rounding in case of tie (fractional part 0.5), otherwise ordinary rounding.
rint(float a)1677 static inline float rint (float a)
1678 {
1679 DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
1680
1681 float fracVal = deFloatFrac(a);
1682
1683 if (fracVal != 0.5f)
1684 return deFloatRound(a); // Ordinary case.
1685
1686 float floorVal = a - fracVal;
1687 bool roundUp = (deInt64)floorVal % 2 != 0;
1688
1689 return floorVal + (roundUp ? 1.0f : 0.0f);
1690 }
1691
wrap(Sampler::WrapMode mode,int c,int size)1692 static inline int wrap (Sampler::WrapMode mode, int c, int size)
1693 {
1694 switch (mode)
1695 {
1696 case tcu::Sampler::CLAMP_TO_BORDER:
1697 return deClamp32(c, -1, size);
1698
1699 case tcu::Sampler::CLAMP_TO_EDGE:
1700 return deClamp32(c, 0, size-1);
1701
1702 case tcu::Sampler::REPEAT_GL:
1703 return imod(c, size);
1704
1705 case tcu::Sampler::REPEAT_CL:
1706 return imod(c, size);
1707
1708 case tcu::Sampler::MIRRORED_ONCE:
1709 c = deClamp32(c, -size, size);
1710 // Fall-through
1711
1712 case tcu::Sampler::MIRRORED_REPEAT_GL:
1713 return (size - 1) - mirror(imod(c, 2*size) - size);
1714
1715 case tcu::Sampler::MIRRORED_REPEAT_CL:
1716 return deClamp32(c, 0, size-1); // \note Actual mirroring done already in unnormalization function.
1717
1718 default:
1719 DE_ASSERT(DE_FALSE);
1720 return 0;
1721 }
1722 }
1723
1724 // Special unnormalization for REPEAT_CL and MIRRORED_REPEAT_CL wrap modes; otherwise ordinary unnormalization.
unnormalize(Sampler::WrapMode mode,float c,int size)1725 static inline float unnormalize (Sampler::WrapMode mode, float c, int size)
1726 {
1727 switch (mode)
1728 {
1729 case tcu::Sampler::CLAMP_TO_EDGE:
1730 case tcu::Sampler::CLAMP_TO_BORDER:
1731 case tcu::Sampler::REPEAT_GL:
1732 case tcu::Sampler::MIRRORED_REPEAT_GL:
1733 case tcu::Sampler::MIRRORED_ONCE: // Fall-through (ordinary case).
1734 return (float)size*c;
1735
1736 case tcu::Sampler::REPEAT_CL:
1737 return (float)size * (c - deFloatFloor(c));
1738
1739 case tcu::Sampler::MIRRORED_REPEAT_CL:
1740 return (float)size * deFloatAbs(c - 2.0f * rint(0.5f * c));
1741
1742 default:
1743 DE_ASSERT(DE_FALSE);
1744 return 0.0f;
1745 }
1746 }
1747
isFixedPointDepthTextureFormat(const tcu::TextureFormat & format)1748 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
1749 {
1750 DE_ASSERT(format.order == TextureFormat::D);
1751
1752 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
1753 if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
1754 return false;
1755 else if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
1756 return true;
1757 else
1758 {
1759 DE_ASSERT(false);
1760 return false;
1761 }
1762 }
1763
1764 // Texel lookup with color conversion.
lookup(const ConstPixelBufferAccess & access,int i,int j,int k)1765 static inline Vec4 lookup (const ConstPixelBufferAccess& access, int i, int j, int k)
1766 {
1767 const TextureFormat& format = access.getFormat();
1768
1769 if (isSRGB(format))
1770 {
1771 if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGB)
1772 return sRGB8ToLinear(access.getPixelUint(i, j, k));
1773 else if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGBA)
1774 return sRGBA8ToLinear(access.getPixelUint(i, j, k));
1775 else
1776 return sRGBToLinear(access.getPixel(i, j, k));
1777 }
1778 else
1779 {
1780 return access.getPixel(i, j, k);
1781 }
1782 }
1783
1784 // Border texel lookup with color conversion.
lookupBorder(const tcu::TextureFormat & format,const tcu::Sampler & sampler)1785 static inline Vec4 lookupBorder (const tcu::TextureFormat& format, const tcu::Sampler& sampler)
1786 {
1787 // "lookup" for a combined format does not make sense, disallow
1788 DE_ASSERT(!isCombinedDepthStencilType(format.type));
1789
1790 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
1791 const bool isFloat = channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
1792 const bool isFixed = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
1793 channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
1794 const bool isPureInteger = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
1795 const bool isPureUnsignedInteger = channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
1796
1797 if (isFloat || isFixed)
1798 return sampleTextureBorder<float>(format, sampler);
1799 else if (isPureInteger)
1800 return sampleTextureBorder<deInt32>(format, sampler).cast<float>();
1801 else if (isPureUnsignedInteger)
1802 return sampleTextureBorder<deUint32>(format, sampler).cast<float>();
1803 else
1804 {
1805 DE_ASSERT(false);
1806 return Vec4(-1.0);
1807 }
1808 }
1809
execCompare(const tcu::Vec4 & color,Sampler::CompareMode compare,int chanNdx,float ref_,bool isFixedPoint)1810 static inline float execCompare (const tcu::Vec4& color, Sampler::CompareMode compare, int chanNdx, float ref_, bool isFixedPoint)
1811 {
1812 const bool clampValues = isFixedPoint; // if comparing against a floating point texture, ref (and value) is not clamped
1813 const float cmp = (clampValues) ? (de::clamp(color[chanNdx], 0.0f, 1.0f)) : (color[chanNdx]);
1814 const float ref = (clampValues) ? (de::clamp(ref_, 0.0f, 1.0f)) : (ref_);
1815 bool res = false;
1816
1817 switch (compare)
1818 {
1819 case Sampler::COMPAREMODE_LESS: res = ref < cmp; break;
1820 case Sampler::COMPAREMODE_LESS_OR_EQUAL: res = ref <= cmp; break;
1821 case Sampler::COMPAREMODE_GREATER: res = ref > cmp; break;
1822 case Sampler::COMPAREMODE_GREATER_OR_EQUAL: res = ref >= cmp; break;
1823 case Sampler::COMPAREMODE_EQUAL: res = ref == cmp; break;
1824 case Sampler::COMPAREMODE_NOT_EQUAL: res = ref != cmp; break;
1825 case Sampler::COMPAREMODE_ALWAYS: res = true; break;
1826 case Sampler::COMPAREMODE_NEVER: res = false; break;
1827 default:
1828 DE_ASSERT(false);
1829 }
1830
1831 return res ? 1.0f : 0.0f;
1832 }
1833
sampleNearest1D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,const IVec2 & offset)1834 static Vec4 sampleNearest1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1835 {
1836 int width = access.getWidth();
1837
1838 int x = deFloorFloatToInt32(u)+offset.x();
1839
1840 // Check for CLAMP_TO_BORDER.
1841 if (sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width))
1842 return lookupBorder(access.getFormat(), sampler);
1843
1844 int i = wrap(sampler.wrapS, x, width);
1845
1846 return lookup(access, i, offset.y(), 0);
1847 }
1848
sampleNearest2D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,const IVec3 & offset)1849 static Vec4 sampleNearest2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
1850 {
1851 int width = access.getWidth();
1852 int height = access.getHeight();
1853
1854 int x = deFloorFloatToInt32(u)+offset.x();
1855 int y = deFloorFloatToInt32(v)+offset.y();
1856
1857 // Check for CLAMP_TO_BORDER.
1858 if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)) ||
1859 (sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height)))
1860 return lookupBorder(access.getFormat(), sampler);
1861
1862 int i = wrap(sampler.wrapS, x, width);
1863 int j = wrap(sampler.wrapT, y, height);
1864
1865 return lookup(access, i, j, offset.z());
1866 }
1867
sampleNearest3D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,float w,const IVec3 & offset)1868 static Vec4 sampleNearest3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
1869 {
1870 int width = access.getWidth();
1871 int height = access.getHeight();
1872 int depth = access.getDepth();
1873
1874 int x = deFloorFloatToInt32(u)+offset.x();
1875 int y = deFloorFloatToInt32(v)+offset.y();
1876 int z = deFloorFloatToInt32(w)+offset.z();
1877
1878 // Check for CLAMP_TO_BORDER.
1879 if ((sampler.wrapS == Sampler::CLAMP_TO_BORDER && !deInBounds32(x, 0, width)) ||
1880 (sampler.wrapT == Sampler::CLAMP_TO_BORDER && !deInBounds32(y, 0, height)) ||
1881 (sampler.wrapR == Sampler::CLAMP_TO_BORDER && !deInBounds32(z, 0, depth)))
1882 return lookupBorder(access.getFormat(), sampler);
1883
1884 int i = wrap(sampler.wrapS, x, width);
1885 int j = wrap(sampler.wrapT, y, height);
1886 int k = wrap(sampler.wrapR, z, depth);
1887
1888 return lookup(access, i, j, k);
1889 }
1890
sampleLinear1D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,const IVec2 & offset)1891 static Vec4 sampleLinear1D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1892 {
1893 int w = access.getWidth();
1894
1895 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1896 int x1 = x0+1;
1897
1898 int i0 = wrap(sampler.wrapS, x0, w);
1899 int i1 = wrap(sampler.wrapS, x1, w);
1900
1901 float a = deFloatFrac(u-0.5f);
1902
1903 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
1904 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
1905
1906 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
1907 Vec4 p0 = i0UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, offset.y(), 0);
1908 Vec4 p1 = i1UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, offset.y(), 0);
1909
1910 // Interpolate.
1911 return p0 * (1.0f - a) + p1 * a;
1912 }
1913
sampleCubic1D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,const IVec2 & offset)1914 static Vec4 sampleCubic1D(const ConstPixelBufferAccess& access, const Sampler& sampler, float u, const IVec2& offset)
1915 {
1916 int width = access.getWidth();
1917
1918 tcu::IVec4 x, i;
1919
1920 x[0] = deFloorFloatToInt32(u - 1.5f) + offset.x();
1921 x[1] = x[0] + 1;
1922 x[2] = x[1] + 1;
1923 x[3] = x[2] + 1;
1924
1925 for (deUint32 m = 0; m < 4; ++m)
1926 i[m] = wrap(sampler.wrapS, x[m], width);
1927
1928 bool iUseBorder[4];
1929 for (deUint32 m = 0; m < 4; ++m)
1930 iUseBorder[m] = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i[m], 0, width);
1931
1932 // Catmull-Rom basis matrix
1933 static const float crValues[16] = { 0.0f, 1.0f, 0.0f, 0.0f,
1934 -0.5f, 0.0f, 0.5f, 0.0f,
1935 1.0f, -2.5f, 2.0f, -0.5f,
1936 -0.5f, 1.5f, -1.5f, 0.5f };
1937 static const tcu::Mat4 crBasis(crValues);
1938
1939 float a = deFloatFrac(u - 0.5f);
1940 tcu::Vec4 alpha(1, a, a*a, a*a*a);
1941 tcu::Vec4 wi = alpha * crBasis;
1942
1943 tcu::Vec4 result(0.0f, 0.0f, 0.0f, 0.0f);
1944 for (deUint32 m = 0; m < 4; ++m)
1945 {
1946 tcu::Vec4 p = (iUseBorder[m]) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i[m], offset.y(), 0);
1947 result += wi[m] * p;
1948 }
1949 return result;
1950 }
1951
sampleLinear2D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,const IVec3 & offset)1952 static Vec4 sampleLinear2D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
1953 {
1954 int w = access.getWidth();
1955 int h = access.getHeight();
1956
1957 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
1958 int x1 = x0+1;
1959 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
1960 int y1 = y0+1;
1961
1962 int i0 = wrap(sampler.wrapS, x0, w);
1963 int i1 = wrap(sampler.wrapS, x1, w);
1964 int j0 = wrap(sampler.wrapT, y0, h);
1965 int j1 = wrap(sampler.wrapT, y1, h);
1966
1967 float a = deFloatFrac(u-0.5f);
1968 float b = deFloatFrac(v-0.5f);
1969
1970 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
1971 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
1972 bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
1973 bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
1974
1975 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
1976 Vec4 p00 = (i0UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, offset.z());
1977 Vec4 p10 = (i1UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, offset.z());
1978 Vec4 p01 = (i0UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, offset.z());
1979 Vec4 p11 = (i1UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, offset.z());
1980
1981 // Interpolate.
1982 return (p00*(1.0f-a)*(1.0f-b)) +
1983 (p10*( a)*(1.0f-b)) +
1984 (p01*(1.0f-a)*( b)) +
1985 (p11*( a)*( b));
1986 }
1987
sampleCubic2D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,const IVec3 & offset)1988 static Vec4 sampleCubic2D(const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, const IVec3& offset)
1989 {
1990 int width = access.getWidth();
1991 int height = access.getHeight();
1992
1993 tcu::IVec4 x, y, i, j;
1994
1995 x[0] = deFloorFloatToInt32(u - 1.5f) + offset.x();
1996 x[1] = x[0] + 1;
1997 x[2] = x[1] + 1;
1998 x[3] = x[2] + 1;
1999 y[0] = deFloorFloatToInt32(v - 1.5f) + offset.y();
2000 y[1] = y[0] + 1;
2001 y[2] = y[1] + 1;
2002 y[3] = y[2] + 1;
2003
2004 for (deUint32 m = 0; m < 4; ++m)
2005 i[m] = wrap(sampler.wrapS, x[m], width);
2006 for (deUint32 n = 0; n < 4; ++n)
2007 j[n] = wrap(sampler.wrapT, y[n], height);
2008
2009 bool iUseBorder[4], jUseBorder[4];
2010 for (deUint32 m = 0; m < 4; ++m)
2011 iUseBorder[m] = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i[m], 0, width);
2012 for (deUint32 n = 0; n < 4; ++n)
2013 jUseBorder[n] = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j[n], 0, height);
2014
2015 // Catmull-Rom basis matrix
2016 static const float crValues[16] = { 0.0f, 1.0f, 0.0f, 0.0f,
2017 -0.5f, 0.0f, 0.5f, 0.0f,
2018 1.0f, -2.5f, 2.0f, -0.5f,
2019 -0.5f, 1.5f, -1.5f, 0.5f };
2020 static const tcu::Mat4 crBasis(crValues);
2021
2022 float a = deFloatFrac(u - 0.5f);
2023 float b = deFloatFrac(v - 0.5f);
2024 tcu::Vec4 alpha (1, a, a*a, a*a*a);
2025 tcu::Vec4 beta (1, b, b*b, b*b*b);
2026 tcu::Vec4 wi = alpha * crBasis;
2027 tcu::Vec4 wj = beta * crBasis;
2028
2029 tcu::Vec4 result(0.0f, 0.0f, 0.0f, 0.0f);
2030 for (deUint32 n = 0; n < 4; ++n)
2031 for (deUint32 m = 0; m < 4; ++m)
2032 {
2033 tcu::Vec4 p = (iUseBorder[m] || jUseBorder[n]) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i[m], j[n], offset.z());
2034 result += wi[m] * wj[n] * p;
2035 }
2036 return result;
2037 }
2038
sampleLinear1DCompare(const ConstPixelBufferAccess & access,const Sampler & sampler,float ref,float u,const IVec2 & offset,bool isFixedPointDepthFormat)2039 static float sampleLinear1DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, const IVec2& offset, bool isFixedPointDepthFormat)
2040 {
2041 int w = access.getWidth();
2042
2043 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
2044 int x1 = x0+1;
2045
2046 int i0 = wrap(sampler.wrapS, x0, w);
2047 int i1 = wrap(sampler.wrapS, x1, w);
2048
2049 float a = deFloatFrac(u-0.5f);
2050
2051 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
2052 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
2053
2054 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
2055 Vec4 p0Clr = i0UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, offset.y(), 0);
2056 Vec4 p1Clr = i1UseBorder ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, offset.y(), 0);
2057
2058 // Execute comparisons.
2059 float p0 = execCompare(p0Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2060 float p1 = execCompare(p1Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2061
2062 // Interpolate.
2063 return (p0 * (1.0f - a)) + (p1 * a);
2064 }
2065
sampleLinear2DCompare(const ConstPixelBufferAccess & access,const Sampler & sampler,float ref,float u,float v,const IVec3 & offset,bool isFixedPointDepthFormat)2066 static float sampleLinear2DCompare (const ConstPixelBufferAccess& access, const Sampler& sampler, float ref, float u, float v, const IVec3& offset, bool isFixedPointDepthFormat)
2067 {
2068 int w = access.getWidth();
2069 int h = access.getHeight();
2070
2071 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
2072 int x1 = x0+1;
2073 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
2074 int y1 = y0+1;
2075
2076 int i0 = wrap(sampler.wrapS, x0, w);
2077 int i1 = wrap(sampler.wrapS, x1, w);
2078 int j0 = wrap(sampler.wrapT, y0, h);
2079 int j1 = wrap(sampler.wrapT, y1, h);
2080
2081 float a = deFloatFrac(u-0.5f);
2082 float b = deFloatFrac(v-0.5f);
2083
2084 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, w);
2085 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, w);
2086 bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, h);
2087 bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, h);
2088
2089 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
2090 Vec4 p00Clr = (i0UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, offset.z());
2091 Vec4 p10Clr = (i1UseBorder || j0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, offset.z());
2092 Vec4 p01Clr = (i0UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, offset.z());
2093 Vec4 p11Clr = (i1UseBorder || j1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, offset.z());
2094
2095 // Execute comparisons.
2096 float p00 = execCompare(p00Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2097 float p10 = execCompare(p10Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2098 float p01 = execCompare(p01Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2099 float p11 = execCompare(p11Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
2100
2101 // Interpolate.
2102 return (p00*(1.0f-a)*(1.0f-b)) +
2103 (p10*( a)*(1.0f-b)) +
2104 (p01*(1.0f-a)*( b)) +
2105 (p11*( a)*( b));
2106 }
2107
sampleLinear3D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,float w,const IVec3 & offset)2108 static Vec4 sampleLinear3D (const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
2109 {
2110 int width = access.getWidth();
2111 int height = access.getHeight();
2112 int depth = access.getDepth();
2113
2114 int x0 = deFloorFloatToInt32(u-0.5f)+offset.x();
2115 int x1 = x0+1;
2116 int y0 = deFloorFloatToInt32(v-0.5f)+offset.y();
2117 int y1 = y0+1;
2118 int z0 = deFloorFloatToInt32(w-0.5f)+offset.z();
2119 int z1 = z0+1;
2120
2121 int i0 = wrap(sampler.wrapS, x0, width);
2122 int i1 = wrap(sampler.wrapS, x1, width);
2123 int j0 = wrap(sampler.wrapT, y0, height);
2124 int j1 = wrap(sampler.wrapT, y1, height);
2125 int k0 = wrap(sampler.wrapR, z0, depth);
2126 int k1 = wrap(sampler.wrapR, z1, depth);
2127
2128 float a = deFloatFrac(u-0.5f);
2129 float b = deFloatFrac(v-0.5f);
2130 float c = deFloatFrac(w-0.5f);
2131
2132 bool i0UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i0, 0, width);
2133 bool i1UseBorder = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i1, 0, width);
2134 bool j0UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j0, 0, height);
2135 bool j1UseBorder = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j1, 0, height);
2136 bool k0UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k0, 0, depth);
2137 bool k1UseBorder = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k1, 0, depth);
2138
2139 // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
2140 Vec4 p000 = (i0UseBorder || j0UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, k0);
2141 Vec4 p100 = (i1UseBorder || j0UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, k0);
2142 Vec4 p010 = (i0UseBorder || j1UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, k0);
2143 Vec4 p110 = (i1UseBorder || j1UseBorder || k0UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, k0);
2144 Vec4 p001 = (i0UseBorder || j0UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j0, k1);
2145 Vec4 p101 = (i1UseBorder || j0UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j0, k1);
2146 Vec4 p011 = (i0UseBorder || j1UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i0, j1, k1);
2147 Vec4 p111 = (i1UseBorder || j1UseBorder || k1UseBorder) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i1, j1, k1);
2148
2149 // Interpolate.
2150 return (p000*(1.0f-a)*(1.0f-b)*(1.0f-c)) +
2151 (p100*( a)*(1.0f-b)*(1.0f-c)) +
2152 (p010*(1.0f-a)*( b)*(1.0f-c)) +
2153 (p110*( a)*( b)*(1.0f-c)) +
2154 (p001*(1.0f-a)*(1.0f-b)*( c)) +
2155 (p101*( a)*(1.0f-b)*( c)) +
2156 (p011*(1.0f-a)*( b)*( c)) +
2157 (p111*( a)*( b)*( c));
2158 }
2159
sampleCubic3D(const ConstPixelBufferAccess & access,const Sampler & sampler,float u,float v,float w,const IVec3 & offset)2160 static Vec4 sampleCubic3D(const ConstPixelBufferAccess& access, const Sampler& sampler, float u, float v, float w, const IVec3& offset)
2161 {
2162 int width = access.getWidth();
2163 int height = access.getHeight();
2164 int depth = access.getDepth();
2165
2166 tcu::IVec4 x, y, z, i, j, k;
2167
2168 x[0] = deFloorFloatToInt32(u - 1.5f) + offset.x();
2169 x[1] = x[0] + 1;
2170 x[2] = x[1] + 1;
2171 x[3] = x[2] + 1;
2172 y[0] = deFloorFloatToInt32(v - 1.5f) + offset.y();
2173 y[1] = y[0] + 1;
2174 y[2] = y[1] + 1;
2175 y[3] = y[2] + 1;
2176 z[0] = deFloorFloatToInt32(w - 1.5f) + offset.z();
2177 z[1] = z[0] + 1;
2178 z[2] = z[1] + 1;
2179 z[3] = z[2] + 1;
2180
2181 for (deUint32 m = 0; m < 4; ++m)
2182 i[m] = wrap(sampler.wrapS, x[m], width);
2183 for (deUint32 n = 0; n < 4; ++n)
2184 j[n] = wrap(sampler.wrapT, y[n], height);
2185 for (deUint32 o = 0; o < 4; ++o)
2186 k[o] = wrap(sampler.wrapR, k[o], depth);
2187
2188 bool iUseBorder[4], jUseBorder[4], kUseBorder[4];
2189 for (deUint32 m = 0; m < 4; ++m)
2190 iUseBorder[m] = sampler.wrapS == Sampler::CLAMP_TO_BORDER && !de::inBounds(i[m], 0, width);
2191 for (deUint32 n = 0; n < 4; ++n)
2192 jUseBorder[n] = sampler.wrapT == Sampler::CLAMP_TO_BORDER && !de::inBounds(j[n], 0, height);
2193 for (deUint32 o = 0; o < 4; ++o)
2194 kUseBorder[o] = sampler.wrapR == Sampler::CLAMP_TO_BORDER && !de::inBounds(k[o], 0, depth);
2195
2196 // Catmull-Rom basis matrix
2197 static const float crValues[16] = { 0.0f, 1.0f, 0.0f, 0.0f,
2198 -0.5f, 0.0f, 0.5f, 0.0f,
2199 1.0f, -2.5f, 2.0f, -0.5f,
2200 -0.5f, 1.5f, -1.5f, 0.5f };
2201 static const tcu::Mat4 crBasis(crValues);
2202
2203 float a = deFloatFrac(u - 0.5f);
2204 float b = deFloatFrac(v - 0.5f);
2205 float c = deFloatFrac(w - 0.5f);
2206 tcu::Vec4 alpha (1, a, a*a, a*a*a);
2207 tcu::Vec4 beta (1, b, b*b, b*b*b);
2208 tcu::Vec4 gamma (1, c, c*c, c*c*c);
2209 tcu::Vec4 wi = alpha * crBasis;
2210 tcu::Vec4 wj = beta * crBasis;
2211 tcu::Vec4 wk = gamma * crBasis;
2212
2213 tcu::Vec4 result(0.0f, 0.0f, 0.0f, 0.0f);
2214 for (deUint32 o = 0; o < 4; ++o)
2215 for (deUint32 n = 0; n < 4; ++n)
2216 for (deUint32 m = 0; m < 4; ++m)
2217 {
2218 tcu::Vec4 p = (iUseBorder[m] || jUseBorder[n] || kUseBorder[o]) ? lookupBorder(access.getFormat(), sampler) : lookup(access, i[m], j[n], k[o]);
2219 result += wi[m] * wj[n] * wk[o] * p;
2220 }
2221 return result;
2222 }
2223
sample1D(const Sampler & sampler,Sampler::FilterMode filter,float s,int level) const2224 Vec4 ConstPixelBufferAccess::sample1D (const Sampler& sampler, Sampler::FilterMode filter, float s, int level) const
2225 {
2226 // check selected layer exists
2227 DE_ASSERT(de::inBounds(level, 0, m_size.y()));
2228
2229 return sample1DOffset(sampler, filter, s, tcu::IVec2(0, level));
2230 }
2231
sample2D(const Sampler & sampler,Sampler::FilterMode filter,float s,float t,int depth) const2232 Vec4 ConstPixelBufferAccess::sample2D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, int depth) const
2233 {
2234 // check selected layer exists
2235 DE_ASSERT(de::inBounds(depth, 0, m_size.z()));
2236
2237 return sample2DOffset(sampler, filter, s, t, tcu::IVec3(0, 0, depth));
2238 }
2239
sample3D(const Sampler & sampler,Sampler::FilterMode filter,float s,float t,float r) const2240 Vec4 ConstPixelBufferAccess::sample3D (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r) const
2241 {
2242 return sample3DOffset(sampler, filter, s, t, r, tcu::IVec3(0, 0, 0));
2243 }
2244
sample1DOffset(const Sampler & sampler,Sampler::FilterMode filter,float s,const IVec2 & offset) const2245 Vec4 ConstPixelBufferAccess::sample1DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, const IVec2& offset) const
2246 {
2247 // check selected layer exists
2248 // \note offset.x is X offset, offset.y is the selected layer
2249 DE_ASSERT(de::inBounds(offset.y(), 0, m_size.y()));
2250
2251 // Non-normalized coordinates.
2252 float u = s;
2253
2254 if (sampler.normalizedCoords)
2255 u = unnormalize(sampler.wrapS, s, m_size.x());
2256
2257 switch (filter)
2258 {
2259 case Sampler::NEAREST: return sampleNearest1D (*this, sampler, u, offset);
2260 case Sampler::LINEAR: return sampleLinear1D (*this, sampler, u, offset);
2261 case Sampler::CUBIC: return sampleCubic1D (*this, sampler, u, offset);
2262 default:
2263 DE_ASSERT(DE_FALSE);
2264 return Vec4(0.0f);
2265 }
2266 }
2267
sample2DOffset(const Sampler & sampler,Sampler::FilterMode filter,float s,float t,const IVec3 & offset) const2268 Vec4 ConstPixelBufferAccess::sample2DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, const IVec3& offset) const
2269 {
2270 // check selected layer exists
2271 // \note offset.xy is the XY offset, offset.z is the selected layer
2272 DE_ASSERT(de::inBounds(offset.z(), 0, m_size.z()));
2273
2274 // Non-normalized coordinates.
2275 float u = s;
2276 float v = t;
2277
2278 if (sampler.normalizedCoords)
2279 {
2280 u = unnormalize(sampler.wrapS, s, m_size.x());
2281 v = unnormalize(sampler.wrapT, t, m_size.y());
2282 }
2283
2284 switch (filter)
2285 {
2286 case Sampler::NEAREST: return sampleNearest2D (*this, sampler, u, v, offset);
2287 case Sampler::LINEAR: return sampleLinear2D (*this, sampler, u, v, offset);
2288 case Sampler::CUBIC: return sampleCubic2D (*this, sampler, u, v, offset);
2289 default:
2290 DE_ASSERT(DE_FALSE);
2291 return Vec4(0.0f);
2292 }
2293 }
2294
sample3DOffset(const Sampler & sampler,Sampler::FilterMode filter,float s,float t,float r,const IVec3 & offset) const2295 Vec4 ConstPixelBufferAccess::sample3DOffset (const Sampler& sampler, Sampler::FilterMode filter, float s, float t, float r, const IVec3& offset) const
2296 {
2297 // Non-normalized coordinates.
2298 float u = s;
2299 float v = t;
2300 float w = r;
2301
2302 if (sampler.normalizedCoords)
2303 {
2304 u = unnormalize(sampler.wrapS, s, m_size.x());
2305 v = unnormalize(sampler.wrapT, t, m_size.y());
2306 w = unnormalize(sampler.wrapR, r, m_size.z());
2307 }
2308
2309 switch (filter)
2310 {
2311 case Sampler::NEAREST: return sampleNearest3D (*this, sampler, u, v, w, offset);
2312 case Sampler::LINEAR: return sampleLinear3D (*this, sampler, u, v, w, offset);
2313 case Sampler::CUBIC: return sampleCubic3D (*this, sampler, u, v, w, offset);
2314 default:
2315 DE_ASSERT(DE_FALSE);
2316 return Vec4(0.0f);
2317 }
2318 }
2319
sample1DCompare(const Sampler & sampler,Sampler::FilterMode filter,float ref,float s,const IVec2 & offset) const2320 float ConstPixelBufferAccess::sample1DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, const IVec2& offset) const
2321 {
2322 // check selected layer exists
2323 // \note offset.x is X offset, offset.y is the selected layer
2324 DE_ASSERT(de::inBounds(offset.y(), 0, m_size.y()));
2325
2326 // Format information for comparison function
2327 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
2328
2329 // Non-normalized coordinates.
2330 float u = s;
2331
2332 if (sampler.normalizedCoords)
2333 u = unnormalize(sampler.wrapS, s, m_size.x());
2334
2335 switch (filter)
2336 {
2337 case Sampler::NEAREST: return execCompare(sampleNearest1D(*this, sampler, u, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
2338 case Sampler::LINEAR: return sampleLinear1DCompare(*this, sampler, ref, u, offset, isFixedPointDepth);
2339 default:
2340 DE_ASSERT(DE_FALSE);
2341 return 0.0f;
2342 }
2343 }
2344
sample2DCompare(const Sampler & sampler,Sampler::FilterMode filter,float ref,float s,float t,const IVec3 & offset) const2345 float ConstPixelBufferAccess::sample2DCompare (const Sampler& sampler, Sampler::FilterMode filter, float ref, float s, float t, const IVec3& offset) const
2346 {
2347 // check selected layer exists
2348 // \note offset.xy is XY offset, offset.z is the selected layer
2349 DE_ASSERT(de::inBounds(offset.z(), 0, m_size.z()));
2350
2351 // Format information for comparison function
2352 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(m_format);
2353
2354 // Non-normalized coordinates.
2355 float u = s;
2356 float v = t;
2357
2358 if (sampler.normalizedCoords)
2359 {
2360 u = unnormalize(sampler.wrapS, s, m_size.x());
2361 v = unnormalize(sampler.wrapT, t, m_size.y());
2362 }
2363
2364 switch (filter)
2365 {
2366 case Sampler::NEAREST: return execCompare(sampleNearest2D(*this, sampler, u, v, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
2367 case Sampler::LINEAR: return sampleLinear2DCompare(*this, sampler, ref, u, v, offset, isFixedPointDepth);
2368 default:
2369 DE_ASSERT(DE_FALSE);
2370 return 0.0f;
2371 }
2372 }
2373
TextureLevel(void)2374 TextureLevel::TextureLevel (void)
2375 : m_format ()
2376 , m_size (0)
2377 {
2378 }
2379
TextureLevel(const TextureFormat & format)2380 TextureLevel::TextureLevel (const TextureFormat& format)
2381 : m_format (format)
2382 , m_size (0)
2383 {
2384 }
2385
TextureLevel(const TextureFormat & format,int width,int height,int depth)2386 TextureLevel::TextureLevel (const TextureFormat& format, int width, int height, int depth)
2387 : m_format (format)
2388 , m_size (0)
2389 {
2390 setSize(width, height, depth);
2391 }
2392
~TextureLevel(void)2393 TextureLevel::~TextureLevel (void)
2394 {
2395 }
2396
setStorage(const TextureFormat & format,int width,int height,int depth)2397 void TextureLevel::setStorage (const TextureFormat& format, int width, int height, int depth)
2398 {
2399 m_format = format;
2400 setSize(width, height, depth);
2401 }
2402
setSize(int width,int height,int depth)2403 void TextureLevel::setSize (int width, int height, int depth)
2404 {
2405 int pixelSize = m_format.getPixelSize();
2406
2407 m_size = IVec3(width, height, depth);
2408
2409 m_data.setStorage(m_size.x() * m_size.y() * m_size.z() * pixelSize);
2410 }
2411
sampleLevelArray1D(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,int depth,float lod)2412 Vec4 sampleLevelArray1D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, int depth, float lod)
2413 {
2414 return sampleLevelArray1DOffset(levels, numLevels, sampler, s, lod, IVec2(0, depth)); // y-offset in 1D textures is layer selector
2415 }
2416
sampleLevelArray2D(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float t,int depth,float lod,bool es2)2417 Vec4 sampleLevelArray2D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, int depth, float lod, bool es2)
2418 {
2419 return sampleLevelArray2DOffset(levels, numLevels, sampler, s, t, lod, IVec3(0, 0, depth), es2); // z-offset in 2D textures is layer selector
2420 }
2421
sampleLevelArray3D(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float t,float r,float lod)2422 Vec4 sampleLevelArray3D (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod)
2423 {
2424 return sampleLevelArray3DOffset(levels, numLevels, sampler, s, t, r, lod, IVec3(0, 0, 0));
2425 }
2426
sampleLevelArray1DOffset(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float lod,const IVec2 & offset)2427 Vec4 sampleLevelArray1DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float lod, const IVec2& offset)
2428 {
2429 bool magnified = lod <= sampler.lodThreshold;
2430 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2431
2432 switch (filterMode)
2433 {
2434 case Sampler::NEAREST: return levels[0].sample1DOffset(sampler, filterMode, s, offset);
2435 case Sampler::LINEAR: return levels[0].sample1DOffset(sampler, filterMode, s, offset);
2436
2437 case Sampler::NEAREST_MIPMAP_NEAREST:
2438 case Sampler::LINEAR_MIPMAP_NEAREST:
2439 {
2440 int maxLevel = (int)numLevels-1;
2441 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2442 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2443
2444 return levels[level].sample1DOffset(sampler, levelFilter, s, offset);
2445 }
2446
2447 case Sampler::NEAREST_MIPMAP_LINEAR:
2448 case Sampler::LINEAR_MIPMAP_LINEAR:
2449 {
2450 int maxLevel = (int)numLevels-1;
2451 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2452 int level1 = de::min(maxLevel, level0 + 1);
2453 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2454 float f = deFloatFrac(lod);
2455 tcu::Vec4 t0 = levels[level0].sample1DOffset(sampler, levelFilter, s, offset);
2456 tcu::Vec4 t1 = levels[level1].sample1DOffset(sampler, levelFilter, s, offset);
2457
2458 return t0*(1.0f - f) + t1*f;
2459 }
2460
2461 default:
2462 DE_ASSERT(DE_FALSE);
2463 return Vec4(0.0f);
2464 }
2465 }
2466
sampleLevelArray2DOffset(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float t,float lod,const IVec3 & offset,bool es2)2467 Vec4 sampleLevelArray2DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float lod, const IVec3& offset, bool es2)
2468 {
2469 bool magnified;
2470
2471 if (es2 && sampler.magFilter == Sampler::LINEAR &&
2472 (sampler.minFilter == Sampler::NEAREST_MIPMAP_NEAREST || sampler.minFilter == Sampler::NEAREST_MIPMAP_LINEAR))
2473 magnified = lod <= 0.5;
2474 else
2475 magnified = lod <= sampler.lodThreshold;
2476 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2477
2478 switch (filterMode)
2479 {
2480 case Sampler::NEAREST:
2481 case Sampler::LINEAR:
2482 case Sampler::CUBIC:
2483 return levels[0].sample2DOffset(sampler, filterMode, s, t, offset);
2484
2485 case Sampler::NEAREST_MIPMAP_NEAREST:
2486 case Sampler::LINEAR_MIPMAP_NEAREST:
2487 case Sampler::CUBIC_MIPMAP_NEAREST:
2488 {
2489 int maxLevel = (int)numLevels-1;
2490 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2491 Sampler::FilterMode levelFilter;
2492 switch (filterMode)
2493 {
2494 case Sampler::NEAREST_MIPMAP_NEAREST: levelFilter = Sampler::NEAREST; break;
2495 case Sampler::LINEAR_MIPMAP_NEAREST: levelFilter = Sampler::LINEAR; break;
2496 case Sampler::CUBIC_MIPMAP_NEAREST: levelFilter = Sampler::CUBIC; break;
2497 default:
2498 DE_ASSERT(DE_FALSE);
2499 return Vec4(0.0f);
2500 }
2501
2502 return levels[level].sample2DOffset(sampler, levelFilter, s, t, offset);
2503 }
2504
2505 case Sampler::NEAREST_MIPMAP_LINEAR:
2506 case Sampler::LINEAR_MIPMAP_LINEAR:
2507 case Sampler::CUBIC_MIPMAP_LINEAR:
2508 {
2509 int maxLevel = (int)numLevels-1;
2510 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2511 int level1 = de::min(maxLevel, level0 + 1);
2512 Sampler::FilterMode levelFilter;
2513 switch (filterMode)
2514 {
2515 case Sampler::NEAREST_MIPMAP_LINEAR: levelFilter = Sampler::NEAREST; break;
2516 case Sampler::LINEAR_MIPMAP_LINEAR: levelFilter = Sampler::LINEAR; break;
2517 case Sampler::CUBIC_MIPMAP_LINEAR: levelFilter = Sampler::CUBIC; break;
2518 default:
2519 DE_ASSERT(DE_FALSE);
2520 return Vec4(0.0f);
2521 }
2522 float f = deFloatFrac(lod);
2523 tcu::Vec4 t0 = levels[level0].sample2DOffset(sampler, levelFilter, s, t, offset);
2524 tcu::Vec4 t1 = levels[level1].sample2DOffset(sampler, levelFilter, s, t, offset);
2525
2526 return t0*(1.0f - f) + t1*f;
2527 }
2528
2529 default:
2530 DE_ASSERT(DE_FALSE);
2531 return Vec4(0.0f);
2532 }
2533 }
2534
sampleLevelArray3DOffset(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float s,float t,float r,float lod,const IVec3 & offset)2535 Vec4 sampleLevelArray3DOffset (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float s, float t, float r, float lod, const IVec3& offset)
2536 {
2537 bool magnified = lod <= sampler.lodThreshold;
2538 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2539
2540 switch (filterMode)
2541 {
2542 case Sampler::NEAREST: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
2543 case Sampler::LINEAR: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
2544
2545 case Sampler::NEAREST_MIPMAP_NEAREST:
2546 case Sampler::LINEAR_MIPMAP_NEAREST:
2547 {
2548 int maxLevel = (int)numLevels-1;
2549 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2550 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2551
2552 return levels[level].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2553 }
2554
2555 case Sampler::NEAREST_MIPMAP_LINEAR:
2556 case Sampler::LINEAR_MIPMAP_LINEAR:
2557 {
2558 int maxLevel = (int)numLevels-1;
2559 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2560 int level1 = de::min(maxLevel, level0 + 1);
2561 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2562 float f = deFloatFrac(lod);
2563 tcu::Vec4 t0 = levels[level0].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2564 tcu::Vec4 t1 = levels[level1].sample3DOffset(sampler, levelFilter, s, t, r, offset);
2565
2566 return t0*(1.0f - f) + t1*f;
2567 }
2568
2569 default:
2570 DE_ASSERT(DE_FALSE);
2571 return Vec4(0.0f);
2572 }
2573 }
2574
sampleLevelArray1DCompare(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float ref,float s,float lod,const IVec2 & offset)2575 float sampleLevelArray1DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float lod, const IVec2& offset)
2576 {
2577 bool magnified = lod <= sampler.lodThreshold;
2578 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2579
2580 switch (filterMode)
2581 {
2582 case Sampler::NEAREST: return levels[0].sample1DCompare(sampler, filterMode, ref, s, offset);
2583 case Sampler::LINEAR: return levels[0].sample1DCompare(sampler, filterMode, ref, s, offset);
2584
2585 case Sampler::NEAREST_MIPMAP_NEAREST:
2586 case Sampler::LINEAR_MIPMAP_NEAREST:
2587 {
2588 int maxLevel = (int)numLevels-1;
2589 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2590 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2591
2592 return levels[level].sample1DCompare(sampler, levelFilter, ref, s, offset);
2593 }
2594
2595 case Sampler::NEAREST_MIPMAP_LINEAR:
2596 case Sampler::LINEAR_MIPMAP_LINEAR:
2597 {
2598 int maxLevel = (int)numLevels-1;
2599 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2600 int level1 = de::min(maxLevel, level0 + 1);
2601 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2602 float f = deFloatFrac(lod);
2603 float t0 = levels[level0].sample1DCompare(sampler, levelFilter, ref, s, offset);
2604 float t1 = levels[level1].sample1DCompare(sampler, levelFilter, ref, s, offset);
2605
2606 return t0*(1.0f - f) + t1*f;
2607 }
2608
2609 default:
2610 DE_ASSERT(DE_FALSE);
2611 return 0.0f;
2612 }
2613 }
2614
sampleLevelArray2DCompare(const ConstPixelBufferAccess * levels,int numLevels,const Sampler & sampler,float ref,float s,float t,float lod,const IVec3 & offset)2615 float sampleLevelArray2DCompare (const ConstPixelBufferAccess* levels, int numLevels, const Sampler& sampler, float ref, float s, float t, float lod, const IVec3& offset)
2616 {
2617 bool magnified = lod <= sampler.lodThreshold;
2618 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2619
2620 switch (filterMode)
2621 {
2622 case Sampler::NEAREST: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
2623 case Sampler::LINEAR: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
2624
2625 case Sampler::NEAREST_MIPMAP_NEAREST:
2626 case Sampler::LINEAR_MIPMAP_NEAREST:
2627 {
2628 int maxLevel = (int)numLevels-1;
2629 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2630 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2631
2632 return levels[level].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2633 }
2634
2635 case Sampler::NEAREST_MIPMAP_LINEAR:
2636 case Sampler::LINEAR_MIPMAP_LINEAR:
2637 {
2638 int maxLevel = (int)numLevels-1;
2639 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2640 int level1 = de::min(maxLevel, level0 + 1);
2641 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2642 float f = deFloatFrac(lod);
2643 float t0 = levels[level0].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2644 float t1 = levels[level1].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
2645
2646 return t0*(1.0f - f) + t1*f;
2647 }
2648
2649 default:
2650 DE_ASSERT(DE_FALSE);
2651 return 0.0f;
2652 }
2653 }
2654
fetchGatherArray2DOffsets(const ConstPixelBufferAccess & src,const Sampler & sampler,float s,float t,int depth,int componentNdx,const IVec2 (& offsets)[4])2655 static Vec4 fetchGatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
2656 {
2657 DE_ASSERT(de::inBounds(componentNdx, 0, 4));
2658
2659 const int w = src.getWidth();
2660 const int h = src.getHeight();
2661 const float u = unnormalize(sampler.wrapS, s, w);
2662 const float v = unnormalize(sampler.wrapT, t, h);
2663 const int x0 = deFloorFloatToInt32(u-0.5f);
2664 const int y0 = deFloorFloatToInt32(v-0.5f);
2665
2666 Vec4 result;
2667
2668 for (int i = 0; i < 4; i++)
2669 {
2670 const int sampleX = wrap(sampler.wrapS, x0 + offsets[i].x(), w);
2671 const int sampleY = wrap(sampler.wrapT, y0 + offsets[i].y(), h);
2672 Vec4 pixel;
2673
2674 if (deInBounds32(sampleX, 0, w) && deInBounds32(sampleY, 0, h))
2675 pixel = lookup(src, sampleX, sampleY, depth);
2676 else
2677 pixel = lookupBorder(src.getFormat(), sampler);
2678
2679 result[i] = pixel[componentNdx];
2680 }
2681
2682 return result;
2683 }
2684
gatherArray2DOffsets(const ConstPixelBufferAccess & src,const Sampler & sampler,float s,float t,int depth,int componentNdx,const IVec2 (& offsets)[4])2685 Vec4 gatherArray2DOffsets (const ConstPixelBufferAccess& src, const Sampler& sampler, float s, float t, int depth, int componentNdx, const IVec2 (&offsets)[4])
2686 {
2687 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
2688 DE_ASSERT(de::inBounds(componentNdx, 0, 4));
2689
2690 return fetchGatherArray2DOffsets(src, sampler, s, t, depth, componentNdx, offsets);
2691 }
2692
gatherArray2DOffsetsCompare(const ConstPixelBufferAccess & src,const Sampler & sampler,float ref,float s,float t,int depth,const IVec2 (& offsets)[4])2693 Vec4 gatherArray2DOffsetsCompare (const ConstPixelBufferAccess& src, const Sampler& sampler, float ref, float s, float t, int depth, const IVec2 (&offsets)[4])
2694 {
2695 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
2696 DE_ASSERT(src.getFormat().order == TextureFormat::D || src.getFormat().order == TextureFormat::DS);
2697 DE_ASSERT(sampler.compareChannel == 0);
2698
2699 const bool isFixedPoint = isFixedPointDepthTextureFormat(src.getFormat());
2700 const Vec4 gathered = fetchGatherArray2DOffsets(src, sampler, s, t, depth, 0 /* component 0: depth */, offsets);
2701 Vec4 result;
2702
2703 for (int i = 0; i < 4; i++)
2704 result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
2705
2706 return result;
2707 }
2708
sampleCubeSeamlessNearest(const ConstPixelBufferAccess & faceAccess,const Sampler & sampler,float s,float t,int depth)2709 static Vec4 sampleCubeSeamlessNearest (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float s, float t, int depth)
2710 {
2711 Sampler clampingSampler = sampler;
2712 clampingSampler.wrapS = Sampler::CLAMP_TO_EDGE;
2713 clampingSampler.wrapT = Sampler::CLAMP_TO_EDGE;
2714 return faceAccess.sample2D(clampingSampler, Sampler::NEAREST, s, t, depth);
2715 }
2716
selectCubeFace(const Vec3 & coords)2717 CubeFace selectCubeFace (const Vec3& coords)
2718 {
2719 const float x = coords.x();
2720 const float y = coords.y();
2721 const float z = coords.z();
2722 const float ax = deFloatAbs(x);
2723 const float ay = deFloatAbs(y);
2724 const float az = deFloatAbs(z);
2725
2726 if (ay < ax && az < ax)
2727 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2728 else if (ax < ay && az < ay)
2729 return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2730 else if (ax < az && ay < az)
2731 return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2732 else
2733 {
2734 // Some of the components are equal. Use tie-breaking rule.
2735 if (ax == ay)
2736 {
2737 if (ax < az)
2738 return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2739 else
2740 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2741 }
2742 else if (ax == az)
2743 {
2744 if (az < ay)
2745 return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2746 else
2747 return z >= 0.0f ? CUBEFACE_POSITIVE_Z : CUBEFACE_NEGATIVE_Z;
2748 }
2749 else if (ay == az)
2750 {
2751 if (ay < ax)
2752 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2753 else
2754 return y >= 0.0f ? CUBEFACE_POSITIVE_Y : CUBEFACE_NEGATIVE_Y;
2755 }
2756 else
2757 return x >= 0.0f ? CUBEFACE_POSITIVE_X : CUBEFACE_NEGATIVE_X;
2758 }
2759 }
2760
projectToFace(CubeFace face,const Vec3 & coord)2761 Vec2 projectToFace (CubeFace face, const Vec3& coord)
2762 {
2763 const float rx = coord.x();
2764 const float ry = coord.y();
2765 const float rz = coord.z();
2766 float sc = 0.0f;
2767 float tc = 0.0f;
2768 float ma = 0.0f;
2769 float s;
2770 float t;
2771
2772 switch (face)
2773 {
2774 case CUBEFACE_NEGATIVE_X: sc = +rz; tc = -ry; ma = -rx; break;
2775 case CUBEFACE_POSITIVE_X: sc = -rz; tc = -ry; ma = +rx; break;
2776 case CUBEFACE_NEGATIVE_Y: sc = +rx; tc = -rz; ma = -ry; break;
2777 case CUBEFACE_POSITIVE_Y: sc = +rx; tc = +rz; ma = +ry; break;
2778 case CUBEFACE_NEGATIVE_Z: sc = -rx; tc = -ry; ma = -rz; break;
2779 case CUBEFACE_POSITIVE_Z: sc = +rx; tc = -ry; ma = +rz; break;
2780 default:
2781 DE_ASSERT(DE_FALSE);
2782 }
2783
2784 // Compute s, t
2785 s = ((sc / ma) + 1.0f) / 2.0f;
2786 t = ((tc / ma) + 1.0f) / 2.0f;
2787
2788 return Vec2(s, t);
2789 }
2790
getCubeFaceCoords(const Vec3 & coords)2791 CubeFaceFloatCoords getCubeFaceCoords (const Vec3& coords)
2792 {
2793 const CubeFace face = selectCubeFace(coords);
2794 return CubeFaceFloatCoords(face, projectToFace(face, coords));
2795 }
2796
2797 // Checks if origCoords.coords is in bounds defined by size; if not, return a CubeFaceIntCoords with face set to the appropriate neighboring face and coords transformed accordingly.
2798 // \note If both x and y in origCoords.coords are out of bounds, this returns with face CUBEFACE_LAST, signifying that there is no unique neighboring face.
remapCubeEdgeCoords(const CubeFaceIntCoords & origCoords,int size)2799 CubeFaceIntCoords remapCubeEdgeCoords (const CubeFaceIntCoords& origCoords, int size)
2800 {
2801 bool uInBounds = de::inBounds(origCoords.s, 0, size);
2802 bool vInBounds = de::inBounds(origCoords.t, 0, size);
2803
2804 if (uInBounds && vInBounds)
2805 return origCoords;
2806
2807 if (!uInBounds && !vInBounds)
2808 return CubeFaceIntCoords(CUBEFACE_LAST, -1, -1);
2809
2810 IVec2 coords(wrap(Sampler::CLAMP_TO_BORDER, origCoords.s, size),
2811 wrap(Sampler::CLAMP_TO_BORDER, origCoords.t, size));
2812 IVec3 canonizedCoords;
2813
2814 // Map the uv coordinates to canonized 3d coordinates.
2815
2816 switch (origCoords.face)
2817 {
2818 case CUBEFACE_NEGATIVE_X: canonizedCoords = IVec3(0, size-1-coords.y(), coords.x()); break;
2819 case CUBEFACE_POSITIVE_X: canonizedCoords = IVec3(size-1, size-1-coords.y(), size-1-coords.x()); break;
2820 case CUBEFACE_NEGATIVE_Y: canonizedCoords = IVec3(coords.x(), 0, size-1-coords.y()); break;
2821 case CUBEFACE_POSITIVE_Y: canonizedCoords = IVec3(coords.x(), size-1, coords.y()); break;
2822 case CUBEFACE_NEGATIVE_Z: canonizedCoords = IVec3(size-1-coords.x(), size-1-coords.y(), 0); break;
2823 case CUBEFACE_POSITIVE_Z: canonizedCoords = IVec3(coords.x(), size-1-coords.y(), size-1); break;
2824 default: DE_ASSERT(false);
2825 }
2826
2827 // Find an appropriate face to re-map the coordinates to.
2828
2829 if (canonizedCoords.x() == -1)
2830 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_X, IVec2(canonizedCoords.z(), size-1-canonizedCoords.y()));
2831
2832 if (canonizedCoords.x() == size)
2833 return CubeFaceIntCoords(CUBEFACE_POSITIVE_X, IVec2(size-1-canonizedCoords.z(), size-1-canonizedCoords.y()));
2834
2835 if (canonizedCoords.y() == -1)
2836 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Y, IVec2(canonizedCoords.x(), size-1-canonizedCoords.z()));
2837
2838 if (canonizedCoords.y() == size)
2839 return CubeFaceIntCoords(CUBEFACE_POSITIVE_Y, IVec2(canonizedCoords.x(), canonizedCoords.z()));
2840
2841 if (canonizedCoords.z() == -1)
2842 return CubeFaceIntCoords(CUBEFACE_NEGATIVE_Z, IVec2(size-1-canonizedCoords.x(), size-1-canonizedCoords.y()));
2843
2844 if (canonizedCoords.z() == size)
2845 return CubeFaceIntCoords(CUBEFACE_POSITIVE_Z, IVec2(canonizedCoords.x(), size-1-canonizedCoords.y()));
2846
2847 DE_ASSERT(false);
2848 return CubeFaceIntCoords(CUBEFACE_LAST, IVec2(-1));
2849 }
2850
getCubeLinearSamples(const ConstPixelBufferAccess (& faceAccesses)[CUBEFACE_LAST],CubeFace baseFace,float u,float v,int depth,Vec4 (& dst)[4])2851 static void getCubeLinearSamples (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, float u, float v, int depth, Vec4 (&dst)[4])
2852 {
2853 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2854 int size = faceAccesses[0].getWidth();
2855 int x0 = deFloorFloatToInt32(u-0.5f);
2856 int x1 = x0+1;
2857 int y0 = deFloorFloatToInt32(v-0.5f);
2858 int y1 = y0+1;
2859 IVec2 baseSampleCoords[4] =
2860 {
2861 IVec2(x0, y0),
2862 IVec2(x1, y0),
2863 IVec2(x0, y1),
2864 IVec2(x1, y1)
2865 };
2866 Vec4 sampleColors[4];
2867 bool hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
2868
2869 // Find correct faces and coordinates for out-of-bounds sample coordinates.
2870
2871 for (int i = 0; i < 4; i++)
2872 {
2873 CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
2874 hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
2875 if (!hasBothCoordsOutOfBounds[i])
2876 sampleColors[i] = lookup(faceAccesses[coords.face], coords.s, coords.t, depth);
2877 }
2878
2879 // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
2880 // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
2881 // requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
2882 // must have this color as well.
2883
2884 {
2885 int bothOutOfBoundsNdx = -1;
2886 for (int i = 0; i < 4; i++)
2887 {
2888 if (hasBothCoordsOutOfBounds[i])
2889 {
2890 DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
2891 bothOutOfBoundsNdx = i;
2892 }
2893 }
2894 if (bothOutOfBoundsNdx != -1)
2895 {
2896 sampleColors[bothOutOfBoundsNdx] = Vec4(0.0f);
2897 for (int i = 0; i < 4; i++)
2898 if (i != bothOutOfBoundsNdx)
2899 sampleColors[bothOutOfBoundsNdx] += sampleColors[i];
2900
2901 sampleColors[bothOutOfBoundsNdx] = sampleColors[bothOutOfBoundsNdx] * (1.0f/3.0f);
2902 }
2903 }
2904
2905 for (int i = 0; i < DE_LENGTH_OF_ARRAY(sampleColors); i++)
2906 dst[i] = sampleColors[i];
2907 }
2908
2909 // \todo [2014-02-19 pyry] Optimize faceAccesses
sampleCubeSeamlessLinear(const ConstPixelBufferAccess (& faceAccesses)[CUBEFACE_LAST],CubeFace baseFace,const Sampler & sampler,float s,float t,int depth)2910 static Vec4 sampleCubeSeamlessLinear (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float s, float t, int depth)
2911 {
2912 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
2913
2914 int size = faceAccesses[0].getWidth();
2915 // Non-normalized coordinates.
2916 float u = s;
2917 float v = t;
2918
2919 if (sampler.normalizedCoords)
2920 {
2921 u = unnormalize(sampler.wrapS, s, size);
2922 v = unnormalize(sampler.wrapT, t, size);
2923 }
2924
2925 // Get sample colors.
2926
2927 Vec4 sampleColors[4];
2928 getCubeLinearSamples(faceAccesses, baseFace, u, v, depth, sampleColors);
2929
2930 // Interpolate.
2931
2932 float a = deFloatFrac(u-0.5f);
2933 float b = deFloatFrac(v-0.5f);
2934
2935 return (sampleColors[0]*(1.0f-a)*(1.0f-b)) +
2936 (sampleColors[1]*( a)*(1.0f-b)) +
2937 (sampleColors[2]*(1.0f-a)*( b)) +
2938 (sampleColors[3]*( a)*( b));
2939 }
2940
sampleLevelArrayCubeSeamless(const ConstPixelBufferAccess * const (& faces)[CUBEFACE_LAST],int numLevels,CubeFace face,const Sampler & sampler,float s,float t,int depth,float lod)2941 static Vec4 sampleLevelArrayCubeSeamless (const ConstPixelBufferAccess* const (&faces)[CUBEFACE_LAST], int numLevels, CubeFace face, const Sampler& sampler, float s, float t, int depth, float lod)
2942 {
2943 bool magnified = lod <= sampler.lodThreshold;
2944 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
2945
2946 switch (filterMode)
2947 {
2948 case Sampler::NEAREST:
2949 return sampleCubeSeamlessNearest(faces[face][0], sampler, s, t, depth);
2950
2951 case Sampler::LINEAR:
2952 {
2953 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2954 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2955 faceAccesses[i] = faces[i][0];
2956
2957 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
2958 }
2959
2960 case Sampler::NEAREST_MIPMAP_NEAREST:
2961 case Sampler::LINEAR_MIPMAP_NEAREST:
2962 {
2963 int maxLevel = (int)numLevels-1;
2964 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
2965 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
2966
2967 if (levelFilter == Sampler::NEAREST)
2968 return sampleCubeSeamlessNearest(faces[face][level], sampler, s, t, depth);
2969 else
2970 {
2971 DE_ASSERT(levelFilter == Sampler::LINEAR);
2972
2973 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
2974 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
2975 faceAccesses[i] = faces[i][level];
2976
2977 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
2978 }
2979 }
2980
2981 case Sampler::NEAREST_MIPMAP_LINEAR:
2982 case Sampler::LINEAR_MIPMAP_LINEAR:
2983 {
2984 int maxLevel = (int)numLevels-1;
2985 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
2986 int level1 = de::min(maxLevel, level0 + 1);
2987 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
2988 float f = deFloatFrac(lod);
2989 Vec4 t0;
2990 Vec4 t1;
2991
2992 if (levelFilter == Sampler::NEAREST)
2993 {
2994 t0 = sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth);
2995 t1 = sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth);
2996 }
2997 else
2998 {
2999 DE_ASSERT(levelFilter == Sampler::LINEAR);
3000
3001 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3002 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3003 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3004 {
3005 faceAccesses0[i] = faces[i][level0];
3006 faceAccesses1[i] = faces[i][level1];
3007 }
3008
3009 t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, depth);
3010 t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, depth);
3011 }
3012
3013 return t0*(1.0f - f) + t1*f;
3014 }
3015
3016 default:
3017 DE_ASSERT(DE_FALSE);
3018 return Vec4(0.0f);
3019 }
3020 }
3021
sampleCubeSeamlessNearestCompare(const ConstPixelBufferAccess & faceAccess,const Sampler & sampler,float ref,float s,float t,int depth=0)3022 static float sampleCubeSeamlessNearestCompare (const ConstPixelBufferAccess& faceAccess, const Sampler& sampler, float ref, float s, float t, int depth = 0)
3023 {
3024 Sampler clampingSampler = sampler;
3025 clampingSampler.wrapS = Sampler::CLAMP_TO_EDGE;
3026 clampingSampler.wrapT = Sampler::CLAMP_TO_EDGE;
3027 return faceAccess.sample2DCompare(clampingSampler, Sampler::NEAREST, ref, s, t, IVec3(0, 0, depth));
3028 }
3029
sampleCubeSeamlessLinearCompare(const ConstPixelBufferAccess (& faceAccesses)[CUBEFACE_LAST],CubeFace baseFace,const Sampler & sampler,float ref,float s,float t)3030 static float sampleCubeSeamlessLinearCompare (const ConstPixelBufferAccess (&faceAccesses)[CUBEFACE_LAST], CubeFace baseFace, const Sampler& sampler, float ref, float s, float t)
3031 {
3032 DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
3033
3034 int size = faceAccesses[0].getWidth();
3035 // Non-normalized coordinates.
3036 float u = s;
3037 float v = t;
3038
3039 if (sampler.normalizedCoords)
3040 {
3041 u = unnormalize(sampler.wrapS, s, size);
3042 v = unnormalize(sampler.wrapT, t, size);
3043 }
3044
3045 int x0 = deFloorFloatToInt32(u-0.5f);
3046 int x1 = x0+1;
3047 int y0 = deFloorFloatToInt32(v-0.5f);
3048 int y1 = y0+1;
3049 IVec2 baseSampleCoords[4] =
3050 {
3051 IVec2(x0, y0),
3052 IVec2(x1, y0),
3053 IVec2(x0, y1),
3054 IVec2(x1, y1)
3055 };
3056 float sampleRes[4];
3057 bool hasBothCoordsOutOfBounds[4]; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
3058
3059 // Find correct faces and coordinates for out-of-bounds sample coordinates.
3060
3061 for (int i = 0; i < 4; i++)
3062 {
3063 CubeFaceIntCoords coords = remapCubeEdgeCoords(CubeFaceIntCoords(baseFace, baseSampleCoords[i]), size);
3064 hasBothCoordsOutOfBounds[i] = coords.face == CUBEFACE_LAST;
3065
3066 if (!hasBothCoordsOutOfBounds[i])
3067 {
3068 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(faceAccesses[coords.face].getFormat());
3069
3070 sampleRes[i] = execCompare(faceAccesses[coords.face].getPixel(coords.s, coords.t), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
3071 }
3072 }
3073
3074 // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
3075 // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
3076 // requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
3077 // must have this color as well.
3078
3079 {
3080 int bothOutOfBoundsNdx = -1;
3081 for (int i = 0; i < 4; i++)
3082 {
3083 if (hasBothCoordsOutOfBounds[i])
3084 {
3085 DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
3086 bothOutOfBoundsNdx = i;
3087 }
3088 }
3089 if (bothOutOfBoundsNdx != -1)
3090 {
3091 sampleRes[bothOutOfBoundsNdx] = 0.0f;
3092 for (int i = 0; i < 4; i++)
3093 if (i != bothOutOfBoundsNdx)
3094 sampleRes[bothOutOfBoundsNdx] += sampleRes[i];
3095
3096 sampleRes[bothOutOfBoundsNdx] = sampleRes[bothOutOfBoundsNdx] * (1.0f/3.0f);
3097 }
3098 }
3099
3100 // Interpolate.
3101
3102 float a = deFloatFrac(u-0.5f);
3103 float b = deFloatFrac(v-0.5f);
3104
3105 return (sampleRes[0]*(1.0f-a)*(1.0f-b)) +
3106 (sampleRes[1]*( a)*(1.0f-b)) +
3107 (sampleRes[2]*(1.0f-a)*( b)) +
3108 (sampleRes[3]*( a)*( b));
3109 }
3110
sampleLevelArrayCubeSeamlessCompare(const ConstPixelBufferAccess * const (& faces)[CUBEFACE_LAST],int numLevels,CubeFace face,const Sampler & sampler,float ref,float s,float t,float lod)3111 static float sampleLevelArrayCubeSeamlessCompare (const ConstPixelBufferAccess* const (&faces)[CUBEFACE_LAST], int numLevels, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod)
3112 {
3113 bool magnified = lod <= sampler.lodThreshold;
3114 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
3115
3116 switch (filterMode)
3117 {
3118 case Sampler::NEAREST:
3119 return sampleCubeSeamlessNearestCompare(faces[face][0], sampler, ref, s, t);
3120
3121 case Sampler::LINEAR:
3122 {
3123 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3124 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3125 faceAccesses[i] = faces[i][0];
3126
3127 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3128 }
3129
3130 case Sampler::NEAREST_MIPMAP_NEAREST:
3131 case Sampler::LINEAR_MIPMAP_NEAREST:
3132 {
3133 int maxLevel = (int)numLevels-1;
3134 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
3135 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
3136
3137 if (levelFilter == Sampler::NEAREST)
3138 return sampleCubeSeamlessNearestCompare(faces[face][level], sampler, ref, s, t);
3139 else
3140 {
3141 DE_ASSERT(levelFilter == Sampler::LINEAR);
3142
3143 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3144 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3145 faceAccesses[i] = faces[i][level];
3146
3147 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3148 }
3149 }
3150
3151 case Sampler::NEAREST_MIPMAP_LINEAR:
3152 case Sampler::LINEAR_MIPMAP_LINEAR:
3153 {
3154 int maxLevel = (int)numLevels-1;
3155 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
3156 int level1 = de::min(maxLevel, level0 + 1);
3157 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
3158 float f = deFloatFrac(lod);
3159 float t0;
3160 float t1;
3161
3162 if (levelFilter == Sampler::NEAREST)
3163 {
3164 t0 = sampleCubeSeamlessNearestCompare(faces[face][level0], sampler, ref, s, t);
3165 t1 = sampleCubeSeamlessNearestCompare(faces[face][level1], sampler, ref, s, t);
3166 }
3167 else
3168 {
3169 DE_ASSERT(levelFilter == Sampler::LINEAR);
3170
3171 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3172 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3173 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3174 {
3175 faceAccesses0[i] = faces[i][level0];
3176 faceAccesses1[i] = faces[i][level1];
3177 }
3178
3179 t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
3180 t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
3181 }
3182
3183 return t0*(1.0f - f) + t1*f;
3184 }
3185
3186 default:
3187 DE_ASSERT(DE_FALSE);
3188 return 0.0f;
3189 }
3190 }
3191
3192 // Cube map array sampling
3193
getCubeArrayFaceAccess(const ConstPixelBufferAccess * const levels,int levelNdx,int slice,CubeFace face)3194 static inline ConstPixelBufferAccess getCubeArrayFaceAccess (const ConstPixelBufferAccess* const levels, int levelNdx, int slice, CubeFace face)
3195 {
3196 const ConstPixelBufferAccess& level = levels[levelNdx];
3197 const int depth = (slice * 6) + getCubeArrayFaceIndex(face);
3198
3199 return getSubregion(level, 0, 0, depth, level.getWidth(), level.getHeight(), 1);
3200 }
3201
sampleCubeArraySeamless(const ConstPixelBufferAccess * const levels,int numLevels,int slice,CubeFace face,const Sampler & sampler,float s,float t,float lod)3202 static Vec4 sampleCubeArraySeamless (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float s, float t, float lod)
3203 {
3204 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(face);
3205 const bool magnified = lod <= sampler.lodThreshold;
3206 const Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
3207
3208 switch (filterMode)
3209 {
3210 case Sampler::NEAREST:
3211 return sampleCubeSeamlessNearest(levels[0], sampler, s, t, faceDepth);
3212
3213 case Sampler::LINEAR:
3214 {
3215 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3216 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3217 faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
3218
3219 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
3220 }
3221
3222 case Sampler::NEAREST_MIPMAP_NEAREST:
3223 case Sampler::LINEAR_MIPMAP_NEAREST:
3224 {
3225 int maxLevel = (int)numLevels-1;
3226 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
3227 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
3228
3229 if (levelFilter == Sampler::NEAREST)
3230 return sampleCubeSeamlessNearest(levels[level], sampler, s, t, faceDepth);
3231 else
3232 {
3233 DE_ASSERT(levelFilter == Sampler::LINEAR);
3234
3235 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3236 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3237 faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
3238
3239 return sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, 0);
3240 }
3241 }
3242
3243 case Sampler::NEAREST_MIPMAP_LINEAR:
3244 case Sampler::LINEAR_MIPMAP_LINEAR:
3245 {
3246 int maxLevel = (int)numLevels-1;
3247 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
3248 int level1 = de::min(maxLevel, level0 + 1);
3249 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
3250 float f = deFloatFrac(lod);
3251 Vec4 t0;
3252 Vec4 t1;
3253
3254 if (levelFilter == Sampler::NEAREST)
3255 {
3256 t0 = sampleCubeSeamlessNearest(levels[level0], sampler, s, t, faceDepth);
3257 t1 = sampleCubeSeamlessNearest(levels[level1], sampler, s, t, faceDepth);
3258 }
3259 else
3260 {
3261 DE_ASSERT(levelFilter == Sampler::LINEAR);
3262
3263 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3264 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3265 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3266 {
3267 faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
3268 faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
3269 }
3270
3271 t0 = sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, 0);
3272 t1 = sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, 0);
3273 }
3274
3275 return t0*(1.0f - f) + t1*f;
3276 }
3277
3278 default:
3279 DE_ASSERT(DE_FALSE);
3280 return Vec4(0.0f);
3281 }
3282 }
3283
sampleCubeArraySeamlessCompare(const ConstPixelBufferAccess * const levels,int numLevels,int slice,CubeFace face,const Sampler & sampler,float ref,float s,float t,float lod)3284 static float sampleCubeArraySeamlessCompare (const ConstPixelBufferAccess* const levels, int numLevels, int slice, CubeFace face, const Sampler& sampler, float ref, float s, float t, float lod)
3285 {
3286 const int faceDepth = (slice * 6) + getCubeArrayFaceIndex(face);
3287 const bool magnified = lod <= sampler.lodThreshold;
3288 Sampler::FilterMode filterMode = magnified ? sampler.magFilter : sampler.minFilter;
3289
3290 switch (filterMode)
3291 {
3292 case Sampler::NEAREST:
3293 return sampleCubeSeamlessNearestCompare(levels[0], sampler, ref, s, t, faceDepth);
3294
3295 case Sampler::LINEAR:
3296 {
3297 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3298 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3299 faceAccesses[i] = getCubeArrayFaceAccess(levels, 0, slice, (CubeFace)i);
3300
3301 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3302 }
3303
3304 case Sampler::NEAREST_MIPMAP_NEAREST:
3305 case Sampler::LINEAR_MIPMAP_NEAREST:
3306 {
3307 int maxLevel = (int)numLevels-1;
3308 int level = deClamp32((int)deFloatCeil(lod + 0.5f) - 1, 0, maxLevel);
3309 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_NEAREST) ? Sampler::LINEAR : Sampler::NEAREST;
3310
3311 if (levelFilter == Sampler::NEAREST)
3312 return sampleCubeSeamlessNearestCompare(levels[level], sampler, ref, s, t, faceDepth);
3313 else
3314 {
3315 DE_ASSERT(levelFilter == Sampler::LINEAR);
3316
3317 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3318 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3319 faceAccesses[i] = getCubeArrayFaceAccess(levels, level, slice, (CubeFace)i);
3320
3321 return sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
3322 }
3323 }
3324
3325 case Sampler::NEAREST_MIPMAP_LINEAR:
3326 case Sampler::LINEAR_MIPMAP_LINEAR:
3327 {
3328 int maxLevel = (int)numLevels-1;
3329 int level0 = deClamp32((int)deFloatFloor(lod), 0, maxLevel);
3330 int level1 = de::min(maxLevel, level0 + 1);
3331 Sampler::FilterMode levelFilter = (filterMode == Sampler::LINEAR_MIPMAP_LINEAR) ? Sampler::LINEAR : Sampler::NEAREST;
3332 float f = deFloatFrac(lod);
3333 float t0;
3334 float t1;
3335
3336 if (levelFilter == Sampler::NEAREST)
3337 {
3338 t0 = sampleCubeSeamlessNearestCompare(levels[level0], sampler, ref, s, t, faceDepth);
3339 t1 = sampleCubeSeamlessNearestCompare(levels[level1], sampler, ref, s, t, faceDepth);
3340 }
3341 else
3342 {
3343 DE_ASSERT(levelFilter == Sampler::LINEAR);
3344
3345 ConstPixelBufferAccess faceAccesses0[CUBEFACE_LAST];
3346 ConstPixelBufferAccess faceAccesses1[CUBEFACE_LAST];
3347 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3348 {
3349 faceAccesses0[i] = getCubeArrayFaceAccess(levels, level0, slice, (CubeFace)i);
3350 faceAccesses1[i] = getCubeArrayFaceAccess(levels, level1, slice, (CubeFace)i);
3351 }
3352
3353 t0 = sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
3354 t1 = sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
3355 }
3356
3357 return t0*(1.0f - f) + t1*f;
3358 }
3359
3360 default:
3361 DE_ASSERT(DE_FALSE);
3362 return 0.0f;
3363 }
3364 }
3365
computeMipPyramidLevels(int size)3366 inline int computeMipPyramidLevels (int size)
3367 {
3368 return deLog2Floor32(size)+1;
3369 }
3370
computeMipPyramidLevels(int width,int height)3371 inline int computeMipPyramidLevels (int width, int height)
3372 {
3373 return deLog2Floor32(de::max(width, height))+1;
3374 }
3375
computeMipPyramidLevels(int width,int height,int depth)3376 inline int computeMipPyramidLevels (int width, int height, int depth)
3377 {
3378 return deLog2Floor32(de::max(width, de::max(height, depth)))+1;
3379 }
3380
getMipPyramidLevelSize(int baseLevelSize,int levelNdx)3381 inline int getMipPyramidLevelSize (int baseLevelSize, int levelNdx)
3382 {
3383 return de::max(baseLevelSize >> levelNdx, 1);
3384 }
3385
3386 // TextureLevelPyramid
3387
TextureLevelPyramid(const TextureFormat & format,int numLevels)3388 TextureLevelPyramid::TextureLevelPyramid (const TextureFormat& format, int numLevels)
3389 : m_format (format)
3390 , m_data (numLevels)
3391 , m_access (numLevels)
3392 {
3393 }
3394
TextureLevelPyramid(const TextureLevelPyramid & other)3395 TextureLevelPyramid::TextureLevelPyramid (const TextureLevelPyramid& other)
3396 : m_format (other.m_format)
3397 , m_data (other.getNumLevels())
3398 , m_access (other.getNumLevels())
3399 {
3400 for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
3401 {
3402 if (!other.isLevelEmpty(levelNdx))
3403 {
3404 const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
3405
3406 m_data[levelNdx] = other.m_data[levelNdx];
3407 m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr());
3408 }
3409 }
3410 }
3411
operator =(const TextureLevelPyramid & other)3412 TextureLevelPyramid& TextureLevelPyramid::operator= (const TextureLevelPyramid& other)
3413 {
3414 if (this == &other)
3415 return *this;
3416
3417 m_format = other.m_format;
3418 m_data.resize(other.getNumLevels());
3419 m_access.resize(other.getNumLevels());
3420
3421 for (int levelNdx = 0; levelNdx < other.getNumLevels(); levelNdx++)
3422 {
3423 if (!other.isLevelEmpty(levelNdx))
3424 {
3425 const tcu::ConstPixelBufferAccess& srcLevel = other.getLevel(levelNdx);
3426
3427 m_data[levelNdx] = other.m_data[levelNdx];
3428 m_access[levelNdx] = PixelBufferAccess(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), m_data[levelNdx].getPtr());
3429 }
3430 else if (!isLevelEmpty(levelNdx))
3431 clearLevel(levelNdx);
3432 }
3433
3434 return *this;
3435 }
3436
~TextureLevelPyramid(void)3437 TextureLevelPyramid::~TextureLevelPyramid (void)
3438 {
3439 }
3440
allocLevel(int levelNdx,int width,int height,int depth)3441 void TextureLevelPyramid::allocLevel (int levelNdx, int width, int height, int depth)
3442 {
3443 const int size = m_format.getPixelSize()*width*height*depth;
3444
3445 DE_ASSERT(isLevelEmpty(levelNdx));
3446
3447 m_data[levelNdx].setStorage(size);
3448 m_access[levelNdx] = PixelBufferAccess(m_format, width, height, depth, m_data[levelNdx].getPtr());
3449 }
3450
clearLevel(int levelNdx)3451 void TextureLevelPyramid::clearLevel (int levelNdx)
3452 {
3453 DE_ASSERT(!isLevelEmpty(levelNdx));
3454
3455 m_data[levelNdx].clear();
3456 m_access[levelNdx] = PixelBufferAccess();
3457 }
3458
3459 // Texture1D
3460
Texture1D(const TextureFormat & format,int width)3461 Texture1D::Texture1D (const TextureFormat& format, int width)
3462 : TextureLevelPyramid (format, computeMipPyramidLevels(width))
3463 , m_width (width)
3464 , m_view (getNumLevels(), getLevels())
3465 {
3466 }
3467
Texture1D(const Texture1D & other)3468 Texture1D::Texture1D (const Texture1D& other)
3469 : TextureLevelPyramid (other)
3470 , m_width (other.m_width)
3471 , m_view (getNumLevels(), getLevels())
3472 {
3473 }
3474
operator =(const Texture1D & other)3475 Texture1D& Texture1D::operator= (const Texture1D& other)
3476 {
3477 if (this == &other)
3478 return *this;
3479
3480 TextureLevelPyramid::operator=(other);
3481
3482 m_width = other.m_width;
3483 m_view = Texture1DView(getNumLevels(), getLevels());
3484
3485 return *this;
3486 }
3487
~Texture1D(void)3488 Texture1D::~Texture1D (void)
3489 {
3490 }
3491
allocLevel(int levelNdx)3492 void Texture1D::allocLevel (int levelNdx)
3493 {
3494 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3495
3496 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3497
3498 TextureLevelPyramid::allocLevel(levelNdx, width, 1, 1);
3499 }
3500
3501 // Texture2D
3502
Texture2D(const TextureFormat & format,int width,int height,bool es2)3503 Texture2D::Texture2D (const TextureFormat& format, int width, int height, bool es2)
3504 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height))
3505 , m_width (width)
3506 , m_height (height)
3507 , m_view (getNumLevels(), getLevels(), es2)
3508 {
3509 }
3510
Texture2D(const TextureFormat & format,int width,int height,int mipmaps)3511 Texture2D::Texture2D (const TextureFormat& format, int width, int height, int mipmaps)
3512 : TextureLevelPyramid (format, mipmaps)
3513 , m_width (width)
3514 , m_height (height)
3515 , m_view (getNumLevels(), getLevels())
3516 {
3517 }
3518
Texture2D(const Texture2D & other)3519 Texture2D::Texture2D (const Texture2D& other)
3520 : TextureLevelPyramid (other)
3521 , m_width (other.m_width)
3522 , m_height (other.m_height)
3523 , m_view (getNumLevels(), getLevels(), other.getView().isES2())
3524 {
3525 }
3526
operator =(const Texture2D & other)3527 Texture2D& Texture2D::operator= (const Texture2D& other)
3528 {
3529 if (this == &other)
3530 return *this;
3531
3532 TextureLevelPyramid::operator=(other);
3533
3534 m_width = other.m_width;
3535 m_height = other.m_height;
3536 m_view = Texture2DView(getNumLevels(), getLevels(), other.getView().isES2());
3537
3538 return *this;
3539 }
3540
~Texture2D(void)3541 Texture2D::~Texture2D (void)
3542 {
3543 }
3544
allocLevel(int levelNdx)3545 void Texture2D::allocLevel (int levelNdx)
3546 {
3547 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3548
3549 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3550 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3551
3552 TextureLevelPyramid::allocLevel(levelNdx, width, height, 1);
3553 }
3554
3555 // TextureCubeView
3556
TextureCubeView(void)3557 TextureCubeView::TextureCubeView (void)
3558 : m_numLevels(0)
3559 {
3560 for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
3561 m_levels[ndx] = DE_NULL;
3562 }
3563
TextureCubeView(int numLevels,const ConstPixelBufferAccess * const (& levels)[CUBEFACE_LAST],bool es2)3564 TextureCubeView::TextureCubeView (int numLevels, const ConstPixelBufferAccess* const (&levels) [CUBEFACE_LAST], bool es2)
3565 : m_numLevels(numLevels)
3566 , m_es2(es2)
3567 {
3568 for (int ndx = 0; ndx < CUBEFACE_LAST; ndx++)
3569 m_levels[ndx] = levels[ndx];
3570 }
3571
sample(const Sampler & sampler,float s,float t,float r,float lod) const3572 tcu::Vec4 TextureCubeView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
3573 {
3574 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3575
3576 // Computes (face, s, t).
3577 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3578 if (sampler.seamlessCubeMap)
3579 return sampleLevelArrayCubeSeamless(m_levels, m_numLevels, coords.face, sampler, coords.s, coords.t, 0 /* depth */, lod);
3580 else
3581 return sampleLevelArray2D(m_levels[coords.face], m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod, m_es2);
3582 }
3583
sampleCompare(const Sampler & sampler,float ref,float s,float t,float r,float lod) const3584 float TextureCubeView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
3585 {
3586 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
3587
3588 // Computes (face, s, t).
3589 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3590 if (sampler.seamlessCubeMap)
3591 return sampleLevelArrayCubeSeamlessCompare(m_levels, m_numLevels, coords.face, sampler, ref, coords.s, coords.t, lod);
3592 else
3593 return sampleLevelArray2DCompare(m_levels[coords.face], m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, 0));
3594 }
3595
gather(const Sampler & sampler,float s,float t,float r,int componentNdx) const3596 Vec4 TextureCubeView::gather (const Sampler& sampler, float s, float t, float r, int componentNdx) const
3597 {
3598 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
3599
3600 ConstPixelBufferAccess faceAccesses[CUBEFACE_LAST];
3601 for (int i = 0; i < (int)CUBEFACE_LAST; i++)
3602 faceAccesses[i] = m_levels[i][0];
3603
3604 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
3605 const int size = faceAccesses[0].getWidth();
3606 // Non-normalized coordinates.
3607 float u = coords.s;
3608 float v = coords.t;
3609
3610 if (sampler.normalizedCoords)
3611 {
3612 u = unnormalize(sampler.wrapS, coords.s, size);
3613 v = unnormalize(sampler.wrapT, coords.t, size);
3614 }
3615
3616 Vec4 sampleColors[4];
3617 getCubeLinearSamples(faceAccesses, coords.face, u, v, 0, sampleColors);
3618
3619 const int sampleIndices[4] = { 2, 3, 1, 0 }; // \note Gather returns the samples in a non-obvious order.
3620 Vec4 result;
3621 for (int i = 0; i < 4; i++)
3622 result[i] = sampleColors[sampleIndices[i]][componentNdx];
3623
3624 return result;
3625 }
3626
gatherCompare(const Sampler & sampler,float ref,float s,float t,float r) const3627 Vec4 TextureCubeView::gatherCompare (const Sampler& sampler, float ref, float s, float t, float r) const
3628 {
3629 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
3630 DE_ASSERT(m_levels[0][0].getFormat().order == TextureFormat::D || m_levels[0][0].getFormat().order == TextureFormat::DS);
3631 DE_ASSERT(sampler.compareChannel == 0);
3632
3633 Sampler noCompareSampler = sampler;
3634 noCompareSampler.compare = Sampler::COMPAREMODE_NONE;
3635
3636 const Vec4 gathered = gather(noCompareSampler, s, t, r, 0 /* component 0: depth */);
3637 const bool isFixedPoint = isFixedPointDepthTextureFormat(m_levels[0][0].getFormat());
3638 Vec4 result;
3639 for (int i = 0; i < 4; i++)
3640 result[i] = execCompare(gathered, sampler.compare, i, ref, isFixedPoint);
3641
3642 return result;
3643 }
3644
3645 // TextureCube
3646
TextureCube(const TextureFormat & format,int size,bool es2)3647 TextureCube::TextureCube (const TextureFormat& format, int size, bool es2)
3648 : m_format (format)
3649 , m_size (size)
3650 {
3651 const int numLevels = computeMipPyramidLevels(m_size);
3652 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3653
3654 for (int face = 0; face < CUBEFACE_LAST; face++)
3655 {
3656 m_data[face].resize(numLevels);
3657 m_access[face].resize(numLevels);
3658 levels[face] = &m_access[face][0];
3659 }
3660
3661 m_view = TextureCubeView(numLevels, levels, es2);
3662 }
3663
TextureCube(const TextureCube & other)3664 TextureCube::TextureCube (const TextureCube& other)
3665 : m_format (other.m_format)
3666 , m_size (other.m_size)
3667 {
3668 const int numLevels = computeMipPyramidLevels(m_size);
3669 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3670
3671 for (int face = 0; face < CUBEFACE_LAST; face++)
3672 {
3673 m_data[face].resize(numLevels);
3674 m_access[face].resize(numLevels);
3675 levels[face] = &m_access[face][0];
3676 }
3677
3678 m_view = TextureCubeView(numLevels, levels, other.getView().isES2());
3679
3680 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
3681 {
3682 for (int face = 0; face < CUBEFACE_LAST; face++)
3683 {
3684 if (!other.isLevelEmpty((CubeFace)face, levelNdx))
3685 {
3686 allocLevel((CubeFace)face, levelNdx);
3687 copy(getLevelFace(levelNdx, (CubeFace)face),
3688 other.getLevelFace(levelNdx, (CubeFace)face));
3689 }
3690 }
3691 }
3692 }
3693
operator =(const TextureCube & other)3694 TextureCube& TextureCube::operator= (const TextureCube& other)
3695 {
3696 if (this == &other)
3697 return *this;
3698
3699 const int numLevels = computeMipPyramidLevels(other.m_size);
3700 const ConstPixelBufferAccess* levels[CUBEFACE_LAST];
3701
3702 for (int face = 0; face < CUBEFACE_LAST; face++)
3703 {
3704 m_data[face].resize(numLevels);
3705 m_access[face].resize(numLevels);
3706 levels[face] = &m_access[face][0];
3707 }
3708
3709 m_format = other.m_format;
3710 m_size = other.m_size;
3711 m_view = TextureCubeView(numLevels, levels, other.getView().isES2());
3712
3713 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
3714 {
3715 for (int face = 0; face < CUBEFACE_LAST; face++)
3716 {
3717 if (!isLevelEmpty((CubeFace)face, levelNdx))
3718 clearLevel((CubeFace)face, levelNdx);
3719
3720 if (!other.isLevelEmpty((CubeFace)face, levelNdx))
3721 {
3722 allocLevel((CubeFace)face, levelNdx);
3723 copy(getLevelFace(levelNdx, (CubeFace)face),
3724 other.getLevelFace(levelNdx, (CubeFace)face));
3725 }
3726 }
3727 }
3728
3729 return *this;
3730 }
3731
~TextureCube(void)3732 TextureCube::~TextureCube (void)
3733 {
3734 }
3735
allocLevel(tcu::CubeFace face,int levelNdx)3736 void TextureCube::allocLevel (tcu::CubeFace face, int levelNdx)
3737 {
3738 const int size = getMipPyramidLevelSize(m_size, levelNdx);
3739 const int dataSize = m_format.getPixelSize()*size*size;
3740 DE_ASSERT(isLevelEmpty(face, levelNdx));
3741
3742 m_data[face][levelNdx].setStorage(dataSize);
3743 m_access[face][levelNdx] = PixelBufferAccess(m_format, size, size, 1, m_data[face][levelNdx].getPtr());
3744 }
3745
clearLevel(tcu::CubeFace face,int levelNdx)3746 void TextureCube::clearLevel (tcu::CubeFace face, int levelNdx)
3747 {
3748 DE_ASSERT(!isLevelEmpty(face, levelNdx));
3749 m_data[face][levelNdx].clear();
3750 m_access[face][levelNdx] = PixelBufferAccess();
3751 }
3752
3753 // Texture1DArrayView
3754
Texture1DArrayView(int numLevels,const ConstPixelBufferAccess * levels,bool es2 DE_UNUSED_ATTR)3755 Texture1DArrayView::Texture1DArrayView (int numLevels, const ConstPixelBufferAccess* levels, bool es2 DE_UNUSED_ATTR)
3756 : m_numLevels (numLevels)
3757 , m_levels (levels)
3758 {
3759 }
3760
selectLayer(float r) const3761 inline int Texture1DArrayView::selectLayer (float r) const
3762 {
3763 DE_ASSERT(m_numLevels > 0 && m_levels);
3764 return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getHeight()-1);
3765 }
3766
sample(const Sampler & sampler,float s,float t,float lod) const3767 Vec4 Texture1DArrayView::sample (const Sampler& sampler, float s, float t, float lod) const
3768 {
3769 return sampleLevelArray1D(m_levels, m_numLevels, sampler, s, selectLayer(t), lod);
3770 }
3771
sampleOffset(const Sampler & sampler,float s,float t,float lod,deInt32 offset) const3772 Vec4 Texture1DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float lod, deInt32 offset) const
3773 {
3774 return sampleLevelArray1DOffset(m_levels, m_numLevels, sampler, s, lod, IVec2(offset, selectLayer(t)));
3775 }
3776
sampleCompare(const Sampler & sampler,float ref,float s,float t,float lod) const3777 float Texture1DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float lod) const
3778 {
3779 return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(0, selectLayer(t)));
3780 }
3781
sampleCompareOffset(const Sampler & sampler,float ref,float s,float t,float lod,deInt32 offset) const3782 float Texture1DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float lod, deInt32 offset) const
3783 {
3784 return sampleLevelArray1DCompare(m_levels, m_numLevels, sampler, ref, s, lod, IVec2(offset, selectLayer(t)));
3785 }
3786
3787 // Texture2DArrayView
3788
Texture2DArrayView(int numLevels,const ConstPixelBufferAccess * levels,bool es2 DE_UNUSED_ATTR)3789 Texture2DArrayView::Texture2DArrayView (int numLevels, const ConstPixelBufferAccess* levels, bool es2 DE_UNUSED_ATTR)
3790 : m_numLevels (numLevels)
3791 , m_levels (levels)
3792 {
3793 }
3794
selectLayer(float r) const3795 inline int Texture2DArrayView::selectLayer (float r) const
3796 {
3797 DE_ASSERT(m_numLevels > 0 && m_levels);
3798 return de::clamp(deFloorFloatToInt32(r + 0.5f), 0, m_levels[0].getDepth()-1);
3799 }
3800
sample(const Sampler & sampler,float s,float t,float r,float lod) const3801 Vec4 Texture2DArrayView::sample (const Sampler& sampler, float s, float t, float r, float lod) const
3802 {
3803 return sampleLevelArray2D(m_levels, m_numLevels, sampler, s, t, selectLayer(r), lod);
3804 }
3805
sampleCompare(const Sampler & sampler,float ref,float s,float t,float r,float lod) const3806 float Texture2DArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float lod) const
3807 {
3808 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(0, 0, selectLayer(r)));
3809 }
3810
sampleOffset(const Sampler & sampler,float s,float t,float r,float lod,const IVec2 & offset) const3811 Vec4 Texture2DArrayView::sampleOffset (const Sampler& sampler, float s, float t, float r, float lod, const IVec2& offset) const
3812 {
3813 return sampleLevelArray2DOffset(m_levels, m_numLevels, sampler, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
3814 }
3815
sampleCompareOffset(const Sampler & sampler,float ref,float s,float t,float r,float lod,const IVec2 & offset) const3816 float Texture2DArrayView::sampleCompareOffset (const Sampler& sampler, float ref, float s, float t, float r, float lod, const IVec2& offset) const
3817 {
3818 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, s, t, lod, IVec3(offset.x(), offset.y(), selectLayer(r)));
3819 }
3820
gatherOffsets(const Sampler & sampler,float s,float t,float r,int componentNdx,const IVec2 (& offsets)[4]) const3821 Vec4 Texture2DArrayView::gatherOffsets (const Sampler& sampler, float s, float t, float r, int componentNdx, const IVec2 (&offsets)[4]) const
3822 {
3823 return gatherArray2DOffsets(m_levels[0], sampler, s, t, selectLayer(r), componentNdx, offsets);
3824 }
3825
gatherOffsetsCompare(const Sampler & sampler,float ref,float s,float t,float r,const IVec2 (& offsets)[4]) const3826 Vec4 Texture2DArrayView::gatherOffsetsCompare (const Sampler& sampler, float ref, float s, float t, float r, const IVec2 (&offsets)[4]) const
3827 {
3828 return gatherArray2DOffsetsCompare(m_levels[0], sampler, ref, s, t, selectLayer(r), offsets);
3829 }
3830
3831 // Texture1DArray
3832
Texture1DArray(const TextureFormat & format,int width,int numLayers)3833 Texture1DArray::Texture1DArray (const TextureFormat& format, int width, int numLayers)
3834 : TextureLevelPyramid (format, computeMipPyramidLevels(width))
3835 , m_width (width)
3836 , m_numLayers (numLayers)
3837 , m_view (getNumLevels(), getLevels())
3838 {
3839 }
3840
Texture1DArray(const Texture1DArray & other)3841 Texture1DArray::Texture1DArray (const Texture1DArray& other)
3842 : TextureLevelPyramid (other)
3843 , m_width (other.m_width)
3844 , m_numLayers (other.m_numLayers)
3845 , m_view (getNumLevels(), getLevels())
3846 {
3847 }
3848
operator =(const Texture1DArray & other)3849 Texture1DArray& Texture1DArray::operator= (const Texture1DArray& other)
3850 {
3851 if (this == &other)
3852 return *this;
3853
3854 TextureLevelPyramid::operator=(other);
3855
3856 m_width = other.m_width;
3857 m_numLayers = other.m_numLayers;
3858 m_view = Texture1DArrayView(getNumLevels(), getLevels());
3859
3860 return *this;
3861 }
3862
~Texture1DArray(void)3863 Texture1DArray::~Texture1DArray (void)
3864 {
3865 }
3866
allocLevel(int levelNdx)3867 void Texture1DArray::allocLevel (int levelNdx)
3868 {
3869 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3870
3871 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3872
3873 TextureLevelPyramid::allocLevel(levelNdx, width, m_numLayers, 1);
3874 }
3875
3876 // Texture2DArray
3877
Texture2DArray(const TextureFormat & format,int width,int height,int numLayers)3878 Texture2DArray::Texture2DArray (const TextureFormat& format, int width, int height, int numLayers)
3879 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height))
3880 , m_width (width)
3881 , m_height (height)
3882 , m_numLayers (numLayers)
3883 , m_view (getNumLevels(), getLevels())
3884 {
3885 }
3886
Texture2DArray(const Texture2DArray & other)3887 Texture2DArray::Texture2DArray (const Texture2DArray& other)
3888 : TextureLevelPyramid (other)
3889 , m_width (other.m_width)
3890 , m_height (other.m_height)
3891 , m_numLayers (other.m_numLayers)
3892 , m_view (getNumLevels(), getLevels())
3893 {
3894 }
3895
operator =(const Texture2DArray & other)3896 Texture2DArray& Texture2DArray::operator= (const Texture2DArray& other)
3897 {
3898 if (this == &other)
3899 return *this;
3900
3901 TextureLevelPyramid::operator=(other);
3902
3903 m_width = other.m_width;
3904 m_height = other.m_height;
3905 m_numLayers = other.m_numLayers;
3906 m_view = Texture2DArrayView(getNumLevels(), getLevels());
3907
3908 return *this;
3909 }
3910
~Texture2DArray(void)3911 Texture2DArray::~Texture2DArray (void)
3912 {
3913 }
3914
allocLevel(int levelNdx)3915 void Texture2DArray::allocLevel (int levelNdx)
3916 {
3917 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3918
3919 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3920 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3921
3922 TextureLevelPyramid::allocLevel(levelNdx, width, height, m_numLayers);
3923 }
3924
3925 // Texture3DView
3926
Texture3DView(int numLevels,const ConstPixelBufferAccess * levels,bool es2 DE_UNUSED_ATTR)3927 Texture3DView::Texture3DView (int numLevels, const ConstPixelBufferAccess* levels, bool es2 DE_UNUSED_ATTR)
3928 : m_numLevels (numLevels)
3929 , m_levels (levels)
3930 {
3931 }
3932
3933 // Texture3D
3934
Texture3D(const TextureFormat & format,int width,int height,int depth)3935 Texture3D::Texture3D (const TextureFormat& format, int width, int height, int depth)
3936 : TextureLevelPyramid (format, computeMipPyramidLevels(width, height, depth))
3937 , m_width (width)
3938 , m_height (height)
3939 , m_depth (depth)
3940 , m_view (getNumLevels(), getLevels())
3941 {
3942 }
3943
Texture3D(const Texture3D & other)3944 Texture3D::Texture3D (const Texture3D& other)
3945 : TextureLevelPyramid (other)
3946 , m_width (other.m_width)
3947 , m_height (other.m_height)
3948 , m_depth (other.m_depth)
3949 , m_view (getNumLevels(), getLevels())
3950 {
3951 }
3952
operator =(const Texture3D & other)3953 Texture3D& Texture3D::operator= (const Texture3D& other)
3954 {
3955 if (this == &other)
3956 return *this;
3957
3958 TextureLevelPyramid::operator=(other);
3959
3960 m_width = other.m_width;
3961 m_height = other.m_height;
3962 m_depth = other.m_depth;
3963 m_view = Texture3DView(getNumLevels(), getLevels());
3964
3965 return *this;
3966 }
3967
~Texture3D(void)3968 Texture3D::~Texture3D (void)
3969 {
3970 }
3971
allocLevel(int levelNdx)3972 void Texture3D::allocLevel (int levelNdx)
3973 {
3974 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
3975
3976 const int width = getMipPyramidLevelSize(m_width, levelNdx);
3977 const int height = getMipPyramidLevelSize(m_height, levelNdx);
3978 const int depth = getMipPyramidLevelSize(m_depth, levelNdx);
3979
3980 TextureLevelPyramid::allocLevel(levelNdx, width, height, depth);
3981 }
3982
3983 // TextureCubeArrayView
3984
TextureCubeArrayView(int numLevels,const ConstPixelBufferAccess * levels,bool es2 DE_UNUSED_ATTR)3985 TextureCubeArrayView::TextureCubeArrayView (int numLevels, const ConstPixelBufferAccess* levels, bool es2 DE_UNUSED_ATTR)
3986 : m_numLevels (numLevels)
3987 , m_levels (levels)
3988 {
3989 }
3990
selectLayer(float q) const3991 inline int TextureCubeArrayView::selectLayer (float q) const
3992 {
3993 DE_ASSERT(m_numLevels > 0 && m_levels);
3994 DE_ASSERT((m_levels[0].getDepth() % 6) == 0);
3995
3996 return de::clamp(deFloorFloatToInt32(q + 0.5f), 0, (m_levels[0].getDepth() / 6)-1);
3997 }
3998
sample(const Sampler & sampler,float s,float t,float r,float q,float lod) const3999 tcu::Vec4 TextureCubeArrayView::sample (const Sampler& sampler, float s, float t, float r, float q, float lod) const
4000 {
4001 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
4002 const int layer = selectLayer(q);
4003 const int faceDepth = (layer * 6) + getCubeArrayFaceIndex(coords.face);
4004
4005 DE_ASSERT(sampler.compare == Sampler::COMPAREMODE_NONE);
4006
4007 if (sampler.seamlessCubeMap)
4008 return sampleCubeArraySeamless(m_levels, m_numLevels, layer, coords.face, sampler, coords.s, coords.t, lod);
4009 else
4010 return sampleLevelArray2D(m_levels, m_numLevels, sampler, coords.s, coords.t, faceDepth, lod);
4011 }
4012
sampleCompare(const Sampler & sampler,float ref,float s,float t,float r,float q,float lod) const4013 float TextureCubeArrayView::sampleCompare (const Sampler& sampler, float ref, float s, float t, float r, float q, float lod) const
4014 {
4015 const CubeFaceFloatCoords coords = getCubeFaceCoords(Vec3(s, t, r));
4016 const int layer = selectLayer(q);
4017 const int faceDepth = (layer * 6) + getCubeArrayFaceIndex(coords.face);
4018
4019 DE_ASSERT(sampler.compare != Sampler::COMPAREMODE_NONE);
4020
4021 if (sampler.seamlessCubeMap)
4022 return sampleCubeArraySeamlessCompare(m_levels, m_numLevels, layer, coords.face, sampler, ref, coords.s, coords.t, lod);
4023 else
4024 return sampleLevelArray2DCompare(m_levels, m_numLevels, sampler, ref, coords.s, coords.t, lod, IVec3(0, 0, faceDepth));
4025 }
4026
4027 // TextureCubeArray
4028
TextureCubeArray(const TextureFormat & format,int size,int depth)4029 TextureCubeArray::TextureCubeArray (const TextureFormat& format, int size, int depth)
4030 : TextureLevelPyramid (format, computeMipPyramidLevels(size))
4031 , m_size (size)
4032 , m_depth (depth)
4033 , m_view (getNumLevels(), getLevels())
4034 {
4035 DE_ASSERT(m_depth % 6 == 0);
4036 }
4037
TextureCubeArray(const TextureCubeArray & other)4038 TextureCubeArray::TextureCubeArray (const TextureCubeArray& other)
4039 : TextureLevelPyramid (other)
4040 , m_size (other.m_size)
4041 , m_depth (other.m_depth)
4042 , m_view (getNumLevels(), getLevels())
4043 {
4044 DE_ASSERT(m_depth % 6 == 0);
4045 }
4046
operator =(const TextureCubeArray & other)4047 TextureCubeArray& TextureCubeArray::operator= (const TextureCubeArray& other)
4048 {
4049 if (this == &other)
4050 return *this;
4051
4052 TextureLevelPyramid::operator=(other);
4053
4054 m_size = other.m_size;
4055 m_depth = other.m_depth;
4056 m_view = TextureCubeArrayView(getNumLevels(), getLevels());
4057
4058 DE_ASSERT(m_depth % 6 == 0);
4059
4060 return *this;
4061 }
4062
~TextureCubeArray(void)4063 TextureCubeArray::~TextureCubeArray (void)
4064 {
4065 }
4066
allocLevel(int levelNdx)4067 void TextureCubeArray::allocLevel (int levelNdx)
4068 {
4069 DE_ASSERT(de::inBounds(levelNdx, 0, getNumLevels()));
4070
4071 const int size = getMipPyramidLevelSize(m_size, levelNdx);
4072
4073 TextureLevelPyramid::allocLevel(levelNdx, size, size, m_depth);
4074 }
4075
operator <<(std::ostream & str,TextureFormat::ChannelOrder order)4076 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelOrder order)
4077 {
4078 const char* const orderStrings[] =
4079 {
4080 "R",
4081 "A",
4082 "I",
4083 "L",
4084 "LA",
4085 "RG",
4086 "RA",
4087 "RGB",
4088 "RGBA",
4089 "ARGB",
4090 "ABGR",
4091 "BGR",
4092 "BGRA",
4093
4094 "sR",
4095 "sRG",
4096 "sRGB",
4097 "sRGBA",
4098 "sBGR",
4099 "sBGRA",
4100
4101 "D",
4102 "S",
4103 "DS"
4104 };
4105
4106 return str << de::getSizedArrayElement<TextureFormat::CHANNELORDER_LAST>(orderStrings, order);
4107 }
4108
operator <<(std::ostream & str,TextureFormat::ChannelType type)4109 std::ostream& operator<< (std::ostream& str, TextureFormat::ChannelType type)
4110 {
4111 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
4112
4113 const char* const typeStrings[] =
4114 {
4115 "SNORM_INT8",
4116 "SNORM_INT16",
4117 "SNORM_INT32",
4118 "UNORM_INT8",
4119 "UNORM_INT16",
4120 "UNORM_INT24",
4121 "UNORM_INT32",
4122 "UNORM_BYTE_44",
4123 "UNORM_SHORT_565",
4124 "UNORM_SHORT_555",
4125 "UNORM_SHORT_4444",
4126 "UNORM_SHORT_5551",
4127 "UNORM_SHORT_1555",
4128 "UNORM_INT_101010",
4129 "SNORM_INT_1010102_REV",
4130 "UNORM_INT_1010102_REV",
4131 "UNSIGNED_BYTE_44",
4132 "UNSIGNED_SHORT_565",
4133 "UNSIGNED_SHORT_4444",
4134 "UNSIGNED_SHORT_5551",
4135 "SIGNED_INT_1010102_REV",
4136 "UNSIGNED_INT_1010102_REV",
4137 "UNSIGNED_INT_11F_11F_10F_REV",
4138 "UNSIGNED_INT_999_E5_REV",
4139 "UNSIGNED_INT_16_8_8",
4140 "UNSIGNED_INT_24_8",
4141 "UNSIGNED_INT_24_8_REV",
4142 "SIGNED_INT8",
4143 "SIGNED_INT16",
4144 "SIGNED_INT32",
4145 "SIGNED_INT64",
4146 "UNSIGNED_INT8",
4147 "UNSIGNED_INT16",
4148 "UNSIGNED_INT24",
4149 "UNSIGNED_INT32",
4150 "UNSIGNED_INT64",
4151 "HALF_FLOAT",
4152 "FLOAT",
4153 "FLOAT64",
4154 "FLOAT_UNSIGNED_INT_24_8_REV",
4155 "UNORM_SHORT_10",
4156 "UNORM_SHORT_12",
4157 "USCALED_INT8",
4158 "USCALED_INT16",
4159 "SSCALED_INT8",
4160 "SSCALED_INT16",
4161 "USCALED_INT_1010102_REV",
4162 "SSCALED_INT_1010102_REV"
4163 };
4164
4165 return str << de::getSizedArrayElement<TextureFormat::CHANNELTYPE_LAST>(typeStrings, type);
4166 }
4167
operator <<(std::ostream & str,CubeFace face)4168 std::ostream& operator<< (std::ostream& str, CubeFace face)
4169 {
4170 switch (face)
4171 {
4172 case CUBEFACE_NEGATIVE_X: return str << "CUBEFACE_NEGATIVE_X";
4173 case CUBEFACE_POSITIVE_X: return str << "CUBEFACE_POSITIVE_X";
4174 case CUBEFACE_NEGATIVE_Y: return str << "CUBEFACE_NEGATIVE_Y";
4175 case CUBEFACE_POSITIVE_Y: return str << "CUBEFACE_POSITIVE_Y";
4176 case CUBEFACE_NEGATIVE_Z: return str << "CUBEFACE_NEGATIVE_Z";
4177 case CUBEFACE_POSITIVE_Z: return str << "CUBEFACE_POSITIVE_Z";
4178 case CUBEFACE_LAST: return str << "CUBEFACE_LAST";
4179 default: return str << "UNKNOWN(" << (int)face << ")";
4180 }
4181 }
4182
operator <<(std::ostream & str,TextureFormat format)4183 std::ostream& operator<< (std::ostream& str, TextureFormat format)
4184 {
4185 return str << format.order << ", " << format.type << "";
4186 }
4187
operator <<(std::ostream & str,const ConstPixelBufferAccess & access)4188 std::ostream& operator<< (std::ostream& str, const ConstPixelBufferAccess& access)
4189 {
4190 return str << "format = (" << access.getFormat() << "), size = "
4191 << access.getWidth() << " x " << access.getHeight() << " x " << access.getDepth()
4192 << ", pitch = " << access.getRowPitch() << " / " << access.getSlicePitch();
4193 }
4194
4195 } // tcu
4196