• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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