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