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