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