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