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
73 //! Get texture channel class for format
getTextureChannelClass(TextureFormat::ChannelType channelType)74 TextureChannelClass getTextureChannelClass (TextureFormat::ChannelType channelType)
75 {
76 switch (channelType)
77 {
78 case TextureFormat::SNORM_INT8: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
79 case TextureFormat::SNORM_INT16: return TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
80 case TextureFormat::UNORM_INT8: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
81 case TextureFormat::UNORM_INT16: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
82 case TextureFormat::UNORM_SHORT_565: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
83 case TextureFormat::UNORM_SHORT_555: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
84 case TextureFormat::UNORM_SHORT_4444: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
85 case TextureFormat::UNORM_SHORT_5551: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
86 case TextureFormat::UNORM_INT_101010: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
87 case TextureFormat::UNORM_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
88 case TextureFormat::UNSIGNED_INT_1010102_REV: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
89 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return TEXTURECHANNELCLASS_FLOATING_POINT;
90 case TextureFormat::UNSIGNED_INT_999_E5_REV: return TEXTURECHANNELCLASS_FLOATING_POINT;
91 case TextureFormat::SIGNED_INT8: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
92 case TextureFormat::SIGNED_INT16: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
93 case TextureFormat::SIGNED_INT32: return TEXTURECHANNELCLASS_SIGNED_INTEGER;
94 case TextureFormat::UNSIGNED_INT8: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
95 case TextureFormat::UNSIGNED_INT16: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
96 case TextureFormat::UNSIGNED_INT32: return TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
97 case TextureFormat::HALF_FLOAT: return TEXTURECHANNELCLASS_FLOATING_POINT;
98 case TextureFormat::FLOAT: return TEXTURECHANNELCLASS_FLOATING_POINT;
99 default: return TEXTURECHANNELCLASS_LAST;
100 }
101 }
102
103 /*--------------------------------------------------------------------*//*!
104 * \brief Get access to subregion of pixel buffer
105 * \param access Parent access object
106 * \param x X offset
107 * \param y Y offset
108 * \param z Z offset
109 * \param width Width
110 * \param height Height
111 * \param depth Depth
112 * \return Access object that targets given subregion of parent access object
113 *//*--------------------------------------------------------------------*/
getSubregion(const ConstPixelBufferAccess & access,int x,int y,int z,int width,int height,int depth)114 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
115 {
116 DE_ASSERT(de::inBounds(x, 0, access.getWidth()) && de::inRange(x+width, x, access.getWidth()));
117 DE_ASSERT(de::inBounds(y, 0, access.getHeight()) && de::inRange(y+height, y, access.getHeight()));
118 DE_ASSERT(de::inBounds(z, 0, access.getDepth()) && de::inRange(z+depth, z, access.getDepth()));
119 return ConstPixelBufferAccess(access.getFormat(), width, height, depth, access.getRowPitch(), access.getSlicePitch(),
120 (const deUint8*)access.getDataPtr() + access.getFormat().getPixelSize()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
121 }
122
123 /*--------------------------------------------------------------------*//*!
124 * \brief Get access to subregion of pixel buffer
125 * \param access Parent access object
126 * \param x X offset
127 * \param y Y offset
128 * \param z Z offset
129 * \param width Width
130 * \param height Height
131 * \param depth Depth
132 * \return Access object that targets given subregion of parent access object
133 *//*--------------------------------------------------------------------*/
getSubregion(const PixelBufferAccess & access,int x,int y,int z,int width,int height,int depth)134 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int z, int width, int height, int depth)
135 {
136 DE_ASSERT(de::inBounds(x, 0, access.getWidth()) && de::inRange(x+width, x, access.getWidth()));
137 DE_ASSERT(de::inBounds(y, 0, access.getHeight()) && de::inRange(y+height, y, access.getHeight()));
138 DE_ASSERT(de::inBounds(z, 0, access.getDepth()) && de::inRange(z+depth, z, access.getDepth()));
139 return PixelBufferAccess(access.getFormat(), width, height, depth, access.getRowPitch(), access.getSlicePitch(),
140 (deUint8*)access.getDataPtr() + access.getFormat().getPixelSize()*x + access.getRowPitch()*y + access.getSlicePitch()*z);
141 }
142
143 /*--------------------------------------------------------------------*//*!
144 * \brief Get access to subregion of pixel buffer
145 * \param access Parent access object
146 * \param x X offset
147 * \param y Y offset
148 * \param width Width
149 * \param height Height
150 * \return Access object that targets given subregion of parent access object
151 *//*--------------------------------------------------------------------*/
getSubregion(const PixelBufferAccess & access,int x,int y,int width,int height)152 PixelBufferAccess getSubregion (const PixelBufferAccess& access, int x, int y, int width, int height)
153 {
154 return getSubregion(access, x, y, 0, width, height, 1);
155 }
156
157 /*--------------------------------------------------------------------*//*!
158 * \brief Get access to subregion of pixel buffer
159 * \param access Parent access object
160 * \param x X offset
161 * \param y Y offset
162 * \param width Width
163 * \param height Height
164 * \return Access object that targets given subregion of parent access object
165 *//*--------------------------------------------------------------------*/
getSubregion(const ConstPixelBufferAccess & access,int x,int y,int width,int height)166 ConstPixelBufferAccess getSubregion (const ConstPixelBufferAccess& access, int x, int y, int width, int height)
167 {
168 return getSubregion(access, x, y, 0, width, height, 1);
169 }
170
171 /*--------------------------------------------------------------------*//*!
172 * \brief Flip rows in Y direction
173 * \param access Access object
174 * \return Modified access object where Y coordinates are reversed
175 *//*--------------------------------------------------------------------*/
flipYAccess(const PixelBufferAccess & access)176 PixelBufferAccess flipYAccess (const PixelBufferAccess& access)
177 {
178 const int rowPitch = access.getRowPitch();
179 const int offsetToLast = rowPitch*(access.getHeight()-1);
180
181 return PixelBufferAccess(access.getFormat(), access.getWidth(), access.getHeight(), access.getDepth(),
182 -rowPitch, access.getSlicePitch(), (deUint8*)access.getDataPtr() + offsetToLast);
183 }
184
185 /*--------------------------------------------------------------------*//*!
186 * \brief Flip rows in Y direction
187 * \param access Access object
188 * \return Modified access object where Y coordinates are reversed
189 *//*--------------------------------------------------------------------*/
flipYAccess(const ConstPixelBufferAccess & access)190 ConstPixelBufferAccess flipYAccess (const ConstPixelBufferAccess& access)
191 {
192 const int rowPitch = access.getRowPitch();
193 const int offsetToLast = rowPitch*(access.getHeight()-1);
194
195 return ConstPixelBufferAccess(access.getFormat(), access.getWidth(), access.getHeight(), access.getDepth(),
196 -rowPitch, access.getSlicePitch(), (const deUint8*)access.getDataPtr() + offsetToLast);
197 }
198
getChannelValueRange(TextureFormat::ChannelType channelType)199 static Vec2 getChannelValueRange (TextureFormat::ChannelType channelType)
200 {
201 float cMin = 0.0f;
202 float cMax = 0.0f;
203
204 switch (channelType)
205 {
206 // Signed normalized formats.
207 case TextureFormat::SNORM_INT8:
208 case TextureFormat::SNORM_INT16: cMin = -1.0f; cMax = 1.0f; break;
209
210 // Unsigned normalized formats.
211 case TextureFormat::UNORM_INT8:
212 case TextureFormat::UNORM_INT16:
213 case TextureFormat::UNORM_SHORT_565:
214 case TextureFormat::UNORM_SHORT_4444:
215 case TextureFormat::UNORM_INT_101010:
216 case TextureFormat::UNORM_INT_1010102_REV: cMin = 0.0f; cMax = 1.0f; break;
217
218 // Misc formats.
219 case TextureFormat::SIGNED_INT8: cMin = -128.0f; cMax = 127.0f; break;
220 case TextureFormat::SIGNED_INT16: cMin = -32768.0f; cMax = 32767.0f; break;
221 case TextureFormat::SIGNED_INT32: cMin = -2147483648.0f; cMax = 2147483647.0f; break;
222 case TextureFormat::UNSIGNED_INT8: cMin = 0.0f; cMax = 255.0f; break;
223 case TextureFormat::UNSIGNED_INT16: cMin = 0.0f; cMax = 65535.0f; break;
224 case TextureFormat::UNSIGNED_INT32: cMin = 0.0f; cMax = 4294967295.f; break;
225 case TextureFormat::HALF_FLOAT: cMin = -1e3f; cMax = 1e3f; break;
226 case TextureFormat::FLOAT: cMin = -1e5f; cMax = 1e5f; break;
227 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: cMin = 0.0f; cMax = 1e4f; break;
228 case TextureFormat::UNSIGNED_INT_999_E5_REV: cMin = 0.0f; cMax = 1e5f; break;
229
230 default:
231 DE_ASSERT(false);
232 }
233
234 return Vec2(cMin, cMax);
235 }
236
237 /*--------------------------------------------------------------------*//*!
238 * \brief Get standard parameters for testing texture format
239 *
240 * Returns TextureFormatInfo that describes good parameters for exercising
241 * given TextureFormat. Parameters include value ranges per channel and
242 * suitable lookup scaling and bias in order to reduce result back to
243 * 0..1 range.
244 *//*--------------------------------------------------------------------*/
getTextureFormatInfo(const TextureFormat & format)245 TextureFormatInfo getTextureFormatInfo (const TextureFormat& format)
246 {
247 // Special cases.
248 if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT_1010102_REV))
249 return TextureFormatInfo(Vec4( 0.0f, 0.0f, 0.0f, 0.0f),
250 Vec4( 1023.0f, 1023.0f, 1023.0f, 3.0f),
251 Vec4(1.0f/1023.f, 1.0f/1023.0f, 1.0f/1023.0f, 1.0f/3.0f),
252 Vec4( 0.0f, 0.0f, 0.0f, 0.0f));
253 else if (format.order == TextureFormat::D || format.order == TextureFormat::DS)
254 return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.0f),
255 Vec4(1.0f, 1.0f, 1.0f, 0.0f),
256 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
257 Vec4(0.0f, 0.0f, 0.0f, 0.0f)); // Depth / stencil formats.
258 else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551))
259 return TextureFormatInfo(Vec4(0.0f, 0.0f, 0.0f, 0.5f),
260 Vec4(1.0f, 1.0f, 1.0f, 1.5f),
261 Vec4(1.0f, 1.0f, 1.0f, 1.0f),
262 Vec4(0.0f, 0.0f, 0.0f, 0.0f));
263
264 Vec2 cRange = getChannelValueRange(format.type);
265 BVec4 chnMask = BVec4(false);
266
267 switch (format.order)
268 {
269 case TextureFormat::R: chnMask = BVec4(true, false, false, false); break;
270 case TextureFormat::A: chnMask = BVec4(false, false, false, true); break;
271 case TextureFormat::L: chnMask = BVec4(true, true, true, false); break;
272 case TextureFormat::LA: chnMask = BVec4(true, true, true, true); break;
273 case TextureFormat::RG: chnMask = BVec4(true, true, false, false); break;
274 case TextureFormat::RGB: chnMask = BVec4(true, true, true, false); break;
275 case TextureFormat::RGBA: chnMask = BVec4(true, true, true, true); break;
276 case TextureFormat::sRGB: chnMask = BVec4(true, true, true, false); break;
277 case TextureFormat::sRGBA: chnMask = BVec4(true, true, true, true); break;
278 case TextureFormat::D: chnMask = BVec4(true, true, true, false); break;
279 case TextureFormat::DS: chnMask = BVec4(true, true, true, true); break;
280 default:
281 DE_ASSERT(false);
282 }
283
284 float scale = 1.0f / (cRange[1] - cRange[0]);
285 float bias = -cRange[0] * scale;
286
287 return TextureFormatInfo(select(cRange[0], 0.0f, chnMask),
288 select(cRange[1], 0.0f, chnMask),
289 select(scale, 1.0f, chnMask),
290 select(bias, 0.0f, chnMask));
291 }
292
getChannelBitDepth(TextureFormat::ChannelType channelType)293 static IVec4 getChannelBitDepth (TextureFormat::ChannelType channelType)
294 {
295 switch (channelType)
296 {
297 case TextureFormat::SNORM_INT8: return IVec4(8);
298 case TextureFormat::SNORM_INT16: return IVec4(16);
299 case TextureFormat::SNORM_INT32: return IVec4(32);
300 case TextureFormat::UNORM_INT8: return IVec4(8);
301 case TextureFormat::UNORM_INT16: return IVec4(16);
302 case TextureFormat::UNORM_INT32: return IVec4(32);
303 case TextureFormat::UNORM_SHORT_565: return IVec4(5,6,5,0);
304 case TextureFormat::UNORM_SHORT_4444: return IVec4(4);
305 case TextureFormat::UNORM_SHORT_555: return IVec4(5,5,5,0);
306 case TextureFormat::UNORM_SHORT_5551: return IVec4(5,5,5,1);
307 case TextureFormat::UNORM_INT_101010: return IVec4(10,10,10,0);
308 case TextureFormat::UNORM_INT_1010102_REV: return IVec4(10,10,10,2);
309 case TextureFormat::SIGNED_INT8: return IVec4(8);
310 case TextureFormat::SIGNED_INT16: return IVec4(16);
311 case TextureFormat::SIGNED_INT32: return IVec4(32);
312 case TextureFormat::UNSIGNED_INT8: return IVec4(8);
313 case TextureFormat::UNSIGNED_INT16: return IVec4(16);
314 case TextureFormat::UNSIGNED_INT32: return IVec4(32);
315 case TextureFormat::UNSIGNED_INT_1010102_REV: return IVec4(10,10,10,2);
316 case TextureFormat::UNSIGNED_INT_24_8: return IVec4(24,0,0,8);
317 case TextureFormat::HALF_FLOAT: return IVec4(16);
318 case TextureFormat::FLOAT: return IVec4(32);
319 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return IVec4(11,11,10,0);
320 case TextureFormat::UNSIGNED_INT_999_E5_REV: return IVec4(9,9,9,0);
321 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return IVec4(32,0,0,8);
322 default:
323 DE_ASSERT(false);
324 return IVec4(0);
325 }
326 }
327
getTextureFormatBitDepth(const TextureFormat & format)328 IVec4 getTextureFormatBitDepth (const TextureFormat& format)
329 {
330 IVec4 chnBits = getChannelBitDepth(format.type);
331 BVec4 chnMask = BVec4(false);
332 IVec4 chnSwz (0,1,2,3);
333
334 switch (format.order)
335 {
336 case TextureFormat::R: chnMask = BVec4(true, false, false, false); break;
337 case TextureFormat::A: chnMask = BVec4(false, false, false, true); break;
338 case TextureFormat::RA: chnMask = BVec4(true, false, false, true); break;
339 case TextureFormat::L: chnMask = BVec4(true, true, true, false); break;
340 case TextureFormat::I: chnMask = BVec4(true, true, true, true); break;
341 case TextureFormat::LA: chnMask = BVec4(true, true, true, true); break;
342 case TextureFormat::RG: chnMask = BVec4(true, true, false, false); break;
343 case TextureFormat::RGB: chnMask = BVec4(true, true, true, false); break;
344 case TextureFormat::RGBA: chnMask = BVec4(true, true, true, true); break;
345 case TextureFormat::BGRA: chnMask = BVec4(true, true, true, true); chnSwz = IVec4(2, 1, 0, 3); break;
346 case TextureFormat::ARGB: chnMask = BVec4(true, true, true, true); chnSwz = IVec4(1, 2, 3, 0); break;
347 case TextureFormat::sRGB: chnMask = BVec4(true, true, true, false); break;
348 case TextureFormat::sRGBA: chnMask = BVec4(true, true, true, true); break;
349 case TextureFormat::D: chnMask = BVec4(true, false, false, false); break;
350 case TextureFormat::DS: chnMask = BVec4(true, false, false, true); break;
351 case TextureFormat::S: chnMask = BVec4(false, false, false, true); break;
352 default:
353 DE_ASSERT(false);
354 }
355
356 return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
357 }
358
getChannelMantissaBitDepth(TextureFormat::ChannelType channelType)359 static IVec4 getChannelMantissaBitDepth (TextureFormat::ChannelType channelType)
360 {
361 switch (channelType)
362 {
363 case TextureFormat::SNORM_INT8:
364 case TextureFormat::SNORM_INT16:
365 case TextureFormat::SNORM_INT32:
366 case TextureFormat::UNORM_INT8:
367 case TextureFormat::UNORM_INT16:
368 case TextureFormat::UNORM_INT32:
369 case TextureFormat::UNORM_SHORT_565:
370 case TextureFormat::UNORM_SHORT_4444:
371 case TextureFormat::UNORM_SHORT_555:
372 case TextureFormat::UNORM_SHORT_5551:
373 case TextureFormat::UNORM_INT_101010:
374 case TextureFormat::UNORM_INT_1010102_REV:
375 case TextureFormat::SIGNED_INT8:
376 case TextureFormat::SIGNED_INT16:
377 case TextureFormat::SIGNED_INT32:
378 case TextureFormat::UNSIGNED_INT8:
379 case TextureFormat::UNSIGNED_INT16:
380 case TextureFormat::UNSIGNED_INT32:
381 case TextureFormat::UNSIGNED_INT_1010102_REV:
382 case TextureFormat::UNSIGNED_INT_24_8:
383 case TextureFormat::UNSIGNED_INT_999_E5_REV:
384 return getChannelBitDepth(channelType);
385
386 case TextureFormat::HALF_FLOAT: return IVec4(10);
387 case TextureFormat::FLOAT: return IVec4(23);
388 case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: return IVec4(6,6,5,0);
389 case TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return IVec4(23,0,0,8);
390 default:
391 DE_ASSERT(false);
392 return IVec4(0);
393 }
394 }
395
getTextureFormatMantissaBitDepth(const TextureFormat & format)396 IVec4 getTextureFormatMantissaBitDepth (const TextureFormat& format)
397 {
398 IVec4 chnBits = getChannelMantissaBitDepth(format.type);
399 BVec4 chnMask = BVec4(false);
400 IVec4 chnSwz (0,1,2,3);
401
402 switch (format.order)
403 {
404 case TextureFormat::R: chnMask = BVec4(true, false, false, false); break;
405 case TextureFormat::A: chnMask = BVec4(false, false, false, true); break;
406 case TextureFormat::RA: chnMask = BVec4(true, false, false, true); break;
407 case TextureFormat::L: chnMask = BVec4(true, true, true, false); break;
408 case TextureFormat::I: chnMask = BVec4(true, true, true, true); break;
409 case TextureFormat::LA: chnMask = BVec4(true, true, true, true); break;
410 case TextureFormat::RG: chnMask = BVec4(true, true, false, false); break;
411 case TextureFormat::RGB: chnMask = BVec4(true, true, true, false); break;
412 case TextureFormat::RGBA: chnMask = BVec4(true, true, true, true); break;
413 case TextureFormat::BGRA: chnMask = BVec4(true, true, true, true); chnSwz = IVec4(2, 1, 0, 3); break;
414 case TextureFormat::ARGB: chnMask = BVec4(true, true, true, true); chnSwz = IVec4(1, 2, 3, 0); break;
415 case TextureFormat::sRGB: chnMask = BVec4(true, true, true, false); break;
416 case TextureFormat::sRGBA: chnMask = BVec4(true, true, true, true); break;
417 case TextureFormat::D: chnMask = BVec4(true, false, false, false); break;
418 case TextureFormat::DS: chnMask = BVec4(true, false, false, true); break;
419 case TextureFormat::S: chnMask = BVec4(false, false, false, true); break;
420 default:
421 DE_ASSERT(false);
422 }
423
424 return select(chnBits.swizzle(chnSwz.x(), chnSwz.y(), chnSwz.z(), chnSwz.w()), IVec4(0), chnMask);
425 }
426
linearInterpolate(float t,float minVal,float maxVal)427 static inline float linearInterpolate (float t, float minVal, float maxVal)
428 {
429 return minVal + (maxVal - minVal) * t;
430 }
431
linearInterpolate(float t,const Vec4 & a,const Vec4 & b)432 static inline Vec4 linearInterpolate (float t, const Vec4& a, const Vec4& b)
433 {
434 return a + (b - a) * t;
435 }
436
437 enum
438 {
439 CLEAR_OPTIMIZE_THRESHOLD = 128,
440 CLEAR_OPTIMIZE_MAX_PIXEL_SIZE = 8
441 };
442
fillRow(const PixelBufferAccess & dst,int y,int z,int pixelSize,const deUint8 * pixel)443 inline void fillRow (const PixelBufferAccess& dst, int y, int z, int pixelSize, const deUint8* pixel)
444 {
445 deUint8* dstPtr = (deUint8*)dst.getDataPtr() + z*dst.getSlicePitch() + y*dst.getRowPitch();
446 int width = dst.getWidth();
447
448 if (pixelSize == 8 && deIsAlignedPtr(dstPtr, pixelSize) && deIsAlignedPtr(dstPtr, pixelSize))
449 {
450 deUint64 val;
451 memcpy(&val, pixel, sizeof(val));
452
453 for (int i = 0; i < width; i++)
454 ((deUint64*)dstPtr)[i] = val;
455 }
456 else if (pixelSize == 4 && deIsAlignedPtr(dstPtr, pixelSize) && deIsAlignedPtr(dstPtr, pixelSize))
457 {
458 deUint32 val;
459 memcpy(&val, pixel, sizeof(val));
460
461 for (int i = 0; i < width; i++)
462 ((deUint32*)dstPtr)[i] = val;
463 }
464 else
465 {
466 for (int i = 0; i < width; i++)
467 for (int j = 0; j < pixelSize; j++)
468 dstPtr[i*pixelSize+j] = pixel[j];
469 }
470 }
471
clear(const PixelBufferAccess & access,const Vec4 & color)472 void clear (const PixelBufferAccess& access, const Vec4& color)
473 {
474 int pixelSize = access.getFormat().getPixelSize();
475 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
476 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE)
477 {
478 // Convert to destination format.
479 union
480 {
481 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
482 deUint64 u64; // Forces 64-bit alignment.
483 } pixel;
484 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
485 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
486
487 for (int z = 0; z < access.getDepth(); z++)
488 for (int y = 0; y < access.getHeight(); y++)
489 fillRow(access, y, z, pixelSize, &pixel.u8[0]);
490 }
491 else
492 {
493 for (int z = 0; z < access.getDepth(); z++)
494 for (int y = 0; y < access.getHeight(); y++)
495 for (int x = 0; x < access.getWidth(); x++)
496 access.setPixel(color, x, y, z);
497 }
498 }
499
clear(const PixelBufferAccess & access,const IVec4 & color)500 void clear (const PixelBufferAccess& access, const IVec4& color)
501 {
502 int pixelSize = access.getFormat().getPixelSize();
503 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
504 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE)
505 {
506 // Convert to destination format.
507 union
508 {
509 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
510 deUint64 u64; // Forces 64-bit alignment.
511 } pixel;
512 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
513 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixel(color, 0, 0);
514
515 for (int z = 0; z < access.getDepth(); z++)
516 for (int y = 0; y < access.getHeight(); y++)
517 fillRow(access, y, z, pixelSize, &pixel.u8[0]);
518 }
519 else
520 {
521 for (int z = 0; z < access.getDepth(); z++)
522 for (int y = 0; y < access.getHeight(); y++)
523 for (int x = 0; x < access.getWidth(); x++)
524 access.setPixel(color, x, y, z);
525 }
526 }
527
clearDepth(const PixelBufferAccess & access,float depth)528 void clearDepth (const PixelBufferAccess& access, float depth)
529 {
530 int pixelSize = access.getFormat().getPixelSize();
531 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
532 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE)
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]).setPixDepth(depth, 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.setPixDepth(depth, x, y, z);
553 }
554 }
555
clearStencil(const PixelBufferAccess & access,int stencil)556 void clearStencil (const PixelBufferAccess& access, int stencil)
557 {
558 int pixelSize = access.getFormat().getPixelSize();
559 if (access.getWidth()*access.getHeight()*access.getDepth() >= CLEAR_OPTIMIZE_THRESHOLD &&
560 pixelSize < CLEAR_OPTIMIZE_MAX_PIXEL_SIZE)
561 {
562 // Convert to destination format.
563 union
564 {
565 deUint8 u8[CLEAR_OPTIMIZE_MAX_PIXEL_SIZE];
566 deUint64 u64; // Forces 64-bit alignment.
567 } pixel;
568 DE_STATIC_ASSERT(sizeof(pixel) == CLEAR_OPTIMIZE_MAX_PIXEL_SIZE);
569 PixelBufferAccess(access.getFormat(), 1, 1, 1, 0, 0, &pixel.u8[0]).setPixStencil(stencil, 0, 0);
570
571 for (int z = 0; z < access.getDepth(); z++)
572 for (int y = 0; y < access.getHeight(); y++)
573 fillRow(access, y, z, pixelSize, &pixel.u8[0]);
574 }
575 else
576 {
577 for (int z = 0; z < access.getDepth(); z++)
578 for (int y = 0; y < access.getHeight(); y++)
579 for (int x = 0; x < access.getWidth(); x++)
580 access.setPixStencil(stencil, x, y, z);
581 }
582 }
583
fillWithComponentGradients1D(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)584 static void fillWithComponentGradients1D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
585 {
586 DE_ASSERT(access.getHeight() == 1);
587 for (int x = 0; x < access.getWidth(); x++)
588 {
589 float s = ((float)x + 0.5f) / (float)access.getWidth();
590
591 float r = linearInterpolate(s, minVal.x(), maxVal.x());
592 float g = linearInterpolate(s, minVal.y(), maxVal.y());
593 float b = linearInterpolate(s, minVal.z(), maxVal.z());
594 float a = linearInterpolate(s, minVal.w(), maxVal.w());
595
596 access.setPixel(tcu::Vec4(r, g, b, a), x, 0);
597 }
598 }
599
fillWithComponentGradients2D(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)600 static void fillWithComponentGradients2D (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
601 {
602 for (int y = 0; y < access.getHeight(); y++)
603 {
604 for (int x = 0; x < access.getWidth(); x++)
605 {
606 float s = ((float)x + 0.5f) / (float)access.getWidth();
607 float t = ((float)y + 0.5f) / (float)access.getHeight();
608
609 float r = linearInterpolate(( s + t) *0.5f, minVal.x(), maxVal.x());
610 float g = linearInterpolate(( s + (1.0f-t))*0.5f, minVal.y(), maxVal.y());
611 float b = linearInterpolate(((1.0f-s) + t) *0.5f, minVal.z(), maxVal.z());
612 float a = linearInterpolate(((1.0f-s) + (1.0f-t))*0.5f, minVal.w(), maxVal.w());
613
614 access.setPixel(tcu::Vec4(r, g, b, a), x, y);
615 }
616 }
617 }
618
fillWithComponentGradients3D(const PixelBufferAccess & dst,const Vec4 & minVal,const Vec4 & maxVal)619 static void fillWithComponentGradients3D (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal)
620 {
621 for (int z = 0; z < dst.getDepth(); z++)
622 {
623 for (int y = 0; y < dst.getHeight(); y++)
624 {
625 for (int x = 0; x < dst.getWidth(); x++)
626 {
627 float s = ((float)x + 0.5f) / (float)dst.getWidth();
628 float t = ((float)y + 0.5f) / (float)dst.getHeight();
629 float p = ((float)z + 0.5f) / (float)dst.getDepth();
630
631 float r = linearInterpolate(s, minVal.x(), maxVal.x());
632 float g = linearInterpolate(t, minVal.y(), maxVal.y());
633 float b = linearInterpolate(p, minVal.z(), maxVal.z());
634 float a = linearInterpolate(1.0f - (s+t+p)/3.0f, minVal.w(), maxVal.w());
635
636 dst.setPixel(tcu::Vec4(r, g, b, a), x, y, z);
637 }
638 }
639 }
640 }
641
fillWithComponentGradients(const PixelBufferAccess & access,const Vec4 & minVal,const Vec4 & maxVal)642 void fillWithComponentGradients (const PixelBufferAccess& access, const Vec4& minVal, const Vec4& maxVal)
643 {
644 if (access.getHeight() == 1 && access.getDepth() == 1)
645 fillWithComponentGradients1D(access, minVal, maxVal);
646 else if (access.getDepth() == 1)
647 fillWithComponentGradients2D(access, minVal, maxVal);
648 else
649 fillWithComponentGradients3D(access, minVal, maxVal);
650 }
651
fillWithGrid1D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)652 void fillWithGrid1D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
653 {
654 for (int x = 0; x < access.getWidth(); x++)
655 {
656 int mx = (x / cellSize) % 2;
657
658 if (mx)
659 access.setPixel(colorB, x, 0);
660 else
661 access.setPixel(colorA, x, 0);
662 }
663 }
664
fillWithGrid2D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)665 void fillWithGrid2D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
666 {
667 for (int y = 0; y < access.getHeight(); y++)
668 {
669 for (int x = 0; x < access.getWidth(); x++)
670 {
671 int mx = (x / cellSize) % 2;
672 int my = (y / cellSize) % 2;
673
674 if (mx ^ my)
675 access.setPixel(colorB, x, y);
676 else
677 access.setPixel(colorA, x, y);
678 }
679 }
680 }
681
fillWithGrid3D(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)682 void fillWithGrid3D (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
683 {
684 for (int z = 0; z < access.getDepth(); z++)
685 {
686 for (int y = 0; y < access.getHeight(); y++)
687 {
688 for (int x = 0; x < access.getWidth(); x++)
689 {
690 int mx = (x / cellSize) % 2;
691 int my = (y / cellSize) % 2;
692 int mz = (z / cellSize) % 2;
693
694 if (mx ^ my ^ mz)
695 access.setPixel(colorB, x, y, z);
696 else
697 access.setPixel(colorA, x, y, z);
698 }
699 }
700 }
701 }
702
fillWithGrid(const PixelBufferAccess & access,int cellSize,const Vec4 & colorA,const Vec4 & colorB)703 void fillWithGrid (const PixelBufferAccess& access, int cellSize, const Vec4& colorA, const Vec4& colorB)
704 {
705 if (access.getHeight() == 1 && access.getDepth() == 1)
706 fillWithGrid1D(access, cellSize, colorA, colorB);
707 else if (access.getDepth() == 1)
708 fillWithGrid2D(access, cellSize, colorA, colorB);
709 else
710 fillWithGrid3D(access, cellSize, colorA, colorB);
711 }
712
fillWithRepeatableGradient(const PixelBufferAccess & access,const Vec4 & colorA,const Vec4 & colorB)713 void fillWithRepeatableGradient (const PixelBufferAccess& access, const Vec4& colorA, const Vec4& colorB)
714 {
715 for (int y = 0; y < access.getHeight(); y++)
716 {
717 for (int x = 0; x < access.getWidth(); x++)
718 {
719 float s = ((float)x + 0.5f) / (float)access.getWidth();
720 float t = ((float)y + 0.5f) / (float)access.getHeight();
721
722 float a = s > 0.5f ? (2.0f - 2.0f*s) : 2.0f*s;
723 float b = t > 0.5f ? (2.0f - 2.0f*t) : 2.0f*t;
724
725 float p = deFloatClamp(deFloatSqrt(a*a + b*b), 0.0f, 1.0f);
726 access.setPixel(linearInterpolate(p, colorA, colorB), x, y);
727 }
728 }
729 }
730
fillWithRGBAQuads(const PixelBufferAccess & dst)731 void fillWithRGBAQuads (const PixelBufferAccess& dst)
732 {
733 TCU_CHECK_INTERNAL(dst.getDepth() == 1);
734 int width = dst.getWidth();
735 int height = dst.getHeight();
736 int left = width/2;
737 int top = height/2;
738
739 clear(getSubregion(dst, 0, 0, 0, left, top, 1), Vec4(1.0f, 0.0f, 0.0f, 1.0f));
740 clear(getSubregion(dst, left, 0, 0, width-left, top, 1), Vec4(0.0f, 1.0f, 0.0f, 1.0f));
741 clear(getSubregion(dst, 0, top, 0, left, height-top, 1), Vec4(0.0f, 0.0f, 1.0f, 0.0f));
742 clear(getSubregion(dst, left, top, 0, width-left, height-top, 1), Vec4(0.5f, 0.5f, 0.5f, 1.0f));
743 }
744
745 // \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators.
fillWithMetaballs(const PixelBufferAccess & dst,int numBalls,deUint32 seed)746 void fillWithMetaballs (const PixelBufferAccess& dst, int numBalls, deUint32 seed)
747 {
748 TCU_CHECK_INTERNAL(dst.getDepth() == 1);
749 std::vector<Vec2> points(numBalls);
750 de::Random rnd(seed);
751
752 for (int i = 0; i < numBalls; i++)
753 {
754 float x = rnd.getFloat();
755 float y = rnd.getFloat();
756 points[i] = (Vec2(x, y));
757 }
758
759 for (int y = 0; y < dst.getHeight(); y++)
760 for (int x = 0; x < dst.getWidth(); x++)
761 {
762 Vec2 p((float)x/(float)dst.getWidth(), (float)y/(float)dst.getHeight());
763
764 float sum = 0.0f;
765 for (std::vector<Vec2>::const_iterator i = points.begin(); i != points.end(); i++)
766 {
767 Vec2 d = p - *i;
768 float f = 0.01f / (d.x()*d.x() + d.y()*d.y());
769
770 sum += f;
771 }
772
773 dst.setPixel(Vec4(sum), x, y);
774 }
775 }
776
copy(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src)777 void copy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src)
778 {
779 int width = dst.getWidth();
780 int height = dst.getHeight();
781 int depth = dst.getDepth();
782
783 DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth);
784
785 if (src.getFormat() == dst.getFormat())
786 {
787 // Fast-path for matching formats.
788 int pixelSize = src.getFormat().getPixelSize();
789
790 for (int z = 0; z < depth; z++)
791 for (int y = 0; y < height; y++)
792 deMemcpy((deUint8*)dst.getDataPtr() + z*dst.getSlicePitch() + y*dst.getRowPitch(),
793 (const deUint8*)src.getDataPtr() + z*src.getSlicePitch() + y*src.getRowPitch(),
794 pixelSize*width);
795 }
796 else
797 {
798 TextureChannelClass srcClass = getTextureChannelClass(src.getFormat().type);
799 TextureChannelClass dstClass = getTextureChannelClass(dst.getFormat().type);
800 bool srcIsInt = srcClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || srcClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
801 bool dstIsInt = dstClass == TEXTURECHANNELCLASS_SIGNED_INTEGER || dstClass == TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
802
803 if (srcIsInt && dstIsInt)
804 {
805 for (int z = 0; z < depth; z++)
806 for (int y = 0; y < height; y++)
807 for (int x = 0; x < width; x++)
808 dst.setPixel(src.getPixelInt(x, y, z), x, y, z);
809 }
810 else
811 {
812 for (int z = 0; z < depth; z++)
813 for (int y = 0; y < height; y++)
814 for (int x = 0; x < width; x++)
815 dst.setPixel(src.getPixel(x, y, z), x, y, z);
816 }
817 }
818 }
819
scale(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,Sampler::FilterMode filter)820 void scale (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, Sampler::FilterMode filter)
821 {
822 DE_ASSERT(filter == Sampler::NEAREST || filter == Sampler::LINEAR);
823
824 Sampler sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE,
825 filter, filter, 0.0f, false);
826
827 float sX = (float)src.getWidth() / (float)dst.getWidth();
828 float sY = (float)src.getHeight() / (float)dst.getHeight();
829 float sZ = (float)src.getDepth() / (float)dst.getDepth();
830
831 if (dst.getDepth() == 1 && src.getDepth() == 1)
832 {
833 for (int y = 0; y < dst.getHeight(); y++)
834 for (int x = 0; x < dst.getWidth(); x++)
835 dst.setPixel(src.sample2D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, 0), x, y);
836 }
837 else
838 {
839 for (int z = 0; z < dst.getDepth(); z++)
840 for (int y = 0; y < dst.getHeight(); y++)
841 for (int x = 0; x < dst.getWidth(); x++)
842 dst.setPixel(src.sample3D(sampler, filter, (x+0.5f)*sX, (y+0.5f)*sY, (z+0.5f)*sZ), x, y, z);
843 }
844 }
845
estimatePixelValueRange(const ConstPixelBufferAccess & access,Vec4 & minVal,Vec4 & maxVal)846 void estimatePixelValueRange (const ConstPixelBufferAccess& access, Vec4& minVal, Vec4& maxVal)
847 {
848 const TextureFormat& format = access.getFormat();
849
850 switch (format.type)
851 {
852 case TextureFormat::UNORM_INT8:
853 case TextureFormat::UNORM_INT16:
854 // Normalized unsigned formats.
855 minVal = Vec4(0.0f);
856 maxVal = Vec4(1.0f);
857 break;
858
859 case TextureFormat::SNORM_INT8:
860 case TextureFormat::SNORM_INT16:
861 // Normalized signed formats.
862 minVal = Vec4(-1.0f);
863 maxVal = Vec4(+1.0f);
864 break;
865
866 default:
867 // \note Samples every 4/8th pixel.
868 minVal = Vec4(std::numeric_limits<float>::max());
869 maxVal = Vec4(std::numeric_limits<float>::min());
870
871 for (int z = 0; z < access.getDepth(); z += 2)
872 {
873 for (int y = 0; y < access.getHeight(); y += 2)
874 {
875 for (int x = 0; x < access.getWidth(); x += 2)
876 {
877 Vec4 p = access.getPixel(x, y, z);
878
879 minVal[0] = de::min(minVal[0], p[0]);
880 minVal[1] = de::min(minVal[1], p[1]);
881 minVal[2] = de::min(minVal[2], p[2]);
882 minVal[3] = de::min(minVal[3], p[3]);
883
884 maxVal[0] = de::max(maxVal[0], p[0]);
885 maxVal[1] = de::max(maxVal[1], p[1]);
886 maxVal[2] = de::max(maxVal[2], p[2]);
887 maxVal[3] = de::max(maxVal[3], p[3]);
888 }
889 }
890 }
891 break;
892 }
893 }
894
computePixelScaleBias(const ConstPixelBufferAccess & access,Vec4 & scale,Vec4 & bias)895 void computePixelScaleBias (const ConstPixelBufferAccess& access, Vec4& scale, Vec4& bias)
896 {
897 Vec4 minVal, maxVal;
898 estimatePixelValueRange(access, minVal, maxVal);
899
900 const float eps = 0.0001f;
901
902 for (int c = 0; c < 4; c++)
903 {
904 if (maxVal[c] - minVal[c] < eps)
905 {
906 scale[c] = (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
907 bias[c] = (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
908 }
909 else
910 {
911 scale[c] = 1.0f / (maxVal[c] - minVal[c]);
912 bias[c] = 0.0f - minVal[c]*scale[c];
913 }
914 }
915 }
916
getCubeArrayFaceIndex(CubeFace face)917 int getCubeArrayFaceIndex (CubeFace face)
918 {
919 DE_ASSERT((int)face >= 0 && face < CUBEFACE_LAST);
920
921 switch (face)
922 {
923 case CUBEFACE_POSITIVE_X: return 0;
924 case CUBEFACE_NEGATIVE_X: return 1;
925 case CUBEFACE_POSITIVE_Y: return 2;
926 case CUBEFACE_NEGATIVE_Y: return 3;
927 case CUBEFACE_POSITIVE_Z: return 4;
928 case CUBEFACE_NEGATIVE_Z: return 5;
929
930 default:
931 return -1;
932 }
933 }
934
935 } // tcu
936