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