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