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 Texture utilities.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuTextureUtil.hpp"
25 #include "tcuVectorUtil.hpp"
26 #include "deRandom.hpp"
27 #include "deMath.h"
28 #include "deMemory.h"
29
30 #include <limits>
31
32 namespace tcu
33 {
34
sRGBChannelToLinear(float cs)35 static inline float sRGBChannelToLinear (float cs)
36 {
37 if (cs <= 0.04045)
38 return cs / 12.92f;
39 else
40 return deFloatPow((cs + 0.055f) / 1.055f, 2.4f);
41 }
42
43 static const deUint32 s_srgb8Lut[256] =
44 {
45 #include "tcuSRGB8Lut.inl"
46 };
47
sRGB8ChannelToLinear(deUint32 cs)48 static inline float sRGB8ChannelToLinear (deUint32 cs)
49 {
50 DE_ASSERT(cs < 256);
51
52 // \note This triggers UB, but in practice it doesn't cause any problems
53 return ((const float*)s_srgb8Lut)[cs];
54 }
55
linearChannelToSRGB(float cl)56 static inline float linearChannelToSRGB (float cl)
57 {
58 if (cl <= 0.0f)
59 return 0.0f;
60 else if (cl < 0.0031308f)
61 return 12.92f*cl;
62 else if (cl < 1.0f)
63 return 1.055f*deFloatPow(cl, 0.41666f) - 0.055f;
64 else
65 return 1.0f;
66 }
67
68 //! Convert sRGB to linear colorspace
sRGBToLinear(const Vec4 & cs)69 Vec4 sRGBToLinear (const Vec4& cs)
70 {
71 return Vec4(sRGBChannelToLinear(cs[0]),
72 sRGBChannelToLinear(cs[1]),
73 sRGBChannelToLinear(cs[2]),
74 cs[3]);
75 }
76
sRGB8ToLinear(const UVec4 & cs)77 Vec4 sRGB8ToLinear (const UVec4& cs)
78 {
79 return Vec4(sRGB8ChannelToLinear(cs[0]),
80 sRGB8ChannelToLinear(cs[1]),
81 sRGB8ChannelToLinear(cs[2]),
82 1.0f);
83 }
84
sRGBA8ToLinear(const UVec4 & cs)85 Vec4 sRGBA8ToLinear (const UVec4& cs)
86 {
87 return Vec4(sRGB8ChannelToLinear(cs[0]),
88 sRGB8ChannelToLinear(cs[1]),
89 sRGB8ChannelToLinear(cs[2]),
90 (float)cs[3] / 255.0f);
91 }
92
93 //! Convert from linear to sRGB colorspace
linearToSRGB(const Vec4 & cl)94 Vec4 linearToSRGB (const Vec4& cl)
95 {
96 return Vec4(linearChannelToSRGB(cl[0]),
97 linearChannelToSRGB(cl[1]),
98 linearChannelToSRGB(cl[2]),
99 cl[3]);
100 }
101
isSRGB(TextureFormat format)102 bool isSRGB (TextureFormat format)
103 {
104 // make sure to update this if type table is updated
105 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
106
107 return format.order == TextureFormat::sR ||
108 format.order == TextureFormat::sRG ||
109 format.order == TextureFormat::sRGB ||
110 format.order == TextureFormat::sRGBA ||
111 format.order == TextureFormat::sBGR ||
112 format.order == TextureFormat::sBGRA;
113 }
114
linearToSRGBIfNeeded(const TextureFormat & format,const tcu::Vec4 & color)115 tcu::Vec4 linearToSRGBIfNeeded (const TextureFormat& format, const tcu::Vec4& color)
116 {
117 return isSRGB(format) ? linearToSRGB(color) : color;
118 }
119
isCombinedDepthStencilType(TextureFormat::ChannelType type)120 bool isCombinedDepthStencilType (TextureFormat::ChannelType type)
121 {
122 // make sure to update this if type table is updated
123 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
124
125 return type == TextureFormat::UNSIGNED_INT_16_8_8 ||
126 type == TextureFormat::UNSIGNED_INT_24_8 ||
127 type == TextureFormat::UNSIGNED_INT_24_8_REV ||
128 type == TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV;
129 }
130
hasStencilComponent(TextureFormat::ChannelOrder order)131 bool hasStencilComponent (TextureFormat::ChannelOrder order)
132 {
133 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
134
135 switch (order)
136 {
137 case TextureFormat::S:
138 case TextureFormat::DS:
139 return true;
140
141 default:
142 return false;
143 }
144 }
145
hasDepthComponent(TextureFormat::ChannelOrder order)146 bool hasDepthComponent (TextureFormat::ChannelOrder order)
147 {
148 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
149
150 switch (order)
151 {
152 case TextureFormat::D:
153 case TextureFormat::DS:
154 return true;
155
156 default:
157 return false;
158 }
159 }
160
161 //! Get texture channel class for format - how the values are stored (not how they are sampled)
getTextureChannelClass(TextureFormat::ChannelType channelType)162 TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType)
163 {
164 // make sure this table is updated if format table is updated
165 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
166
167 switch (channelType)
168 {
169 case TextureFormat::SNORM_INT8: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
170 case TextureFormat::SNORM_INT16: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
171 case TextureFormat::SNORM_INT32: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
172 case TextureFormat::UNORM_INT8: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
173 case TextureFormat::UNORM_INT16: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
174 case TextureFormat::UNORM_INT24: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
175 case TextureFormat::UNORM_INT32: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
176 case TextureFormat::UNORM_BYTE_44: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
177 case TextureFormat::UNORM_SHORT_565: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
178 case TextureFormat::UNORM_SHORT_555: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
179 case TextureFormat::UNORM_SHORT_4444: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
180 case TextureFormat::UNORM_SHORT_5551: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
181 case TextureFormat::UNORM_SHORT_1555: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
182 case TextureFormat::UNSIGNED_BYTE_44: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
183 case TextureFormat::UNSIGNED_SHORT_565: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
184 case TextureFormat::UNSIGNED_SHORT_4444: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
185 case TextureFormat::UNSIGNED_SHORT_5551: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
186 case TextureFormat::UNORM_INT_101010: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
187 case TextureFormat::SNORM_INT_1010102_REV: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
188 case TextureFormat::UNORM_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
189 case TextureFormat::SIGNED_INT_1010102_REV: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
190 case TextureFormat::UNSIGNED_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
191 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return TEXTURECHANNELCLASS_FLOATING_POINT;
192 case TextureFormat::UNSIGNED_INT_999_E5_REV: return TEXTURECHANNELCLASS_FLOATING_POINT;
193 case TextureFormat::UNSIGNED_INT_16_8_8: return TEXTURECHANNELCLASS_LAST; //!< packed unorm16-x8-uint8
194 case TextureFormat::UNSIGNED_INT_24_8: return TEXTURECHANNELCLASS_LAST; //!< packed unorm24-uint8
195 case TextureFormat::UNSIGNED_INT_24_8_REV: return TEXTURECHANNELCLASS_LAST; //!< packed unorm24-uint8
196 case TextureFormat::SIGNED_INT8: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
197 case TextureFormat::SIGNED_INT16: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
198 case TextureFormat::SIGNED_INT32: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
199 case TextureFormat::SIGNED_INT64: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
200 case TextureFormat::UNSIGNED_INT8: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
201 case TextureFormat::UNSIGNED_INT16: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
202 case TextureFormat::UNSIGNED_INT24: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
203 case TextureFormat::UNSIGNED_INT32: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
204 case TextureFormat::UNSIGNED_INT64: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
205 case TextureFormat::HALF_FLOAT: return TEXTURECHANNELCLASS_FLOATING_POINT;
206 case TextureFormat::FLOAT: return TEXTURECHANNELCLASS_FLOATING_POINT;
207 case TextureFormat::FLOAT64: return TEXTURECHANNELCLASS_FLOATING_POINT;
208 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return TEXTURECHANNELCLASS_LAST; //!< packed float32-pad24-uint8
209 case TextureFormat::UNORM_SHORT_10: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
210 case TextureFormat::UNORM_SHORT_12: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
211 case TextureFormat::USCALED_INT8: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
212 case TextureFormat::USCALED_INT16: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
213 case TextureFormat::SSCALED_INT8: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
214 case TextureFormat::SSCALED_INT16: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
215 case TextureFormat::USCALED_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
216 case TextureFormat::SSCALED_INT_1010102_REV: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
217 default:
218 DE_FATAL("Unknown channel type");
219 return TEXTURECHANNELCLASS_LAST;
220 }
221 }
222
isAccessValid(TextureFormat format,TextureAccessType type)223 bool isAccessValid (TextureFormat format, TextureAccessType type)
224 {
225 DE_ASSERT(isValid(format));
226
227 if (format.order == TextureFormat::DS)
228 {
229 // It is never allowed to access combined depth-stencil format with getPixel().
230 // Instead either getPixDepth() or getPixStencil(), or effective depth- or stencil-
231 // access must be used.
232 return false;
233 }
234 else if (format.order == TextureFormat::D)
235 return type == TEXTUREACCESSTYPE_FLOAT;
236 else if (format.order == TextureFormat::S)
237 return type == TEXTUREACCESSTYPE_UNSIGNED_INT;
238 else
239 {
240 // A few packed color formats have access type restrictions
241 if (format.type == TextureFormat::UNSIGNED_INT_11F_11F_10F_REV ||
242 format.type == TextureFormat::UNSIGNED_INT_999_E5_REV)
243 return type == TEXTUREACCESSTYPE_FLOAT;
244 else
245 return true;
246 }
247 }
248
249 /*--------------------------------------------------------------------*//*!
250 * \brief Get access to subregion of pixel buffer
251 * \param access Parent access object
252 * \param x X offset
253 * \param y Y offset
254 * \param z Z offset
255 * \param width Width
256 * \param height Height
257 * \param depth Depth
258 * \return Access object that targets given subregion of parent access object
259 *//*--------------------------------------------------------------------*/
getSubregion(const ConstPixelBufferAccess & access,int x,int y,int z,int width,int height,int depth)260 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
261 {
262 DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
263 DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
264
265 DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
266 DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
267
268 DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
269 DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth()));
270
271 return ConstPixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
272 (const deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
273 }
274
275 /*--------------------------------------------------------------------*//*!
276 * \brief Get access to subregion of pixel buffer
277 * \param access Parent access object
278 * \param x X offset
279 * \param y Y offset
280 * \param z Z offset
281 * \param width Width
282 * \param height Height
283 * \param depth Depth
284 * \return Access object that targets given subregion of parent access object
285 *//*--------------------------------------------------------------------*/
getSubregion(const PixelBufferAccess & access,int x,int y,int z,int width,int height,int depth)286 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
287 {
288 DE_ASSERT(de::inBounds(x, 0, access.getWidth()));
289 DE_ASSERT(de::inRange(x+width, x+1, access.getWidth()));
290
291 DE_ASSERT(de::inBounds(y, 0, access.getHeight()));
292 DE_ASSERT(de::inRange(y+height, y+1, access.getHeight()));
293
294 DE_ASSERT(de::inBounds(z, 0, access.getDepth()));
295 DE_ASSERT(de::inRange(z+depth, z+1, access.getDepth()));
296
297 return PixelBufferAccess(access.getFormat(), tcu::IVec3(width, height, depth), access.getPitch(),
298 (deUint8*)access.getDataPtr() + access.getPixelPitch()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
299 }
300
301 /*--------------------------------------------------------------------*//*!
302 * \brief Get access to subregion of pixel buffer
303 * \param access Parent access object
304 * \param x X offset
305 * \param y Y offset
306 * \param width Width
307 * \param height Height
308 * \return Access object that targets given subregion of parent access object
309 *//*--------------------------------------------------------------------*/
getSubregion(const PixelBufferAccess & access,int x,int y,int width,int height)310 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height)
311 {
312 return getSubregion(access, x, y, 0, width, height, 1);
313 }
314
315 /*--------------------------------------------------------------------*//*!
316 * \brief Get access to subregion of pixel buffer
317 * \param access Parent access object
318 * \param x X offset
319 * \param y Y offset
320 * \param width Width
321 * \param height Height
322 * \return Access object that targets given subregion of parent access object
323 *//*--------------------------------------------------------------------*/
getSubregion(const ConstPixelBufferAccess & access,int x,int y,int width,int height)324 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height)
325 {
326 return getSubregion(access, x, y, 0, width, height, 1);
327 }
328
329 /*--------------------------------------------------------------------*//*!
330 * \brief Flip rows in Y direction
331 * \param access Access object
332 * \return Modified access object where Y coordinates are reversed
333 *//*--------------------------------------------------------------------*/
flipYAccess(const PixelBufferAccess & access)334 PixelBufferAccess flipYAccess (const PixelBufferAccess& access)
335 {
336 const int rowPitch = access.getRowPitch();
337 const int offsetToLast = rowPitch*(access.getHeight()-1);
338 const tcu::IVec3 pitch (access.getPixelPitch(), -rowPitch, access.getSlicePitch());
339
340 return PixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
341 }
342
343 /*--------------------------------------------------------------------*//*!
344 * \brief Flip rows in Y direction
345 * \param access Access object
346 * \return Modified access object where Y coordinates are reversed
347 *//*--------------------------------------------------------------------*/
flipYAccess(const ConstPixelBufferAccess & access)348 ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access)
349 {
350 const int rowPitch = access.getRowPitch();
351 const int offsetToLast = rowPitch*(access.getHeight()-1);
352 const tcu::IVec3 pitch (access.getPixelPitch(), -rowPitch, access.getSlicePitch());
353
354 return ConstPixelBufferAccess(access.getFormat(), access.getSize(), pitch, (deUint8*)access.getDataPtr() + offsetToLast);
355 }
356
getFloatChannelValueRange(TextureFormat::ChannelType channelType)357 static Vec2 getFloatChannelValueRange (TextureFormat::ChannelType channelType)
358 {
359 // make sure this table is updated if format table is updated
360 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
361
362 float cMin = 0.0f;
363 float cMax = 0.0f;
364
365 switch (channelType)
366 {
367 // Signed normalized formats.
368 case TextureFormat::SNORM_INT8:
369 case TextureFormat::SNORM_INT16:
370 case TextureFormat::SNORM_INT32:
371 case TextureFormat::SNORM_INT_1010102_REV: cMin = -1.0f; cMax = 1.0f; break;
372
373 // Unsigned normalized formats.
374 case TextureFormat::UNORM_INT8:
375 case TextureFormat::UNORM_INT16:
376 case TextureFormat::UNORM_INT24:
377 case TextureFormat::UNORM_INT32:
378 case TextureFormat::UNORM_BYTE_44:
379 case TextureFormat::UNORM_SHORT_565:
380 case TextureFormat::UNORM_SHORT_555:
381 case TextureFormat::UNORM_SHORT_4444:
382 case TextureFormat::UNORM_SHORT_5551:
383 case TextureFormat::UNORM_SHORT_1555:
384 case TextureFormat::UNORM_INT_101010:
385 case TextureFormat::UNORM_INT_1010102_REV:
386 case TextureFormat::UNORM_SHORT_10:
387 case TextureFormat::UNORM_SHORT_12: cMin = 0.0f; cMax = 1.0f; break;
388
389 // Misc formats.
390 case TextureFormat::SIGNED_INT8: cMin = -128.0f; cMax = 127.0f; break;
391 case TextureFormat::SIGNED_INT16: cMin = -32768.0f; cMax = 32767.0f; break;
392 case TextureFormat::SIGNED_INT32: cMin = -2147483520.0f; cMax = 2147483520.0f; break; // Maximum exactly representable 31-bit integer: (2^24 - 1) * 2^7
393 case TextureFormat::UNSIGNED_INT8: cMin = 0.0f; cMax = 255.0f; break;
394 case TextureFormat::UNSIGNED_INT16: cMin = 0.0f; cMax = 65535.0f; break;
395 case TextureFormat::UNSIGNED_INT24: cMin = 0.0f; cMax = 16777215.0f; break;
396 case TextureFormat::UNSIGNED_INT32: cMin = 0.0f; cMax = 4294967040.f; break; // Maximum exactly representable 32-bit integer: (2^24 - 1) * 2^8
397 case TextureFormat::HALF_FLOAT: cMin = -1e3f; cMax = 1e3f; break;
398 case TextureFormat::FLOAT: cMin = -1e5f; cMax = 1e5f; break;
399 case TextureFormat::FLOAT64: cMin = -1e5f; cMax = 1e5f; break;
400 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: cMin = 0.0f; cMax = 1e4f; break;
401 case TextureFormat::UNSIGNED_INT_999_E5_REV: cMin = 0.0f; cMax = 1e5f; break;
402 case TextureFormat::UNSIGNED_BYTE_44: cMin = 0.0f; cMax = 15.f; break;
403 case TextureFormat::UNSIGNED_SHORT_4444: cMin = 0.0f; cMax = 15.f; break;
404 case TextureFormat::USCALED_INT8: cMin = 0.0f; cMax = 255.0f; break;
405 case TextureFormat::USCALED_INT16: cMin = 0.0f; cMax = 65535.0f; break;
406 case TextureFormat::SSCALED_INT8: cMin = -128.0f; cMax = 127.0f; break;
407 case TextureFormat::SSCALED_INT16: cMin = -32768.0f; cMax = 32767.0f; break;
408 case TextureFormat::USCALED_INT_1010102_REV: cMin = 0.0f; cMax = 1023.0f; break;
409 case TextureFormat::SSCALED_INT_1010102_REV: cMin = -512.0f; cMax = 511.0f; break;
410
411 default:
412 DE_ASSERT(false);
413 }
414
415 return Vec2(cMin, cMax);
416 }
417
418 /*--------------------------------------------------------------------*//*!
419 * \brief Get standard parameters for testing texture format
420 *
421 * Returns TextureFormatInfo that describes good parameters for exercising
422 * given TextureFormat. Parameters include value ranges per channel and
423 * suitable lookup scaling and bias in order to reduce result back to
424 * 0..1 range.
425 *//*--------------------------------------------------------------------*/
getTextureFormatInfo(const TextureFormat & format)426 TextureFormatInfo getTextureFormatInfo (const TextureFormat& format)
427 {
428 // Special cases.
429 if (format.type == TextureFormat::UNSIGNED_INT_1010102_REV)
430 return TextureFormatInfo(Vec4( 0.0f, 0.0f, 0.0f, 0.0f),
431 Vec4( 1023.0f, 1023.0f, 1023.0f, 3.0f),
432 Vec4(1.0f/1023.f, 1.0f/1023.0f, 1.0f/1023.0f, 1.0f/3.0f),
433 Vec4( 0.0f, 0.0f, 0.0f, 0.0f));
434 if (format.type == TextureFormat::SIGNED_INT_1010102_REV)
435 return TextureFormatInfo(Vec4( -512.0f, -512.0f, -512.0f, -2.0f),
436 Vec4( 511.0f, 511.0f, 511.0f, 1.0f),
437 Vec4(1.0f/1023.f, 1.0f/1023.0f, 1.0f/1023.0f, 1.0f/3.0f),
438 Vec4( 0.5f, 0.5f, 0.5f, 0.5f));
439 else if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
440 return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.0f),
441 Vec4(1.0f, 1.0f, 1.0f, 0.0f),
442 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
443 Vec4(0.0f, 0.0f, 0.0f, 0.0f)); // Depth / stencil formats.
444 else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551))
445 return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f),
446 Vec4(1.0f, 1.0f, 1.0f, 1.5f),
447 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
448 Vec4(0.0f, 0.0f, 0.0f, 0.0f));
449 else if (format.type == TextureFormat::UNSIGNED_SHORT_5551)
450 return TextureFormatInfo(Vec4( 0.0f, 0.0f, 0.0f, 0.0f),
451 Vec4( 31.0f, 31.0f, 31.0f, 1.0f),
452 Vec4(1.0f/31.f, 1.0f/31.0f, 1.0f/31.0f, 1.0f),
453 Vec4( 0.0f, 0.0f, 0.0f, 0.0f));
454 else if (format.type == TextureFormat::UNSIGNED_SHORT_565)
455 return TextureFormatInfo(Vec4( 0.0f, 0.0f, 0.0f, 0.0f),
456 Vec4( 31.0f, 63.0f, 31.0f, 0.0f),
457 Vec4(1.0f/31.f, 1.0f/63.0f, 1.0f/31.0f, 1.0f),
458 Vec4( 0.0f, 0.0f, 0.0f, 0.0f));
459
460 const Vec2 cRange = getFloatChannelValueRange(format.type);
461 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components;
462 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
463 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
464 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
465 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
466 const float scale = 1.0f / (cRange[1] - cRange[0]);
467 const float bias = -cRange[0] * scale;
468
469 return TextureFormatInfo(select(cRange[0], 0.0f, chnMask),
470 select(cRange[1], 0.0f, chnMask),
471 select(scale, 1.0f, chnMask),
472 select(bias, 0.0f, chnMask));
473 }
474
getFormatMinIntValue(const TextureFormat & format)475 IVec4 getFormatMinIntValue (const TextureFormat& format)
476 {
477 DE_ASSERT(getTextureChannelClass(format.type) == TEXTURECHANNELCLASS_SIGNED_INTEGER);
478
479 switch (format.type)
480 {
481 case TextureFormat::SIGNED_INT8: return IVec4(std::numeric_limits<deInt8>::min());
482 case TextureFormat::SIGNED_INT16: return IVec4(std::numeric_limits<deInt16>::min());
483 case TextureFormat::SIGNED_INT32: return IVec4(std::numeric_limits<deInt32>::min());
484
485 default:
486 DE_FATAL("Invalid channel type");
487 return IVec4(0);
488 }
489 }
490
getFormatMaxIntValue(const TextureFormat & format)491 IVec4 getFormatMaxIntValue (const TextureFormat& format)
492 {
493 DE_ASSERT(getTextureChannelClass(format.type) == TEXTURECHANNELCLASS_SIGNED_INTEGER);
494
495 if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT_1010102_REV) ||
496 format == TextureFormat(TextureFormat::BGRA, TextureFormat::SSCALED_INT_1010102_REV) ||
497 format == TextureFormat(TextureFormat::RGBA, TextureFormat::SSCALED_INT_1010102_REV) ||
498 format == TextureFormat(TextureFormat::BGRA, TextureFormat::SIGNED_INT_1010102_REV))
499 return IVec4(511, 511, 511, 1);
500
501 switch (format.type)
502 {
503 case TextureFormat::SIGNED_INT8: return IVec4(std::numeric_limits<deInt8>::max());
504 case TextureFormat::SIGNED_INT16: return IVec4(std::numeric_limits<deInt16>::max());
505 case TextureFormat::SIGNED_INT32: return IVec4(std::numeric_limits<deInt32>::max());
506
507 case TextureFormat::SSCALED_INT8: return IVec4(std::numeric_limits<deInt8>::max());
508 case TextureFormat::SSCALED_INT16: return IVec4(std::numeric_limits<deInt16>::max());
509
510 default:
511 DE_FATAL("Invalid channel type");
512 return IVec4(0);
513 }
514 }
515
getFormatMaxUintValue(const TextureFormat & format)516 UVec4 getFormatMaxUintValue (const TextureFormat& format)
517 {
518 DE_ASSERT(getTextureChannelClass(format.type) == TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
519
520 if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV) ||
521 format == TextureFormat(TextureFormat::RGBA, TextureFormat::USCALED_INT_1010102_REV) ||
522 format == TextureFormat(TextureFormat::BGRA, TextureFormat::USCALED_INT_1010102_REV) ||
523 format == TextureFormat(TextureFormat::BGRA, TextureFormat::UNSIGNED_INT_1010102_REV))
524 return UVec4(1023u, 1023u, 1023u, 3u);
525
526 switch (format.type)
527 {
528 case TextureFormat::UNSIGNED_INT8: return UVec4(std::numeric_limits<deUint8>::max());
529 case TextureFormat::UNSIGNED_INT16: return UVec4(std::numeric_limits<deUint16>::max());
530 case TextureFormat::UNSIGNED_INT24: return UVec4(0xffffffu);
531 case TextureFormat::UNSIGNED_INT32: return UVec4(std::numeric_limits<deUint32>::max());
532
533 case TextureFormat::USCALED_INT8: return UVec4(std::numeric_limits<deUint8>::max());
534 case TextureFormat::USCALED_INT16: return UVec4(std::numeric_limits<deUint16>::max());
535
536 default:
537 DE_FATAL("Invalid channel type");
538 return UVec4(0);
539 }
540 }
541
getChannelBitDepth(TextureFormat::ChannelType channelType)542 static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType)
543 {
544 // make sure this table is updated if format table is updated
545 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
546
547 switch (channelType)
548 {
549 case TextureFormat::SNORM_INT8: return IVec4(8);
550 case TextureFormat::SNORM_INT16: return IVec4(16);
551 case TextureFormat::SNORM_INT32: return IVec4(32);
552 case TextureFormat::UNORM_INT8: return IVec4(8);
553 case TextureFormat::UNORM_INT16: return IVec4(16);
554 case TextureFormat::UNORM_INT24: return IVec4(24);
555 case TextureFormat::UNORM_INT32: return IVec4(32);
556 case TextureFormat::UNORM_BYTE_44: return IVec4(4,4,0,0);
557 case TextureFormat::UNORM_SHORT_565: return IVec4(5,6,5,0);
558 case TextureFormat::UNORM_SHORT_4444: return IVec4(4);
559 case TextureFormat::UNORM_SHORT_555: return IVec4(5,5,5,0);
560 case TextureFormat::UNORM_SHORT_5551: return IVec4(5,5,5,1);
561 case TextureFormat::UNORM_SHORT_1555: return IVec4(1,5,5,5);
562 case TextureFormat::UNSIGNED_BYTE_44: return IVec4(4,4,0,0);
563 case TextureFormat::UNSIGNED_SHORT_565: return IVec4(5,6,5,0);
564 case TextureFormat::UNSIGNED_SHORT_4444: return IVec4(4);
565 case TextureFormat::UNSIGNED_SHORT_5551: return IVec4(5,5,5,1);
566 case TextureFormat::UNORM_INT_101010: return IVec4(10,10,10,0);
567 case TextureFormat::SNORM_INT_1010102_REV: return IVec4(10,10,10,2);
568 case TextureFormat::UNORM_INT_1010102_REV: return IVec4(10,10,10,2);
569 case TextureFormat::SIGNED_INT8: return IVec4(8);
570 case TextureFormat::SIGNED_INT16: return IVec4(16);
571 case TextureFormat::SIGNED_INT32: return IVec4(32);
572 case TextureFormat::UNSIGNED_INT8: return IVec4(8);
573 case TextureFormat::UNSIGNED_INT16: return IVec4(16);
574 case TextureFormat::UNSIGNED_INT24: return IVec4(24);
575 case TextureFormat::UNSIGNED_INT32: return IVec4(32);
576 case TextureFormat::SIGNED_INT_1010102_REV: return IVec4(10,10,10,2);
577 case TextureFormat::UNSIGNED_INT_1010102_REV: return IVec4(10,10,10,2);
578 case TextureFormat::UNSIGNED_INT_16_8_8: return IVec4(16,8,0,0);
579 case TextureFormat::UNSIGNED_INT_24_8: return IVec4(24,8,0,0);
580 case TextureFormat::UNSIGNED_INT_24_8_REV: return IVec4(24,8,0,0);
581 case TextureFormat::HALF_FLOAT: return IVec4(16);
582 case TextureFormat::FLOAT: return IVec4(32);
583 case TextureFormat::FLOAT64: return IVec4(64);
584 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return IVec4(11,11,10,0);
585 case TextureFormat::UNSIGNED_INT_999_E5_REV: return IVec4(9,9,9,0);
586 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return IVec4(32,8,0,0);
587 case TextureFormat::UNORM_SHORT_10: return IVec4(10);
588 case TextureFormat::UNORM_SHORT_12: return IVec4(12);
589 case TextureFormat::USCALED_INT8: return IVec4(8);
590 case TextureFormat::USCALED_INT16: return IVec4(16);
591 case TextureFormat::SSCALED_INT8: return IVec4(8);
592 case TextureFormat::SSCALED_INT16: return IVec4(16);
593 case TextureFormat::USCALED_INT_1010102_REV: return IVec4(10,10,10,2);
594 case TextureFormat::SSCALED_INT_1010102_REV: return IVec4(10,10,10,2);
595 default:
596 DE_ASSERT(false);
597 return IVec4(0);
598 }
599 }
600
getTextureFormatBitDepth(const TextureFormat & format)601 IVec4 getTextureFormatBitDepth (const TextureFormat& format)
602 {
603 const IVec4 chnBits = getChannelBitDepth(format.type);
604 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components;
605 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
606 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
607 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
608 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
609 const IVec4 chnSwz = IVec4((chnMask[0]) ? ((int)map[0]) : (0),
610 (chnMask[1]) ? ((int)map[1]) : (0),
611 (chnMask[2]) ? ((int)map[2]) : (0),
612 (chnMask[3]) ? ((int)map[3]) : (0));
613
614 return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
615 }
616
getChannelMantissaBitDepth(TextureFormat::ChannelType channelType)617 static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType)
618 {
619 // make sure this table is updated if format table is updated
620 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
621
622 switch (channelType)
623 {
624 case TextureFormat::SNORM_INT8:
625 case TextureFormat::SNORM_INT16:
626 case TextureFormat::SNORM_INT32:
627 case TextureFormat::UNORM_INT8:
628 case TextureFormat::UNORM_INT16:
629 case TextureFormat::UNORM_INT24:
630 case TextureFormat::UNORM_INT32:
631 case TextureFormat::UNORM_BYTE_44:
632 case TextureFormat::UNORM_SHORT_565:
633 case TextureFormat::UNORM_SHORT_4444:
634 case TextureFormat::UNORM_SHORT_555:
635 case TextureFormat::UNORM_SHORT_5551:
636 case TextureFormat::UNORM_SHORT_1555:
637 case TextureFormat::UNSIGNED_BYTE_44:
638 case TextureFormat::UNSIGNED_SHORT_565:
639 case TextureFormat::UNSIGNED_SHORT_4444:
640 case TextureFormat::UNSIGNED_SHORT_5551:
641 case TextureFormat::UNORM_INT_101010:
642 case TextureFormat::SNORM_INT_1010102_REV:
643 case TextureFormat::UNORM_INT_1010102_REV:
644 case TextureFormat::SIGNED_INT8:
645 case TextureFormat::SIGNED_INT16:
646 case TextureFormat::SIGNED_INT32:
647 case TextureFormat::UNSIGNED_INT8:
648 case TextureFormat::UNSIGNED_INT16:
649 case TextureFormat::UNSIGNED_INT24:
650 case TextureFormat::UNSIGNED_INT32:
651 case TextureFormat::SIGNED_INT_1010102_REV:
652 case TextureFormat::UNSIGNED_INT_1010102_REV:
653 case TextureFormat::UNSIGNED_INT_16_8_8:
654 case TextureFormat::UNSIGNED_INT_24_8:
655 case TextureFormat::UNSIGNED_INT_24_8_REV:
656 case TextureFormat::UNSIGNED_INT_999_E5_REV:
657 case TextureFormat::UNORM_SHORT_10:
658 case TextureFormat::UNORM_SHORT_12:
659 case TextureFormat::USCALED_INT8:
660 case TextureFormat::USCALED_INT16:
661 case TextureFormat::SSCALED_INT8:
662 case TextureFormat::SSCALED_INT16:
663 case TextureFormat::USCALED_INT_1010102_REV:
664 case TextureFormat::SSCALED_INT_1010102_REV:
665 return getChannelBitDepth(channelType);
666
667 case TextureFormat::HALF_FLOAT: return IVec4(10);
668 case TextureFormat::FLOAT: return IVec4(23);
669 case TextureFormat::FLOAT64: return IVec4(52);
670 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return IVec4(6,6,5,0);
671 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return IVec4(23,8,0,0);
672 default:
673 DE_ASSERT(false);
674 return IVec4(0);
675 }
676 }
677
getTextureFormatMantissaBitDepth(const TextureFormat & format)678 IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format)
679 {
680 const IVec4 chnBits = getChannelMantissaBitDepth(format.type);
681 const TextureSwizzle::Channel* map = getChannelReadSwizzle(format.order).components;
682 const BVec4 chnMask = BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
683 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
684 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
685 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
686 const IVec4 chnSwz = IVec4((chnMask[0]) ? ((int)map[0]) : (0),
687 (chnMask[1]) ? ((int)map[1]) : (0),
688 (chnMask[2]) ? ((int)map[2]) : (0),
689 (chnMask[3]) ? ((int)map[3]) : (0));
690
691 return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
692 }
693
getTextureFormatChannelMask(const TextureFormat & format)694 BVec4 getTextureFormatChannelMask (const TextureFormat& format)
695 {
696 const TextureSwizzle::Channel* const map = getChannelReadSwizzle(format.order).components;
697 return BVec4(deInRange32(map[0], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
698 deInRange32(map[1], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
699 deInRange32(map[2], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE,
700 deInRange32(map[3], TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE);
701 }
702
linearInterpolate(float t,float minVal,float maxVal)703 static inline float linearInterpolate (float t, float minVal, float maxVal)
704 {
705 return minVal + (maxVal - minVal) * t;
706 }
707
linearInterpolate(float t,const Vec4 & a,const Vec4 & b)708 static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b)
709 {
710 return a + (b - a) * t;
711 }
712
713 enum
714 {
715 CLEAR_OPTIMIZE_THRESHOLD = 128,
716 CLEAR_OPTIMIZE_MAX_PIXEL_SIZE = 8
717 };
718
fillRow(const PixelBufferAccess & dst,int y,int z,int pixelSize,const deUint8 * pixel)719 inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel)
720 {
721 DE_ASSERT(dst.getPixelPitch() == pixelSize); // only tightly packed
722
723 deUint8* dstPtr = (deUint8*)dst.getPixelPtr(0, y, z);
724 int width = dst.getWidth();
725
726 if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize))
727 {
728 deUint64 val;
729 memcpy(&val, pixel, sizeof(val));
730
731 for (int i = 0; i < width; i++)
732 ((deUint64*)dstPtr)[i] = val;
733 }
734 else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize))
735 {
736 deUint32 val;
737 memcpy(&val, pixel, sizeof(val));
738
739 for (int i = 0; i < width; i++)
740 ((deUint32*)dstPtr)[i] = val;
741 }
742 else
743 {
744 for (int i = 0; i < width; i++)
745 for (int j = 0; j < pixelSize; j++)
746 dstPtr[i*pixelSize+j] = pixel[j];
747 }
748 }
749
clear(const PixelBufferAccess & access,const Vec4 & color)750 void clear (const PixelBufferAccess& access, const Vec4& color)
751 {
752 const int pixelSize = access.getFormat().getPixelSize();
753 const int pixelPitch = access.getPixelPitch();
754 const bool rowPixelsTightlyPacked = (pixelSize == pixelPitch);
755
756 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
757 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
758 {
759 // Convert to destination format.
760 union
761 {
762 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
763 deUint64 u64; // Forces 64-bit alignment.
764 } pixel;
765 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
766 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
767
768 for (int z = 0; z < access.getDepth(); z++)
769 for (int y = 0; y < access.getHeight(); y++)
770 fillRow(access, y, z, pixelSize, &pixel.u8[0]);
771 }
772 else
773 {
774 for (int z = 0; z < access.getDepth(); z++)
775 for (int y = 0; y < access.getHeight(); y++)
776 for (int x = 0; x < access.getWidth(); x++)
777 access.setPixel(color, x, y, z);
778 }
779 }
780
clear(const PixelBufferAccess & access,const IVec4 & color)781 void clear (const PixelBufferAccess& access, const IVec4& color)
782 {
783 const int pixelSize = access.getFormat().getPixelSize();
784 const int pixelPitch = access.getPixelPitch();
785 const bool rowPixelsTightlyPacked = (pixelSize == pixelPitch);
786
787 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
788 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE && rowPixelsTightlyPacked)
789 {
790 // Convert to destination format.
791 union
792 {
793 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
794 deUint64 u64; // Forces 64-bit alignment.
795 } pixel;
796 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
797 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
798
799 for (int z = 0; z < access.getDepth(); z++)
800 for (int y = 0; y < access.getHeight(); y++)
801 fillRow(access, y, z, pixelSize, &pixel.u8[0]);
802 }
803 else
804 {
805 for (int z = 0; z < access.getDepth(); z++)
806 for (int y = 0; y < access.getHeight(); y++)
807 for (int x = 0; x < access.getWidth(); x++)
808 access.setPixel(color, x, y, z);
809 }
810 }
811
clear(const PixelBufferAccess & access,const UVec4 & color)812 void clear (const PixelBufferAccess& access, const UVec4& color)
813 {
814 clear(access, color.cast<deInt32>());
815 }
816
clearDepth(const PixelBufferAccess & access,float depth)817 void clearDepth (const PixelBufferAccess& access, float depth)
818 {
819 DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::D);
820
821 clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_DEPTH), tcu::Vec4(depth, 0.0f, 0.0f, 0.0f));
822 }
823
clearStencil(const PixelBufferAccess & access,int stencil)824 void clearStencil (const PixelBufferAccess& access, int stencil)
825 {
826 DE_ASSERT(access.getFormat().order == TextureFormat::DS || access.getFormat().order == TextureFormat::S);
827
828 clear(getEffectiveDepthStencilAccess(access, Sampler::MODE_STENCIL), tcu::UVec4(stencil, 0u, 0u, 0u));
829 }
830
831 enum GradientStyle
832 {
833 GRADIENT_STYLE_OLD = 0,
834 GRADIENT_STYLE_NEW = 1
835 };
836
fillWithComponentGradients1D(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal,GradientStyle)837 static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal, GradientStyle)
838 {
839 DE_ASSERT(access.getHeight() == 1);
840 for (int x = 0; x < access.getWidth(); x++)
841 {
842 float s = ((float)x + 0.5f) / (float)access.getWidth();
843
844 float r = linearInterpolate(s, minVal.x(), maxVal.x());
845 float g = linearInterpolate(s, minVal.y(), maxVal.y());
846 float b = linearInterpolate(s, minVal.z(), maxVal.z());
847 float a = linearInterpolate(s, minVal.w(), maxVal.w());
848
849 access.setPixel(tcu::Vec4(r, g, b, a), x, 0);
850 }
851 }
852
fillWithComponentGradients2D(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal,GradientStyle)853 static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal, GradientStyle)
854 {
855 for (int y = 0; y < access.getHeight(); y++)
856 {
857 for (int x = 0; x < access.getWidth(); x++)
858 {
859 float s = ((float)x + 0.5f) / (float)access.getWidth();
860 float t = ((float)y + 0.5f) / (float)access.getHeight();
861
862 float r = linearInterpolate(( s + t) *0.5f, minVal.x(), maxVal.x());
863 float g = linearInterpolate(( s + (1.0f-t))*0.5f, minVal.y(), maxVal.y());
864 float b = linearInterpolate(((1.0f-s) + t) *0.5f, minVal.z(), maxVal.z());
865 float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w());
866
867 access.setPixel(tcu::Vec4(r, g, b, a), x, y);
868 }
869 }
870 }
871
fillWithComponentGradients3D(const PixelBufferAccess & dst,const Vec4 & minVal,const Vec4 & maxVal,GradientStyle style)872 static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal, GradientStyle style)
873 {
874 for (int z = 0; z < dst.getDepth(); z++)
875 {
876 for (int y = 0; y < dst.getHeight(); y++)
877 {
878 for (int x = 0; x < dst.getWidth(); x++)
879 {
880 float s = ((float)x + 0.5f) / (float)dst.getWidth();
881 float t = ((float)y + 0.5f) / (float)dst.getHeight();
882 float p = ((float)z + 0.5f) / (float)dst.getDepth();
883
884 float r, g, b, a;
885
886 if (style == GRADIENT_STYLE_NEW)
887 {
888 // R, G, B and A all depend on every coordinate.
889 r = linearInterpolate((s+t+p)/3.0f, minVal.x(), maxVal.x());
890 g = linearInterpolate((s + (1.0f - (t+p)*0.5f)*2.0f)/3.0f, minVal.y(), maxVal.y());
891 b = linearInterpolate(((1.0f - (s+t)*0.5f)*2.0f + p)/3.0f, minVal.z(), maxVal.z());
892 a = linearInterpolate(1.0f - (s+t+p)/3.0f, minVal.w(), maxVal.w());
893 }
894 else // GRADIENT_STYLE_OLD
895 {
896 // Each of R, G and B only depend on X, Y and Z, respectively.
897 r = linearInterpolate(s, minVal.x(), maxVal.x());
898 g = linearInterpolate(t, minVal.y(), maxVal.y());
899 b = linearInterpolate(p, minVal.z(), maxVal.z());
900 a = linearInterpolate(1.0f - (s+t+p)/3.0f, minVal.w(), maxVal.w());
901 }
902
903 dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z);
904 }
905 }
906 }
907 }
908
fillWithComponentGradientsStyled(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal,GradientStyle style)909 void fillWithComponentGradientsStyled (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal, GradientStyle style)
910 {
911 if (isCombinedDepthStencilType(access.getFormat().type))
912 {
913 const bool hasDepth = access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
914 const bool hasStencil = access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
915
916 DE_ASSERT(hasDepth || hasStencil);
917
918 // For combined formats, treat D and S as separate channels
919 if (hasDepth)
920 fillWithComponentGradientsStyled(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), minVal, maxVal, style);
921 if (hasStencil)
922 fillWithComponentGradientsStyled(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), minVal.swizzle(3,2,1,0), maxVal.swizzle(3,2,1,0), style);
923 }
924 else
925 {
926 if (access.getHeight() == 1 && access.getDepth() == 1)
927 fillWithComponentGradients1D(access, minVal, maxVal, style);
928 else if (access.getDepth() == 1)
929 fillWithComponentGradients2D(access, minVal, maxVal, style);
930 else
931 fillWithComponentGradients3D(access, minVal, maxVal, style);
932 }
933 }
934
fillWithComponentGradients(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)935 void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
936 {
937 fillWithComponentGradientsStyled(access, minVal, maxVal, GRADIENT_STYLE_OLD);
938 }
939
fillWithComponentGradients2(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)940 void fillWithComponentGradients2 (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
941 {
942 fillWithComponentGradientsStyled(access, minVal, maxVal, GRADIENT_STYLE_NEW);
943 }
944
fillWithGrid1D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)945 static void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
946 {
947 for (int x = 0; x < access.getWidth(); x++)
948 {
949 int mx = (x / cellSize) % 2;
950
951 if (mx)
952 access.setPixel(colorB, x, 0);
953 else
954 access.setPixel(colorA, x, 0);
955 }
956 }
957
fillWithGrid2D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)958 static void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
959 {
960 for (int y = 0; y < access.getHeight(); y++)
961 {
962 for (int x = 0; x < access.getWidth(); x++)
963 {
964 int mx = (x / cellSize) % 2;
965 int my = (y / cellSize) % 2;
966
967 if (mx ^ my)
968 access.setPixel(colorB, x, y);
969 else
970 access.setPixel(colorA, x, y);
971 }
972 }
973 }
974
fillWithGrid3D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)975 static void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
976 {
977 for (int z = 0; z < access.getDepth(); z++)
978 {
979 for (int y = 0; y < access.getHeight(); y++)
980 {
981 for (int x = 0; x < access.getWidth(); x++)
982 {
983 int mx = (x / cellSize) % 2;
984 int my = (y / cellSize) % 2;
985 int mz = (z / cellSize) % 2;
986
987 if (mx ^ my ^ mz)
988 access.setPixel(colorB, x, y, z);
989 else
990 access.setPixel(colorA, x, y, z);
991 }
992 }
993 }
994 }
995
fillWithGrid(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)996 void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
997 {
998 if (isCombinedDepthStencilType(access.getFormat().type))
999 {
1000 const bool hasDepth = access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::D;
1001 const bool hasStencil = access.getFormat().order == tcu::TextureFormat::DS || access.getFormat().order == tcu::TextureFormat::S;
1002
1003 DE_ASSERT(hasDepth || hasStencil);
1004
1005 // For combined formats, treat D and S as separate channels
1006 if (hasDepth)
1007 fillWithGrid(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH), cellSize, colorA, colorB);
1008 if (hasStencil)
1009 fillWithGrid(getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL), cellSize, colorA.swizzle(3,2,1,0), colorB.swizzle(3,2,1,0));
1010 }
1011 else
1012 {
1013 if (access.getHeight() == 1 && access.getDepth() == 1)
1014 fillWithGrid1D(access, cellSize, colorA, colorB);
1015 else if (access.getDepth() == 1)
1016 fillWithGrid2D(access, cellSize, colorA, colorB);
1017 else
1018 fillWithGrid3D(access, cellSize, colorA, colorB);
1019 }
1020 }
1021
fillWithRepeatableGradient(const PixelBufferAccess & access,const Vec4 & colorA,const Vec4 & colorB)1022 void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB)
1023 {
1024 for (int y = 0; y < access.getHeight(); y++)
1025 {
1026 for (int x = 0; x < access.getWidth(); x++)
1027 {
1028 float s = ((float)x + 0.5f) / (float)access.getWidth();
1029 float t = ((float)y + 0.5f) / (float)access.getHeight();
1030
1031 float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s;
1032 float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t;
1033
1034 float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f);
1035 access.setPixel(linearInterpolate(p, colorA, colorB), x, y);
1036 }
1037 }
1038 }
1039
fillWithRGBAQuads(const PixelBufferAccess & dst)1040 void fillWithRGBAQuads (const PixelBufferAccess& dst)
1041 {
1042 TCU_CHECK_INTERNAL(dst.getDepth() == 1);
1043 int width = dst.getWidth();
1044 int height = dst.getHeight();
1045 int left = width/2;
1046 int top = height/2;
1047
1048 clear(getSubregion(dst, 0, 0, 0, left, top, 1), Vec4(1.0f, 0.0f, 0.0f, 1.0f));
1049 clear(getSubregion(dst, left, 0, 0, width-left, top, 1), Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1050 clear(getSubregion(dst, 0, top, 0, left, height-top, 1), Vec4(0.0f, 0.0f, 1.0f, 0.0f));
1051 clear(getSubregion(dst, left, top, 0, width-left, height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f));
1052 }
1053
1054 // \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators.
fillWithMetaballs(const PixelBufferAccess & dst,int numBalls,deUint32 seed)1055 void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed)
1056 {
1057 TCU_CHECK_INTERNAL(dst.getDepth() == 1);
1058 std::vector<Vec2> points(numBalls);
1059 de::Random rnd(seed);
1060
1061 for (int i = 0; i < numBalls; i++)
1062 {
1063 float x = rnd.getFloat();
1064 float y = rnd.getFloat();
1065 points[i] = (Vec2(x, y));
1066 }
1067
1068 for (int y = 0; y < dst.getHeight(); y++)
1069 for (int x = 0; x < dst.getWidth(); x++)
1070 {
1071 Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight());
1072
1073 float sum = 0.0f;
1074 for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++)
1075 {
1076 Vec2 d = p - *i;
1077 float f = 0.01f / (d.x()*d.x() + d.y()*d.y());
1078
1079 sum += f;
1080 }
1081
1082 dst.setPixel(Vec4(sum), x, y);
1083 }
1084 }
1085
copy(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,const bool clearUnused)1086 void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const bool clearUnused)
1087 {
1088 DE_ASSERT(src.getSize() == dst.getSize());
1089
1090 const int width = dst.getWidth();
1091 const int height = dst.getHeight();
1092 const int depth = dst.getDepth();
1093
1094 const int srcPixelSize = src.getFormat().getPixelSize();
1095 const int dstPixelSize = dst.getFormat().getPixelSize();
1096 const int srcPixelPitch = src.getPixelPitch();
1097 const int dstPixelPitch = dst.getPixelPitch();
1098 const bool srcTightlyPacked = (srcPixelSize == srcPixelPitch);
1099 const bool dstTightlyPacked = (dstPixelSize == dstPixelPitch);
1100
1101 const bool srcHasDepth = (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::D);
1102 const bool srcHasStencil = (src.getFormat().order == tcu::TextureFormat::DS || src.getFormat().order == tcu::TextureFormat::S);
1103 const bool dstHasDepth = (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::D);
1104 const bool dstHasStencil = (dst.getFormat().order == tcu::TextureFormat::DS || dst.getFormat().order == tcu::TextureFormat::S);
1105
1106 if (src.getFormat() == dst.getFormat() && srcTightlyPacked && dstTightlyPacked)
1107 {
1108 // Fast-path for matching formats.
1109 for (int z = 0; z < depth; z++)
1110 for (int y = 0; y < height; y++)
1111 deMemcpy(dst.getPixelPtr(0, y, z), src.getPixelPtr(0, y, z), srcPixelSize*width);
1112 }
1113 else if (src.getFormat() == dst.getFormat())
1114 {
1115 // Bit-exact copy for matching formats.
1116 for (int z = 0; z < depth; z++)
1117 for (int y = 0; y < height; y++)
1118 for (int x = 0; x < width; x++)
1119 deMemcpy(dst.getPixelPtr(x, y, z), src.getPixelPtr(x, y, z), srcPixelSize);
1120 }
1121 else if (srcHasDepth || srcHasStencil || dstHasDepth || dstHasStencil)
1122 {
1123 DE_ASSERT((srcHasDepth && dstHasDepth) || (srcHasStencil && dstHasStencil)); // must have at least one common channel
1124
1125 if (dstHasDepth && srcHasDepth)
1126 {
1127 for (int z = 0; z < depth; z++)
1128 for (int y = 0; y < height; y++)
1129 for (int x = 0; x < width; x++)
1130 dst.setPixDepth(src.getPixDepth(x, y, z), x, y, z);
1131 }
1132 else if (dstHasDepth && !srcHasDepth && clearUnused)
1133 {
1134 // consistency with color copies
1135 tcu::clearDepth(dst, 0.0f);
1136 }
1137
1138 if (dstHasStencil && srcHasStencil)
1139 {
1140 for (int z = 0; z < depth; z++)
1141 for (int y = 0; y < height; y++)
1142 for (int x = 0; x < width; x++)
1143 dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z);
1144 }
1145 else if (dstHasStencil && !srcHasStencil && clearUnused)
1146 {
1147 // consistency with color copies
1148 tcu::clearStencil(dst, 0u);
1149 }
1150 }
1151 else
1152 {
1153 TextureChannelClass srcClass = getTextureChannelClass(src.getFormat().type);
1154 TextureChannelClass dstClass = getTextureChannelClass(dst.getFormat().type);
1155 bool srcIsInt = srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
1156 bool dstIsInt = dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
1157
1158 if (srcIsInt && dstIsInt)
1159 {
1160 for (int z = 0; z < depth; z++)
1161 for (int y = 0; y < height; y++)
1162 for (int x = 0; x < width; x++)
1163 dst.setPixel(src.getPixelInt(x, y, z), x, y, z);
1164 }
1165 else
1166 {
1167 for (int z = 0; z < depth; z++)
1168 for (int y = 0; y < height; y++)
1169 for (int x = 0; x < width; x++)
1170 dst.setPixel(src.getPixel(x, y, z), x, y, z);
1171 }
1172 }
1173 }
1174
scale(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,Sampler::FilterMode filter)1175 void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter)
1176 {
1177 DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR);
1178
1179 Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE,
1180 filter, filter, 0.0f, false);
1181
1182 float sX = (float)src.getWidth() / (float)dst.getWidth();
1183 float sY = (float)src.getHeight() / (float)dst.getHeight();
1184 float sZ = (float)src.getDepth() / (float)dst.getDepth();
1185
1186 if (dst.getDepth() == 1 && src.getDepth() == 1)
1187 {
1188 for (int y = 0; y < dst.getHeight(); y++)
1189 for (int x = 0; x < dst.getWidth(); x++)
1190 dst.setPixel(linearToSRGBIfNeeded(dst.getFormat(), src.sample2D(sampler, filter, ((float)x+0.5f)*sX, ((float)y+0.5f)*sY, 0)), x, y);
1191 }
1192 else
1193 {
1194 for (int z = 0; z < dst.getDepth(); z++)
1195 for (int y = 0; y < dst.getHeight(); y++)
1196 for (int x = 0; x < dst.getWidth(); x++)
1197 dst.setPixel(linearToSRGBIfNeeded(dst.getFormat(), src.sample3D(sampler, filter, ((float)x+0.5f)*sX, ((float)y+0.5f)*sY, ((float)z+0.5f)*sZ)), x, y, z);
1198 }
1199 }
1200
estimatePixelValueRange(const ConstPixelBufferAccess & access,Vec4 & minVal,Vec4 & maxVal)1201 void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal)
1202 {
1203 const TextureFormat& format = access.getFormat();
1204
1205 switch (getTextureChannelClass(format.type))
1206 {
1207 case TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1208 // Normalized unsigned formats.
1209 minVal = Vec4(0.0f);
1210 maxVal = Vec4(1.0f);
1211 break;
1212
1213 case TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1214 // Normalized signed formats.
1215 minVal = Vec4(-1.0f);
1216 maxVal = Vec4(+1.0f);
1217 break;
1218
1219 default:
1220 // \note Samples every 4/8th pixel.
1221 minVal = Vec4(std::numeric_limits<float>::max());
1222 maxVal = Vec4(std::numeric_limits<float>::min());
1223
1224 for (int z = 0; z < access.getDepth(); z += 2)
1225 {
1226 for (int y = 0; y < access.getHeight(); y += 2)
1227 {
1228 for (int x = 0; x < access.getWidth(); x += 2)
1229 {
1230 Vec4 p = access.getPixel(x, y, z);
1231
1232 minVal[0] = (deFloatIsNaN(p[0]) ? minVal[0] : de::min(minVal[0], p[0]));
1233 minVal[1] = (deFloatIsNaN(p[1]) ? minVal[1] : de::min(minVal[1], p[1]));
1234 minVal[2] = (deFloatIsNaN(p[2]) ? minVal[2] : de::min(minVal[2], p[2]));
1235 minVal[3] = (deFloatIsNaN(p[3]) ? minVal[3] : de::min(minVal[3], p[3]));
1236
1237 maxVal[0] = (deFloatIsNaN(p[0]) ? maxVal[0] : de::max(maxVal[0], p[0]));
1238 maxVal[1] = (deFloatIsNaN(p[1]) ? maxVal[1] : de::max(maxVal[1], p[1]));
1239 maxVal[2] = (deFloatIsNaN(p[2]) ? maxVal[2] : de::max(maxVal[2], p[2]));
1240 maxVal[3] = (deFloatIsNaN(p[3]) ? maxVal[3] : de::max(maxVal[3], p[3]));
1241 }
1242 }
1243 }
1244 break;
1245 }
1246 }
1247
computePixelScaleBias(const ConstPixelBufferAccess & access,Vec4 & scale,Vec4 & bias)1248 void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias)
1249 {
1250 Vec4 minVal, maxVal;
1251 estimatePixelValueRange(access, minVal, maxVal);
1252
1253 const float eps = 0.0001f;
1254
1255 for (int c = 0; c < 4; c++)
1256 {
1257 if (maxVal[c] - minVal[c] < eps)
1258 {
1259 scale[c] = (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
1260 bias[c] = (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
1261 }
1262 else
1263 {
1264 scale[c] = 1.0f / (maxVal[c] - minVal[c]);
1265 bias[c] = 0.0f - minVal[c]*scale[c];
1266 }
1267 }
1268 }
1269
getCubeArrayFaceIndex(CubeFace face)1270 int getCubeArrayFaceIndex (CubeFace face)
1271 {
1272 DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
1273
1274 switch (face)
1275 {
1276 case CUBEFACE_POSITIVE_X: return 0;
1277 case CUBEFACE_NEGATIVE_X: return 1;
1278 case CUBEFACE_POSITIVE_Y: return 2;
1279 case CUBEFACE_NEGATIVE_Y: return 3;
1280 case CUBEFACE_POSITIVE_Z: return 4;
1281 case CUBEFACE_NEGATIVE_Z: return 5;
1282
1283 default:
1284 return -1;
1285 }
1286 }
1287
packRGB999E5(const tcu::Vec4 & color)1288 deUint32 packRGB999E5 (const tcu::Vec4& color)
1289 {
1290 const int mBits = 9;
1291 const int eBits = 5;
1292 const int eBias = 15;
1293 const int eMax = (1<<eBits)-1;
1294 const float maxVal = (float)(((1<<mBits) - 1) * (1<<(eMax-eBias))) / (float)(1<<mBits);
1295
1296 float rc = deFloatClamp(color[0], 0.0f, maxVal);
1297 float gc = deFloatClamp(color[1], 0.0f, maxVal);
1298 float bc = deFloatClamp(color[2], 0.0f, maxVal);
1299 float maxc = de::max(rc, de::max(gc, bc));
1300 int exps = de::max(-eBias - 1, deFloorFloatToInt32(deFloatLog2(maxc))) + 1 + eBias;
1301 float e = deFloatPow(2.0f, (float)(exps-eBias-mBits));
1302 int maxs = deFloorFloatToInt32(maxc / e + 0.5f);
1303
1304 if (maxs == (1<<mBits))
1305 {
1306 exps++;
1307 e *= 2.0f;
1308 }
1309
1310 deUint32 rs = (deUint32)deFloorFloatToInt32(rc / e + 0.5f);
1311 deUint32 gs = (deUint32)deFloorFloatToInt32(gc / e + 0.5f);
1312 deUint32 bs = (deUint32)deFloorFloatToInt32(bc / e + 0.5f);
1313
1314 DE_ASSERT((exps & ~((1<<5)-1)) == 0);
1315 DE_ASSERT((rs & ~((1<<9)-1)) == 0);
1316 DE_ASSERT((gs & ~((1<<9)-1)) == 0);
1317 DE_ASSERT((bs & ~((1<<9)-1)) == 0);
1318
1319 return rs | (gs << 9) | (bs << 18) | (exps << 27);
1320 }
1321
1322 // Sampler utils
1323
addOffset(const void * ptr,int numBytes)1324 static const void* addOffset (const void* ptr, int numBytes)
1325 {
1326 return (const deUint8*)ptr + numBytes;
1327 }
1328
addOffset(void * ptr,int numBytes)1329 static void* addOffset (void* ptr, int numBytes)
1330 {
1331 return (deUint8*)ptr + numBytes;
1332 }
1333
1334 template <typename AccessType>
toSamplerAccess(const AccessType & baseAccess,Sampler::DepthStencilMode mode)1335 static AccessType toSamplerAccess (const AccessType& baseAccess, Sampler::DepthStencilMode mode)
1336 {
1337 // make sure to update this if type table is updated
1338 DE_STATIC_ASSERT(TextureFormat::CHANNELTYPE_LAST == 48);
1339
1340 if (!isCombinedDepthStencilType(baseAccess.getFormat().type))
1341 return baseAccess;
1342 else
1343 {
1344 #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
1345 const deUint32 uint32ByteOffsetBits0To8 = 0; //!< least significant byte in the lowest address
1346 const deUint32 uint32ByteOffsetBits0To24 = 0;
1347 const deUint32 uint32ByteOffsetBits8To32 = 1;
1348 const deUint32 uint32ByteOffsetBits16To32 = 2;
1349 const deUint32 uint32ByteOffsetBits24To32 = 3;
1350 #else
1351 const deUint32 uint32ByteOffsetBits0To8 = 3; //!< least significant byte in the highest address
1352 const deUint32 uint32ByteOffsetBits0To24 = 1;
1353 const deUint32 uint32ByteOffsetBits8To32 = 0;
1354 const deUint32 uint32ByteOffsetBits16To32 = 0;
1355 const deUint32 uint32ByteOffsetBits24To32 = 0;
1356 #endif
1357
1358 // Sampled channel must exist
1359 DE_ASSERT(baseAccess.getFormat().order == TextureFormat::DS ||
1360 (mode == Sampler::MODE_DEPTH && baseAccess.getFormat().order == TextureFormat::D) ||
1361 (mode == Sampler::MODE_STENCIL && baseAccess.getFormat().order == TextureFormat::S));
1362
1363 // combined formats have multiple channel classes, detect on sampler settings
1364 switch (baseAccess.getFormat().type)
1365 {
1366 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1367 {
1368 if (mode == Sampler::MODE_DEPTH)
1369 {
1370 // select the float component
1371 return AccessType(TextureFormat(TextureFormat::D, TextureFormat::FLOAT),
1372 baseAccess.getSize(),
1373 baseAccess.getPitch(),
1374 baseAccess.getDataPtr());
1375 }
1376 else if (mode == Sampler::MODE_STENCIL)
1377 {
1378 // select the uint 8 component
1379 return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1380 baseAccess.getSize(),
1381 baseAccess.getPitch(),
1382 addOffset(baseAccess.getDataPtr(), 4 + uint32ByteOffsetBits0To8));
1383 }
1384 else
1385 {
1386 // unknown sampler mode
1387 DE_ASSERT(false);
1388 return AccessType();
1389 }
1390 }
1391
1392 case TextureFormat::UNSIGNED_INT_16_8_8:
1393 {
1394 if (mode == Sampler::MODE_DEPTH)
1395 {
1396 // select the unorm16 component
1397 return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT16),
1398 baseAccess.getSize(),
1399 baseAccess.getPitch(),
1400 addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits16To32));
1401 }
1402 else if (mode == Sampler::MODE_STENCIL)
1403 {
1404 // select the uint 8 component
1405 return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1406 baseAccess.getSize(),
1407 baseAccess.getPitch(),
1408 addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To8));
1409 }
1410 else
1411 {
1412 // unknown sampler mode
1413 DE_ASSERT(false);
1414 return AccessType();
1415 }
1416 }
1417
1418 case TextureFormat::UNSIGNED_INT_24_8:
1419 {
1420 if (mode == Sampler::MODE_DEPTH)
1421 {
1422 // select the unorm24 component
1423 return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT24),
1424 baseAccess.getSize(),
1425 baseAccess.getPitch(),
1426 addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits8To32));
1427 }
1428 else if (mode == Sampler::MODE_STENCIL)
1429 {
1430 // select the uint 8 component
1431 return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1432 baseAccess.getSize(),
1433 baseAccess.getPitch(),
1434 addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To8));
1435 }
1436 else
1437 {
1438 // unknown sampler mode
1439 DE_ASSERT(false);
1440 return AccessType();
1441 }
1442 }
1443
1444 case TextureFormat::UNSIGNED_INT_24_8_REV:
1445 {
1446 if (mode == Sampler::MODE_DEPTH)
1447 {
1448 // select the unorm24 component
1449 return AccessType(TextureFormat(TextureFormat::D, TextureFormat::UNORM_INT24),
1450 baseAccess.getSize(),
1451 baseAccess.getPitch(),
1452 addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits0To24));
1453 }
1454 else if (mode == Sampler::MODE_STENCIL)
1455 {
1456 // select the uint 8 component
1457 return AccessType(TextureFormat(TextureFormat::S, TextureFormat::UNSIGNED_INT8),
1458 baseAccess.getSize(),
1459 baseAccess.getPitch(),
1460 addOffset(baseAccess.getDataPtr(), uint32ByteOffsetBits24To32));
1461 }
1462 else
1463 {
1464 // unknown sampler mode
1465 DE_ASSERT(false);
1466 return AccessType();
1467 }
1468 }
1469
1470 default:
1471 {
1472 // unknown combined format
1473 DE_ASSERT(false);
1474 return AccessType();
1475 }
1476 }
1477 }
1478 }
1479
getEffectiveDepthStencilAccess(const PixelBufferAccess & baseAccess,Sampler::DepthStencilMode mode)1480 PixelBufferAccess getEffectiveDepthStencilAccess (const PixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
1481 {
1482 return toSamplerAccess<PixelBufferAccess>(baseAccess, mode);
1483 }
1484
getEffectiveDepthStencilAccess(const ConstPixelBufferAccess & baseAccess,Sampler::DepthStencilMode mode)1485 ConstPixelBufferAccess getEffectiveDepthStencilAccess (const ConstPixelBufferAccess& baseAccess, Sampler::DepthStencilMode mode)
1486 {
1487 return toSamplerAccess<ConstPixelBufferAccess>(baseAccess, mode);
1488 }
1489
getEffectiveDepthStencilTextureFormat(const TextureFormat & baseFormat,Sampler::DepthStencilMode mode)1490 TextureFormat getEffectiveDepthStencilTextureFormat (const TextureFormat& baseFormat, Sampler::DepthStencilMode mode)
1491 {
1492 return toSamplerAccess(ConstPixelBufferAccess(baseFormat, IVec3(0, 0, 0), DE_NULL), mode).getFormat();
1493 }
1494
1495 template <typename ViewType>
getEffectiveTView(const ViewType & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1496 ViewType getEffectiveTView (const ViewType& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1497 {
1498 storage.resize(src.getNumLevels());
1499
1500 ViewType view = ViewType(src.getNumLevels(), &storage[0], src.isES2());
1501
1502 for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
1503 storage[levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevel(levelNdx), sampler.depthStencilMode);
1504
1505 return view;
1506 }
1507
getEffectiveTView(const tcu::TextureCubeView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1508 tcu::TextureCubeView getEffectiveTView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1509 {
1510 storage.resize(tcu::CUBEFACE_LAST * src.getNumLevels());
1511
1512 const tcu::ConstPixelBufferAccess* storagePtrs[tcu::CUBEFACE_LAST] =
1513 {
1514 &storage[0 * src.getNumLevels()],
1515 &storage[1 * src.getNumLevels()],
1516 &storage[2 * src.getNumLevels()],
1517 &storage[3 * src.getNumLevels()],
1518 &storage[4 * src.getNumLevels()],
1519 &storage[5 * src.getNumLevels()],
1520 };
1521
1522 tcu::TextureCubeView view = tcu::TextureCubeView(src.getNumLevels(), storagePtrs, false);
1523
1524 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1525 for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx)
1526 storage[faceNdx * src.getNumLevels() + levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), sampler.depthStencilMode);
1527
1528 return view;
1529 }
1530
getEffectiveTextureView(const tcu::Texture1DView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1531 tcu::Texture1DView getEffectiveTextureView (const tcu::Texture1DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1532 {
1533 return getEffectiveTView(src, storage, sampler);
1534 }
1535
getEffectiveTextureView(const tcu::Texture2DView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1536 tcu::Texture2DView getEffectiveTextureView (const tcu::Texture2DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1537 {
1538 return getEffectiveTView(src, storage, sampler);
1539 }
1540
getEffectiveTextureView(const tcu::Texture3DView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1541 tcu::Texture3DView getEffectiveTextureView (const tcu::Texture3DView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1542 {
1543 return getEffectiveTView(src, storage, sampler);
1544 }
1545
getEffectiveTextureView(const tcu::Texture1DArrayView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1546 tcu::Texture1DArrayView getEffectiveTextureView (const tcu::Texture1DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1547 {
1548 return getEffectiveTView(src, storage, sampler);
1549 }
1550
getEffectiveTextureView(const tcu::Texture2DArrayView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1551 tcu::Texture2DArrayView getEffectiveTextureView (const tcu::Texture2DArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1552 {
1553 return getEffectiveTView(src, storage, sampler);
1554 }
1555
getEffectiveTextureView(const tcu::TextureCubeView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1556 tcu::TextureCubeView getEffectiveTextureView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1557 {
1558 return getEffectiveTView(src, storage, sampler);
1559 }
1560
getEffectiveTextureView(const tcu::TextureCubeArrayView & src,std::vector<tcu::ConstPixelBufferAccess> & storage,const tcu::Sampler & sampler)1561 tcu::TextureCubeArrayView getEffectiveTextureView (const tcu::TextureCubeArrayView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler)
1562 {
1563 return getEffectiveTView(src, storage, sampler);
1564 }
1565
1566 //! Returns the effective swizzle of a border color. The effective swizzle is the
1567 //! equal to first writing an RGBA color with a write swizzle and then reading
1568 //! it back using a read swizzle, i.e. BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
getBorderColorReadSwizzle(TextureFormat::ChannelOrder order)1569 static const TextureSwizzle& getBorderColorReadSwizzle (TextureFormat::ChannelOrder order)
1570 {
1571 // make sure to update these tables when channel orders are updated
1572 DE_STATIC_ASSERT(TextureFormat::CHANNELORDER_LAST == 21);
1573
1574 static const TextureSwizzle INV = {{ TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
1575 static const TextureSwizzle R = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
1576 static const TextureSwizzle A = {{ TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_3 }};
1577 static const TextureSwizzle I = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0 }};
1578 static const TextureSwizzle L = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ONE }};
1579 static const TextureSwizzle LA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3 }};
1580 static const TextureSwizzle RG = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
1581 static const TextureSwizzle RA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_3 }};
1582 static const TextureSwizzle RGB = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_ONE }};
1583 static const TextureSwizzle RGBA = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1, TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3 }};
1584 static const TextureSwizzle D = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
1585 static const TextureSwizzle S = {{ TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ZERO, TextureSwizzle::CHANNEL_ONE }};
1586
1587 const TextureSwizzle* swizzle;
1588
1589 switch (order)
1590 {
1591 case TextureFormat::R: swizzle = &R; break;
1592 case TextureFormat::A: swizzle = &A; break;
1593 case TextureFormat::I: swizzle = &I; break;
1594 case TextureFormat::L: swizzle = &L; break;
1595 case TextureFormat::LA: swizzle = &LA; break;
1596 case TextureFormat::RG: swizzle = &RG; break;
1597 case TextureFormat::RA: swizzle = &RA; break;
1598 case TextureFormat::RGB: swizzle = &RGB; break;
1599 case TextureFormat::RGBA: swizzle = &RGBA; break;
1600 case TextureFormat::ARGB: swizzle = &RGBA; break;
1601 case TextureFormat::BGR: swizzle = &RGB; break;
1602 case TextureFormat::BGRA: swizzle = &RGBA; break;
1603 case TextureFormat::sR: swizzle = &R; break;
1604 case TextureFormat::sRG: swizzle = &RG; break;
1605 case TextureFormat::sRGB: swizzle = &RGB; break;
1606 case TextureFormat::sRGBA: swizzle = &RGBA; break;
1607 case TextureFormat::sBGR: swizzle = &RGB; break;
1608 case TextureFormat::sBGRA: swizzle = &RGBA; break;
1609 case TextureFormat::D: swizzle = &D; break;
1610 case TextureFormat::S: swizzle = &S; break;
1611
1612 case TextureFormat::DS:
1613 DE_ASSERT(false); // combined depth-stencil border color?
1614 swizzle = &INV;
1615 break;
1616
1617 default:
1618 DE_ASSERT(false);
1619 swizzle = &INV;
1620 break;
1621 }
1622
1623 #ifdef DE_DEBUG
1624
1625 {
1626 // check that BorderSwizzle(c) == readSwizzle(writeSwizzle(C))
1627 const TextureSwizzle& readSwizzle = getChannelReadSwizzle(order);
1628 const TextureSwizzle& writeSwizzle = getChannelWriteSwizzle(order);
1629
1630 for (int ndx = 0; ndx < 4; ++ndx)
1631 {
1632 TextureSwizzle::Channel writeRead = readSwizzle.components[ndx];
1633 if (deInRange32(writeRead, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_3) == DE_TRUE)
1634 writeRead = writeSwizzle.components[(int)writeRead];
1635 DE_ASSERT(writeRead == swizzle->components[ndx]);
1636 }
1637 }
1638
1639 #endif
1640
1641 return *swizzle;
1642 }
1643
getNBitUnsignedIntegerVec4MaxValue(const tcu::IVec4 & numBits)1644 static tcu::UVec4 getNBitUnsignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
1645 {
1646 return tcu::UVec4((numBits[0] > 0) ? (deUintMaxValue32(numBits[0])) : (0),
1647 (numBits[1] > 0) ? (deUintMaxValue32(numBits[1])) : (0),
1648 (numBits[2] > 0) ? (deUintMaxValue32(numBits[2])) : (0),
1649 (numBits[3] > 0) ? (deUintMaxValue32(numBits[3])) : (0));
1650 }
1651
getNBitSignedIntegerVec4MaxValue(const tcu::IVec4 & numBits)1652 static tcu::IVec4 getNBitSignedIntegerVec4MaxValue (const tcu::IVec4& numBits)
1653 {
1654 return tcu::IVec4((numBits[0] > 0) ? (deIntMaxValue32(numBits[0])) : (0),
1655 (numBits[1] > 0) ? (deIntMaxValue32(numBits[1])) : (0),
1656 (numBits[2] > 0) ? (deIntMaxValue32(numBits[2])) : (0),
1657 (numBits[3] > 0) ? (deIntMaxValue32(numBits[3])) : (0));
1658 }
1659
getNBitSignedIntegerVec4MinValue(const tcu::IVec4 & numBits)1660 static tcu::IVec4 getNBitSignedIntegerVec4MinValue (const tcu::IVec4& numBits)
1661 {
1662 return tcu::IVec4((numBits[0] > 0) ? (deIntMinValue32(numBits[0])) : (0),
1663 (numBits[1] > 0) ? (deIntMinValue32(numBits[1])) : (0),
1664 (numBits[2] > 0) ? (deIntMinValue32(numBits[2])) : (0),
1665 (numBits[3] > 0) ? (deIntMinValue32(numBits[3])) : (0));
1666 }
1667
getTextureBorderColorFloat(const TextureFormat & format,const Sampler & sampler)1668 static tcu::Vec4 getTextureBorderColorFloat (const TextureFormat& format, const Sampler& sampler)
1669 {
1670 const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
1671 const TextureSwizzle::Channel* channelMap = getBorderColorReadSwizzle(format.order).components;
1672 const bool isFloat = channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
1673 const bool isSigned = channelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
1674 const float valueMin = (isSigned) ? (-1.0f) : (0.0f);
1675 const float valueMax = 1.0f;
1676 Vec4 result;
1677
1678 DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT ||
1679 channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
1680 channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
1681
1682 for (int c = 0; c < 4; c++)
1683 {
1684 const TextureSwizzle::Channel map = channelMap[c];
1685 if (map == TextureSwizzle::CHANNEL_ZERO)
1686 result[c] = 0.0f;
1687 else if (map == TextureSwizzle::CHANNEL_ONE)
1688 result[c] = 1.0f;
1689 else if (isFloat)
1690 {
1691 // floating point values are not clamped
1692 result[c] = sampler.borderColor.getAccess<float>()[(int)map];
1693 }
1694 else
1695 {
1696 // fixed point values are clamped to a representable range
1697 result[c] = de::clamp(sampler.borderColor.getAccess<float>()[(int)map], valueMin, valueMax);
1698 }
1699 }
1700
1701 return result;
1702 }
1703
getTextureBorderColorInt(const TextureFormat & format,const Sampler & sampler)1704 static tcu::IVec4 getTextureBorderColorInt (const TextureFormat& format, const Sampler& sampler)
1705 {
1706 const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
1707 const TextureSwizzle::Channel* channelMap = getBorderColorReadSwizzle(format.order).components;
1708 const IVec4 channelBits = getChannelBitDepth(format.type);
1709 const IVec4 valueMin = getNBitSignedIntegerVec4MinValue(channelBits);
1710 const IVec4 valueMax = getNBitSignedIntegerVec4MaxValue(channelBits);
1711 IVec4 result;
1712
1713 DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
1714 DE_UNREF(channelClass);
1715
1716 for (int c = 0; c < 4; c++)
1717 {
1718 const TextureSwizzle::Channel map = channelMap[c];
1719 if (map == TextureSwizzle::CHANNEL_ZERO)
1720 result[c] = 0;
1721 else if (map == TextureSwizzle::CHANNEL_ONE)
1722 result[c] = 1;
1723 else
1724 {
1725 // integer values are clamped to a representable range
1726 result[c] = de::clamp(sampler.borderColor.getAccess<deInt32>()[(int)map], valueMin[(int)map], valueMax[(int)map]);
1727 }
1728 }
1729
1730 return result;
1731 }
1732
getTextureBorderColorUint(const TextureFormat & format,const Sampler & sampler)1733 static tcu::UVec4 getTextureBorderColorUint (const TextureFormat& format, const Sampler& sampler)
1734 {
1735 const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
1736 const TextureSwizzle::Channel* channelMap = getBorderColorReadSwizzle(format.order).components;
1737 const IVec4 channelBits = getChannelBitDepth(format.type);
1738 const UVec4 valueMax = getNBitUnsignedIntegerVec4MaxValue(channelBits);
1739 UVec4 result;
1740
1741 DE_ASSERT(channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
1742 DE_UNREF(channelClass);
1743
1744 for (int c = 0; c < 4; c++)
1745 {
1746 const TextureSwizzle::Channel map = channelMap[c];
1747 if (map == TextureSwizzle::CHANNEL_ZERO)
1748 result[c] = 0;
1749 else if (map == TextureSwizzle::CHANNEL_ONE)
1750 result[c] = 1;
1751 else
1752 {
1753 // integer values are clamped to a representable range
1754 result[c] = de::min(sampler.borderColor.getAccess<deUint32>()[(int)map], valueMax[(int)map]);
1755 }
1756 }
1757
1758 return result;
1759 }
1760
1761 template <typename ScalarType>
sampleTextureBorder(const TextureFormat & format,const Sampler & sampler)1762 tcu::Vector<ScalarType, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler)
1763 {
1764 const tcu::TextureChannelClass channelClass = getTextureChannelClass(format.type);
1765
1766 switch (channelClass)
1767 {
1768 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1769 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1770 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1771 return getTextureBorderColorFloat(format, sampler).cast<ScalarType>();
1772
1773 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1774 return getTextureBorderColorInt(format, sampler).cast<ScalarType>();
1775
1776 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1777 return getTextureBorderColorUint(format, sampler).cast<ScalarType>();
1778
1779 default:
1780 DE_ASSERT(false);
1781 return tcu::Vector<ScalarType, 4>();
1782 }
1783 }
1784
1785 // instantiation
1786 template tcu::Vector<float, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1787 template tcu::Vector<deInt32, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1788 template tcu::Vector<deUint32, 4> sampleTextureBorder (const TextureFormat& format, const Sampler& sampler);
1789
1790 } // tcu
1791