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