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