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