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