• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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