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