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