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