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