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