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