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