1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
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 Utility functions and structures for texture tests. This code
22 * is originated from the modules/glshared/glsTextureTestUtil.hpp and it
23 * is tightly coupled with the GLES and Vulkan texture tests!
24 *//*--------------------------------------------------------------------*/
25
26 #include "gluTextureTestUtil.hpp"
27
28 #include "tcuFloat.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuVectorUtil.hpp"
32
33 #include "deMath.h"
34 #include "deStringUtil.hpp"
35
36 #include <string>
37
38 using std::string;
39
40 namespace glu
41 {
42
43 namespace TextureTestUtil
44 {
45
46 enum
47 {
48 MIN_SUBPIXEL_BITS = 4
49 };
50
getSamplerType(tcu::TextureFormat format)51 SamplerType getSamplerType(tcu::TextureFormat format)
52 {
53 using tcu::TextureFormat;
54
55 switch (format.type)
56 {
57 case TextureFormat::SIGNED_INT8:
58 case TextureFormat::SIGNED_INT16:
59 case TextureFormat::SIGNED_INT32:
60 return SAMPLERTYPE_INT;
61
62 case TextureFormat::UNSIGNED_INT8:
63 case TextureFormat::UNSIGNED_INT32:
64 case TextureFormat::UNSIGNED_INT_1010102_REV:
65 return SAMPLERTYPE_UINT;
66
67 // Texture formats used in depth/stencil textures.
68 case TextureFormat::UNSIGNED_INT16:
69 case TextureFormat::UNSIGNED_INT_24_8:
70 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FLOAT :
71 SAMPLERTYPE_UINT;
72
73 default:
74 return SAMPLERTYPE_FLOAT;
75 }
76 }
77
getFetchSamplerType(tcu::TextureFormat format)78 SamplerType getFetchSamplerType(tcu::TextureFormat format)
79 {
80 using tcu::TextureFormat;
81
82 switch (format.type)
83 {
84 case TextureFormat::SIGNED_INT8:
85 case TextureFormat::SIGNED_INT16:
86 case TextureFormat::SIGNED_INT32:
87 return SAMPLERTYPE_FETCH_INT;
88
89 case TextureFormat::UNSIGNED_INT8:
90 case TextureFormat::UNSIGNED_INT32:
91 case TextureFormat::UNSIGNED_INT_1010102_REV:
92 return SAMPLERTYPE_FETCH_UINT;
93
94 // Texture formats used in depth/stencil textures.
95 case TextureFormat::UNSIGNED_INT16:
96 case TextureFormat::UNSIGNED_INT_24_8:
97 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FETCH_FLOAT :
98 SAMPLERTYPE_FETCH_UINT;
99
100 default:
101 return SAMPLERTYPE_FETCH_FLOAT;
102 }
103 }
104
getSubView(const tcu::Texture1DView & view,int baseLevel,int maxLevel,tcu::ImageViewMinLodParams * minLodParams DE_UNUSED_ATTR)105 static tcu::Texture1DView getSubView(const tcu::Texture1DView &view, int baseLevel, int maxLevel,
106 tcu::ImageViewMinLodParams *minLodParams DE_UNUSED_ATTR)
107 {
108 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels() - 1);
109 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels() - 1);
110 const int numLevels = clampedMax - clampedBase + 1;
111 return tcu::Texture1DView(numLevels, view.getLevels() + clampedBase);
112 }
113
getSubView(const tcu::Texture2DView & view,int baseLevel,int maxLevel,tcu::ImageViewMinLodParams * minLodParams=DE_NULL)114 static tcu::Texture2DView getSubView(const tcu::Texture2DView &view, int baseLevel, int maxLevel,
115 tcu::ImageViewMinLodParams *minLodParams = DE_NULL)
116 {
117 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels() - 1);
118 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels() - 1);
119 const int numLevels = clampedMax - clampedBase + 1;
120 return tcu::Texture2DView(numLevels, view.getLevels() + clampedBase, view.isES2(), minLodParams);
121 }
122
getSubView(const tcu::TextureCubeView & view,int baseLevel,int maxLevel,tcu::ImageViewMinLodParams * minLodParams=DE_NULL)123 static tcu::TextureCubeView getSubView(const tcu::TextureCubeView &view, int baseLevel, int maxLevel,
124 tcu::ImageViewMinLodParams *minLodParams = DE_NULL)
125 {
126 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels() - 1);
127 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels() - 1);
128 const int numLevels = clampedMax - clampedBase + 1;
129 const tcu::ConstPixelBufferAccess *levels[tcu::CUBEFACE_LAST];
130
131 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
132 levels[face] = view.getFaceLevels((tcu::CubeFace)face) + clampedBase;
133
134 return tcu::TextureCubeView(numLevels, levels, false, minLodParams);
135 }
136
getSubView(const tcu::Texture3DView & view,int baseLevel,int maxLevel,tcu::ImageViewMinLodParams * minLodParams=DE_NULL)137 static tcu::Texture3DView getSubView(const tcu::Texture3DView &view, int baseLevel, int maxLevel,
138 tcu::ImageViewMinLodParams *minLodParams = DE_NULL)
139 {
140 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels() - 1);
141 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels() - 1);
142 const int numLevels = clampedMax - clampedBase + 1;
143 return tcu::Texture3DView(numLevels, view.getLevels() + clampedBase, false, minLodParams);
144 }
145
getSubView(const tcu::TextureCubeArrayView & view,int baseLevel,int maxLevel,tcu::ImageViewMinLodParams * minLodParams DE_UNUSED_ATTR=DE_NULL)146 static tcu::TextureCubeArrayView getSubView(const tcu::TextureCubeArrayView &view, int baseLevel, int maxLevel,
147 tcu::ImageViewMinLodParams *minLodParams DE_UNUSED_ATTR = DE_NULL)
148 {
149 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels() - 1);
150 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels() - 1);
151 const int numLevels = clampedMax - clampedBase + 1;
152 return tcu::TextureCubeArrayView(numLevels, view.getLevels() + clampedBase);
153 }
154
linearInterpolate(float t,float minVal,float maxVal)155 inline float linearInterpolate(float t, float minVal, float maxVal)
156 {
157 return minVal + (maxVal - minVal) * t;
158 }
159
linearInterpolate(float t,const tcu::Vec4 & a,const tcu::Vec4 & b)160 inline tcu::Vec4 linearInterpolate(float t, const tcu::Vec4 &a, const tcu::Vec4 &b)
161 {
162 return a + (b - a) * t;
163 }
164
bilinearInterpolate(float x,float y,const tcu::Vec4 & quad)165 inline float bilinearInterpolate(float x, float y, const tcu::Vec4 &quad)
166 {
167 float w00 = (1.0f - x) * (1.0f - y);
168 float w01 = (1.0f - x) * y;
169 float w10 = x * (1.0f - y);
170 float w11 = x * y;
171 return quad.x() * w00 + quad.y() * w10 + quad.z() * w01 + quad.w() * w11;
172 }
173
triangleInterpolate(float v0,float v1,float v2,float x,float y)174 float triangleInterpolate(float v0, float v1, float v2, float x, float y)
175 {
176 return v0 + (v2 - v0) * x + (v1 - v0) * y;
177 }
178
triangleInterpolate(const tcu::Vec3 & v,float x,float y)179 float triangleInterpolate(const tcu::Vec3 &v, float x, float y)
180 {
181 return triangleInterpolate(v.x(), v.y(), v.z(), x, y);
182 }
183
184 // 1D lookup LOD computation.
185
computeLodFromDerivates(LodMode mode,float dudx,float dudy)186 float computeLodFromDerivates(LodMode mode, float dudx, float dudy)
187 {
188 float p = 0.0f;
189 switch (mode)
190 {
191 // \note [mika] Min and max bounds equal to exact with 1D textures
192 case LODMODE_EXACT:
193 case LODMODE_MIN_BOUND:
194 case LODMODE_MAX_BOUND:
195 p = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
196 break;
197
198 default:
199 DE_ASSERT(false);
200 }
201
202 return deFloatLog2(p);
203 }
204
computeNonProjectedTriLod(LodMode mode,const tcu::IVec2 & dstSize,int32_t srcSize,const tcu::Vec3 & sq)205 float computeNonProjectedTriLod(LodMode mode, const tcu::IVec2 &dstSize, int32_t srcSize, const tcu::Vec3 &sq)
206 {
207 float dux = (sq.z() - sq.x()) * (float)srcSize;
208 float duy = (sq.y() - sq.x()) * (float)srcSize;
209 float dx = (float)dstSize.x();
210 float dy = (float)dstSize.y();
211
212 return computeLodFromDerivates(mode, dux / dx, duy / dy);
213 }
214
215 // 2D lookup LOD computation.
216
computeLodFromDerivates(LodMode mode,float dudx,float dvdx,float dudy,float dvdy)217 float computeLodFromDerivates(LodMode mode, float dudx, float dvdx, float dudy, float dvdy)
218 {
219 float p = 0.0f;
220 switch (mode)
221 {
222 case LODMODE_EXACT:
223 p = de::max(deFloatSqrt(dudx * dudx + dvdx * dvdx), deFloatSqrt(dudy * dudy + dvdy * dvdy));
224 break;
225
226 case LODMODE_MIN_BOUND:
227 case LODMODE_MAX_BOUND:
228 {
229 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
230 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
231
232 p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv;
233 break;
234 }
235
236 default:
237 DE_ASSERT(false);
238 }
239
240 return deFloatLog2(p);
241 }
242
computeNonProjectedTriLod(LodMode mode,const tcu::IVec2 & dstSize,const tcu::IVec2 & srcSize,const tcu::Vec3 & sq,const tcu::Vec3 & tq)243 float computeNonProjectedTriLod(LodMode mode, const tcu::IVec2 &dstSize, const tcu::IVec2 &srcSize, const tcu::Vec3 &sq,
244 const tcu::Vec3 &tq)
245 {
246 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
247 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
248 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
249 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
250 float dx = (float)dstSize.x();
251 float dy = (float)dstSize.y();
252
253 return computeLodFromDerivates(mode, dux / dx, dvx / dx, duy / dy, dvy / dy);
254 }
255
256 // 3D lookup LOD computation.
257
computeLodFromDerivates(LodMode mode,float dudx,float dvdx,float dwdx,float dudy,float dvdy,float dwdy)258 float computeLodFromDerivates(LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy)
259 {
260 float p = 0.0f;
261 switch (mode)
262 {
263 case LODMODE_EXACT:
264 p = de::max(deFloatSqrt(dudx * dudx + dvdx * dvdx + dwdx * dwdx),
265 deFloatSqrt(dudy * dudy + dvdy * dvdy + dwdy * dwdy));
266 break;
267
268 case LODMODE_MIN_BOUND:
269 case LODMODE_MAX_BOUND:
270 {
271 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
272 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
273 float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy));
274
275 p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw);
276 break;
277 }
278
279 default:
280 DE_ASSERT(false);
281 }
282
283 return deFloatLog2(p);
284 }
285
computeNonProjectedTriLod(LodMode mode,const tcu::IVec2 & dstSize,const tcu::IVec3 & srcSize,const tcu::Vec3 & sq,const tcu::Vec3 & tq,const tcu::Vec3 & rq)286 float computeNonProjectedTriLod(LodMode mode, const tcu::IVec2 &dstSize, const tcu::IVec3 &srcSize, const tcu::Vec3 &sq,
287 const tcu::Vec3 &tq, const tcu::Vec3 &rq)
288 {
289 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
290 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
291 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
292 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
293 float dwx = (rq.z() - rq.x()) * (float)srcSize.z();
294 float dwy = (rq.y() - rq.x()) * (float)srcSize.z();
295 float dx = (float)dstSize.x();
296 float dy = (float)dstSize.y();
297
298 return computeLodFromDerivates(mode, dux / dx, dvx / dx, dwx / dx, duy / dy, dvy / dy, dwy / dy);
299 }
300
projectedTriInterpolate(const tcu::Vec3 & s,const tcu::Vec3 & w,float nx,float ny)301 static inline float projectedTriInterpolate(const tcu::Vec3 &s, const tcu::Vec3 &w, float nx, float ny)
302 {
303 return (s[0] * (1.0f - nx - ny) / w[0] + s[1] * ny / w[1] + s[2] * nx / w[2]) /
304 ((1.0f - nx - ny) / w[0] + ny / w[1] + nx / w[2]);
305 }
306
triDerivateX(const tcu::Vec3 & s,const tcu::Vec3 & w,float wx,float width,float ny)307 static inline float triDerivateX(const tcu::Vec3 &s, const tcu::Vec3 &w, float wx, float width, float ny)
308 {
309 float d = w[1] * w[2] * (width * (ny - 1.0f) + wx) - w[0] * (w[2] * width * ny + w[1] * wx);
310 return (w[0] * w[1] * w[2] * width *
311 (w[1] * (s[0] - s[2]) * (ny - 1.0f) + ny * (w[2] * (s[1] - s[0]) + w[0] * (s[2] - s[1])))) /
312 (d * d);
313 }
314
triDerivateY(const tcu::Vec3 & s,const tcu::Vec3 & w,float wy,float height,float nx)315 static inline float triDerivateY(const tcu::Vec3 &s, const tcu::Vec3 &w, float wy, float height, float nx)
316 {
317 float d = w[1] * w[2] * (height * (nx - 1.0f) + wy) - w[0] * (w[1] * height * nx + w[2] * wy);
318 return (w[0] * w[1] * w[2] * height *
319 (w[2] * (s[0] - s[1]) * (nx - 1.0f) + nx * (w[0] * (s[1] - s[2]) + w[1] * (s[2] - s[0])))) /
320 (d * d);
321 }
322
323 // 1D lookup LOD.
computeProjectedTriLod(LodMode mode,const tcu::Vec3 & u,const tcu::Vec3 & projection,float wx,float wy,float width,float height)324 static float computeProjectedTriLod(LodMode mode, const tcu::Vec3 &u, const tcu::Vec3 &projection, float wx, float wy,
325 float width, float height)
326 {
327 // Exact derivatives.
328 float dudx = triDerivateX(u, projection, wx, width, wy / height);
329 float dudy = triDerivateY(u, projection, wy, height, wx / width);
330
331 return computeLodFromDerivates(mode, dudx, dudy);
332 }
333
334 // 2D lookup LOD.
computeProjectedTriLod(LodMode mode,const tcu::Vec3 & u,const tcu::Vec3 & v,const tcu::Vec3 & projection,float wx,float wy,float width,float height)335 static float computeProjectedTriLod(LodMode mode, const tcu::Vec3 &u, const tcu::Vec3 &v, const tcu::Vec3 &projection,
336 float wx, float wy, float width, float height)
337 {
338 // Exact derivatives.
339 float dudx = triDerivateX(u, projection, wx, width, wy / height);
340 float dvdx = triDerivateX(v, projection, wx, width, wy / height);
341 float dudy = triDerivateY(u, projection, wy, height, wx / width);
342 float dvdy = triDerivateY(v, projection, wy, height, wx / width);
343
344 return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy);
345 }
346
347 // 3D lookup LOD.
computeProjectedTriLod(LodMode mode,const tcu::Vec3 & u,const tcu::Vec3 & v,const tcu::Vec3 & w,const tcu::Vec3 & projection,float wx,float wy,float width,float height)348 static float computeProjectedTriLod(LodMode mode, const tcu::Vec3 &u, const tcu::Vec3 &v, const tcu::Vec3 &w,
349 const tcu::Vec3 &projection, float wx, float wy, float width, float height)
350 {
351 // Exact derivatives.
352 float dudx = triDerivateX(u, projection, wx, width, wy / height);
353 float dvdx = triDerivateX(v, projection, wx, width, wy / height);
354 float dwdx = triDerivateX(w, projection, wx, width, wy / height);
355 float dudy = triDerivateY(u, projection, wy, height, wx / width);
356 float dvdy = triDerivateY(v, projection, wy, height, wx / width);
357 float dwdy = triDerivateY(w, projection, wy, height, wx / width);
358
359 return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy);
360 }
361
execSample(const tcu::Texture1DView & src,const ReferenceParams & params,float s,float lod)362 static inline tcu::Vec4 execSample(const tcu::Texture1DView &src, const ReferenceParams ¶ms, float s, float lod)
363 {
364 if (params.samplerType == SAMPLERTYPE_SHADOW)
365 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f);
366 else
367 return src.sample(params.sampler, s, lod);
368 }
369
execSample(const tcu::Texture2DView & src,const ReferenceParams & params,float s,float t,float lod)370 static inline tcu::Vec4 execSample(const tcu::Texture2DView &src, const ReferenceParams ¶ms, float s, float t,
371 float lod)
372 {
373 if (params.samplerType == SAMPLERTYPE_SHADOW)
374 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
375 else
376 return src.sample(params.sampler, s, t, lod);
377 }
378
execSample(const tcu::TextureCubeView & src,const ReferenceParams & params,float s,float t,float r,float lod)379 static inline tcu::Vec4 execSample(const tcu::TextureCubeView &src, const ReferenceParams ¶ms, float s, float t,
380 float r, float lod)
381 {
382 if (params.samplerType == SAMPLERTYPE_SHADOW)
383 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
384 else
385 return src.sample(params.sampler, s, t, r, lod);
386 }
387
execSample(const tcu::Texture2DArrayView & src,const ReferenceParams & params,float s,float t,float r,float lod)388 static inline tcu::Vec4 execSample(const tcu::Texture2DArrayView &src, const ReferenceParams ¶ms, float s, float t,
389 float r, float lod)
390 {
391 if (params.samplerType == SAMPLERTYPE_SHADOW)
392 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
393 else
394 return src.sample(params.sampler, s, t, r, lod);
395 }
396
execSample(const tcu::TextureCubeArrayView & src,const ReferenceParams & params,float s,float t,float r,float q,float lod)397 static inline tcu::Vec4 execSample(const tcu::TextureCubeArrayView &src, const ReferenceParams ¶ms, float s,
398 float t, float r, float q, float lod)
399 {
400 if (params.samplerType == SAMPLERTYPE_SHADOW)
401 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f);
402 else
403 return src.sample(params.sampler, s, t, r, q, lod);
404 }
405
execSample(const tcu::Texture1DArrayView & src,const ReferenceParams & params,float s,float t,float lod)406 static inline tcu::Vec4 execSample(const tcu::Texture1DArrayView &src, const ReferenceParams ¶ms, float s, float t,
407 float lod)
408 {
409 if (params.samplerType == SAMPLERTYPE_SHADOW)
410 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
411 else
412 return src.sample(params.sampler, s, t, lod);
413 }
414
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture1DView & rawSrc,const tcu::Vec4 & sq,const ReferenceParams & params)415 static void sampleTextureNonProjected(const tcu::SurfaceAccess &dst, const tcu::Texture1DView &rawSrc,
416 const tcu::Vec4 &sq, const ReferenceParams ¶ms)
417 {
418 // Separate combined DS formats
419 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
420 const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
421
422 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
423
424 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
425 int srcSize = src.getWidth();
426
427 // Coordinates and lod per triangle.
428 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
429 float triLod[2] = {de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
430 params.minLod, params.maxLod),
431 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias,
432 params.minLod, params.maxLod)};
433
434 for (int y = 0; y < dst.getHeight(); y++)
435 {
436 for (int x = 0; x < dst.getWidth(); x++)
437 {
438 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
439 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
440
441 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
442 float triX = triNdx ? 1.0f - xf : xf;
443 float triY = triNdx ? 1.0f - yf : yf;
444
445 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
446 float lod = triLod[triNdx];
447
448 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
449 }
450 }
451 }
452
453 template <class PixelAccess>
sampleTextureNonProjected(const PixelAccess & dst,const tcu::Texture2DView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const ReferenceParams & params)454 static void sampleTextureNonProjected(const PixelAccess &dst, const tcu::Texture2DView &rawSrc, const tcu::Vec4 &sq,
455 const tcu::Vec4 &tq, const ReferenceParams ¶ms)
456 {
457 // Separate combined DS formats
458 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
459 tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
460
461 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
462
463 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
464 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
465
466 // Coordinates and lod per triangle.
467 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
468 tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
469 float triLod[2] = {
470 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias,
471 params.minLod, params.maxLod),
472 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias,
473 params.minLod, params.maxLod)};
474
475 for (int y = 0; y < dst.getHeight(); y++)
476 {
477 for (int x = 0; x < dst.getWidth(); x++)
478 {
479 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
480 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
481
482 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
483 float triX = triNdx ? 1.0f - xf : xf;
484 float triY = triNdx ? 1.0f - yf : yf;
485
486 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
487 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
488 float lod = triLod[triNdx];
489
490 if (params.imageViewMinLod != 0.0f && params.samplerType == SAMPLERTYPE_FETCH_FLOAT)
491 lod = (float)params.lodTexelFetch;
492
493 if (params.float16TexCoord)
494 {
495 s = tcu::Float16(s, tcu::ROUND_TO_ZERO).asFloat();
496 t = tcu::Float16(t, tcu::ROUND_TO_ZERO).asFloat();
497 }
498
499 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
500 }
501 }
502 }
503
sampleTextureProjected(const tcu::SurfaceAccess & dst,const tcu::Texture1DView & rawSrc,const tcu::Vec4 & sq,const ReferenceParams & params)504 static void sampleTextureProjected(const tcu::SurfaceAccess &dst, const tcu::Texture1DView &rawSrc, const tcu::Vec4 &sq,
505 const ReferenceParams ¶ms)
506 {
507 // Separate combined DS formats
508 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
509 const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
510
511 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
512 float dstW = (float)dst.getWidth();
513 float dstH = (float)dst.getHeight();
514
515 tcu::Vec4 uq = sq * (float)src.getWidth();
516
517 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
518 tcu::Vec3 triU[2] = {uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1)};
519 tcu::Vec3 triW[2] = {params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1)};
520
521 for (int py = 0; py < dst.getHeight(); py++)
522 {
523 for (int px = 0; px < dst.getWidth(); px++)
524 {
525 float wx = (float)px + 0.5f;
526 float wy = (float)py + 0.5f;
527 float nx = wx / dstW;
528 float ny = wy / dstH;
529
530 int triNdx = nx + ny >= 1.0f ? 1 : 0;
531 float triWx = triNdx ? dstW - wx : wx;
532 float triWy = triNdx ? dstH - wy : wy;
533 float triNx = triNdx ? 1.0f - nx : nx;
534 float triNy = triNdx ? 1.0f - ny : ny;
535
536 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
537 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy,
538 (float)dst.getWidth(), (float)dst.getHeight()) +
539 lodBias;
540
541 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
542 }
543 }
544 }
545
546 template <class PixelAccess>
sampleTextureProjected(const PixelAccess & dst,const tcu::Texture2DView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const ReferenceParams & params)547 static void sampleTextureProjected(const PixelAccess &dst, const tcu::Texture2DView &rawSrc, const tcu::Vec4 &sq,
548 const tcu::Vec4 &tq, const ReferenceParams ¶ms)
549 {
550 // Separate combined DS formats
551 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
552 const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
553
554 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
555 float dstW = (float)dst.getWidth();
556 float dstH = (float)dst.getHeight();
557
558 tcu::Vec4 uq = sq * (float)src.getWidth();
559 tcu::Vec4 vq = tq * (float)src.getHeight();
560
561 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
562 tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
563 tcu::Vec3 triU[2] = {uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1)};
564 tcu::Vec3 triV[2] = {vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1)};
565 tcu::Vec3 triW[2] = {params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1)};
566
567 for (int py = 0; py < dst.getHeight(); py++)
568 {
569 for (int px = 0; px < dst.getWidth(); px++)
570 {
571 float wx = (float)px + 0.5f;
572 float wy = (float)py + 0.5f;
573 float nx = wx / dstW;
574 float ny = wy / dstH;
575
576 int triNdx = nx + ny >= 1.0f ? 1 : 0;
577 float triWx = triNdx ? dstW - wx : wx;
578 float triWy = triNdx ? dstH - wy : wy;
579 float triNx = triNdx ? 1.0f - nx : nx;
580 float triNy = triNdx ? 1.0f - ny : ny;
581
582 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
583 float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
584 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy,
585 (float)dst.getWidth(), (float)dst.getHeight()) +
586 lodBias;
587
588 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
589 }
590 }
591 }
592
sampleTexture(const tcu::PixelBufferAccess & dst,const tcu::Texture2DView & src,const float * texCoord,const ReferenceParams & params)593 void sampleTexture(const tcu::PixelBufferAccess &dst, const tcu::Texture2DView &src, const float *texCoord,
594 const ReferenceParams ¶ms)
595 {
596 tcu::ImageViewMinLodParams minLodParams = {
597 params.baseLevel, // int baseLevel;
598 {
599 params.imageViewMinLod, // float minLod;
600 params.imageViewMinLodMode, // ImageViewMinLodMode
601 },
602 params.samplerType == SAMPLERTYPE_FETCH_FLOAT // bool intTexCoord;
603 };
604
605 const tcu::Texture2DView view =
606 getSubView(src, params.baseLevel, params.maxLevel, params.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
607 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]);
608 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]);
609
610 if (params.flags & ReferenceParams::PROJECTED)
611 sampleTextureProjected(dst, view, sq, tq, params);
612 else
613 sampleTextureNonProjected(dst, view, sq, tq, params);
614 }
615
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture2DView & src,const float * texCoord,const ReferenceParams & params)616 void sampleTexture(const tcu::SurfaceAccess &dst, const tcu::Texture2DView &src, const float *texCoord,
617 const ReferenceParams ¶ms)
618 {
619 tcu::ImageViewMinLodParams minLodParams = {
620 params.baseLevel, // int baseLevel;
621 {
622 params.imageViewMinLod, // float minLod;
623 params.imageViewMinLodMode, // ImageViewMinLodMode
624 },
625 params.samplerType == SAMPLERTYPE_FETCH_FLOAT // bool intTexCoord;
626 };
627
628 const tcu::Texture2DView view =
629 getSubView(src, params.baseLevel, params.maxLevel, params.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
630 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]);
631 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]);
632
633 if (params.flags & ReferenceParams::PROJECTED)
634 sampleTextureProjected(dst, view, sq, tq, params);
635 else
636 sampleTextureNonProjected(dst, view, sq, tq, params);
637 }
638
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture1DView & src,const float * texCoord,const ReferenceParams & params)639 void sampleTexture(const tcu::SurfaceAccess &dst, const tcu::Texture1DView &src, const float *texCoord,
640 const ReferenceParams ¶ms)
641 {
642 const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel, DE_NULL);
643 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
644
645 if (params.flags & ReferenceParams::PROJECTED)
646 sampleTextureProjected(dst, view, sq, params);
647 else
648 sampleTextureNonProjected(dst, view, sq, params);
649 }
650
computeCubeLodFromDerivates(LodMode lodMode,const tcu::Vec3 & coord,const tcu::Vec3 & coordDx,const tcu::Vec3 & coordDy,const int faceSize)651 static float computeCubeLodFromDerivates(LodMode lodMode, const tcu::Vec3 &coord, const tcu::Vec3 &coordDx,
652 const tcu::Vec3 &coordDy, const int faceSize)
653 {
654 const tcu::CubeFace face = tcu::selectCubeFace(coord);
655 int maNdx = 0;
656 int sNdx = 0;
657 int tNdx = 0;
658
659 // \note Derivate signs don't matter when computing lod
660 switch (face)
661 {
662 case tcu::CUBEFACE_NEGATIVE_X:
663 case tcu::CUBEFACE_POSITIVE_X:
664 maNdx = 0;
665 sNdx = 2;
666 tNdx = 1;
667 break;
668 case tcu::CUBEFACE_NEGATIVE_Y:
669 case tcu::CUBEFACE_POSITIVE_Y:
670 maNdx = 1;
671 sNdx = 0;
672 tNdx = 2;
673 break;
674 case tcu::CUBEFACE_NEGATIVE_Z:
675 case tcu::CUBEFACE_POSITIVE_Z:
676 maNdx = 2;
677 sNdx = 0;
678 tNdx = 1;
679 break;
680 default:
681 DE_ASSERT(false);
682 }
683
684 {
685 const float sc = coord[sNdx];
686 const float tc = coord[tNdx];
687 const float ma = de::abs(coord[maNdx]);
688 const float scdx = coordDx[sNdx];
689 const float tcdx = coordDx[tNdx];
690 const float madx = de::abs(coordDx[maNdx]);
691 const float scdy = coordDy[sNdx];
692 const float tcdy = coordDy[tNdx];
693 const float mady = de::abs(coordDy[maNdx]);
694 const float dudx = float(faceSize) * 0.5f * (scdx * ma - sc * madx) / (ma * ma);
695 const float dvdx = float(faceSize) * 0.5f * (tcdx * ma - tc * madx) / (ma * ma);
696 const float dudy = float(faceSize) * 0.5f * (scdy * ma - sc * mady) / (ma * ma);
697 const float dvdy = float(faceSize) * 0.5f * (tcdy * ma - tc * mady) / (ma * ma);
698
699 return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
700 }
701 }
702
sampleTextureCube(const tcu::SurfaceAccess & dst,const tcu::TextureCubeView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const ReferenceParams & params)703 static void sampleTextureCube(const tcu::SurfaceAccess &dst, const tcu::TextureCubeView &rawSrc, const tcu::Vec4 &sq,
704 const tcu::Vec4 &tq, const tcu::Vec4 &rq, const ReferenceParams ¶ms)
705 {
706 // Separate combined DS formats
707 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
708 const tcu::TextureCubeView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
709
710 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
711 const float dstW = float(dstSize.x());
712 const float dstH = float(dstSize.y());
713 const int srcSize = src.getSize();
714
715 // Coordinates per triangle.
716 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
717 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
718 const tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
719 const tcu::Vec3 triW[2] = {params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1)};
720
721 const float lodBias((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
722
723 for (int py = 0; py < dst.getHeight(); py++)
724 {
725 for (int px = 0; px < dst.getWidth(); px++)
726 {
727 const float wx = (float)px + 0.5f;
728 const float wy = (float)py + 0.5f;
729 const float nx = wx / dstW;
730 const float ny = wy / dstH;
731
732 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
733 const float triNx = triNdx ? 1.0f - nx : nx;
734 const float triNy = triNdx ? 1.0f - ny : ny;
735
736 const tcu::Vec3 coord(triangleInterpolate(triS[triNdx], triNx, triNy),
737 triangleInterpolate(triT[triNdx], triNx, triNy),
738 triangleInterpolate(triR[triNdx], triNx, triNy));
739 const tcu::Vec3 coordDx(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
740 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
741 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
742 const tcu::Vec3 coordDy(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
743 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
744 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
745
746 const float lod =
747 de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias,
748 params.minLod, params.maxLod);
749
750 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale +
751 params.colorBias,
752 px, py);
753 }
754 }
755 }
756
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::TextureCubeView & src,const float * texCoord,const ReferenceParams & params)757 void sampleTexture(const tcu::SurfaceAccess &dst, const tcu::TextureCubeView &src, const float *texCoord,
758 const ReferenceParams ¶ms)
759 {
760 tcu::ImageViewMinLodParams minLodParams = {
761 params.baseLevel, // int baseLevel;
762 {
763 params.imageViewMinLod, // float minLod;
764 params.imageViewMinLodMode, // ImageViewMinLodMode
765 },
766 params.samplerType == SAMPLERTYPE_FETCH_FLOAT // bool intTexCoord;
767 };
768
769 const tcu::TextureCubeView view =
770 getSubView(src, params.baseLevel, params.maxLevel, params.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
771 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]);
772 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]);
773 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]);
774
775 return sampleTextureCube(dst, view, sq, tq, rq, params);
776 }
777
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture2DArrayView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const ReferenceParams & params)778 static void sampleTextureNonProjected(const tcu::SurfaceAccess &dst, const tcu::Texture2DArrayView &rawSrc,
779 const tcu::Vec4 &sq, const tcu::Vec4 &tq, const tcu::Vec4 &rq,
780 const ReferenceParams ¶ms)
781 {
782 // Separate combined DS formats
783 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
784 const tcu::Texture2DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
785
786 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
787
788 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
789 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
790
791 // Coordinates and lod per triangle.
792 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
793 tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
794 tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
795 float triLod[2] = {
796 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias,
797 params.minLod, params.maxLod),
798 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias,
799 params.minLod, params.maxLod)};
800
801 for (int y = 0; y < dst.getHeight(); y++)
802 {
803 for (int x = 0; x < dst.getWidth(); x++)
804 {
805 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
806 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
807
808 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
809 float triX = triNdx ? 1.0f - xf : xf;
810 float triY = triNdx ? 1.0f - yf : yf;
811
812 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
813 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
814 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
815 float lod = triLod[triNdx];
816
817 dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
818 }
819 }
820 }
821
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture2DArrayView & src,const float * texCoord,const ReferenceParams & params)822 void sampleTexture(const tcu::SurfaceAccess &dst, const tcu::Texture2DArrayView &src, const float *texCoord,
823 const ReferenceParams ¶ms)
824 {
825 tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]);
826 tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]);
827 tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]);
828
829 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
830 sampleTextureNonProjected(dst, src, sq, tq, rq, params);
831 }
832
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture1DArrayView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const ReferenceParams & params)833 static void sampleTextureNonProjected(const tcu::SurfaceAccess &dst, const tcu::Texture1DArrayView &rawSrc,
834 const tcu::Vec4 &sq, const tcu::Vec4 &tq, const ReferenceParams ¶ms)
835 {
836 // Separate combined DS formats
837 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
838 const tcu::Texture1DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
839
840 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
841
842 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
843 int32_t srcSize = src.getWidth();
844
845 // Coordinates and lod per triangle.
846 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
847 tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
848 float triLod[2] = {computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
849 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
850
851 for (int y = 0; y < dst.getHeight(); y++)
852 {
853 for (int x = 0; x < dst.getWidth(); x++)
854 {
855 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
856 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
857
858 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
859 float triX = triNdx ? 1.0f - xf : xf;
860 float triY = triNdx ? 1.0f - yf : yf;
861
862 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
863 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
864 float lod = triLod[triNdx];
865
866 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
867 }
868 }
869 }
870
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture1DArrayView & src,const float * texCoord,const ReferenceParams & params)871 void sampleTexture(const tcu::SurfaceAccess &dst, const tcu::Texture1DArrayView &src, const float *texCoord,
872 const ReferenceParams ¶ms)
873 {
874 tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]);
875 tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]);
876
877 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
878 sampleTextureNonProjected(dst, src, sq, tq, params);
879 }
880
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture3DView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const ReferenceParams & params)881 static void sampleTextureNonProjected(const tcu::SurfaceAccess &dst, const tcu::Texture3DView &rawSrc,
882 const tcu::Vec4 &sq, const tcu::Vec4 &tq, const tcu::Vec4 &rq,
883 const ReferenceParams ¶ms)
884 {
885 // Separate combined DS formats
886 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
887 const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
888
889 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
890
891 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
892 tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
893
894 // Coordinates and lod per triangle.
895 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
896 tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
897 tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
898 float triLod[2] = {
899 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias,
900 params.minLod, params.maxLod),
901 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias,
902 params.minLod, params.maxLod)};
903
904 for (int y = 0; y < dst.getHeight(); y++)
905 {
906 for (int x = 0; x < dst.getWidth(); x++)
907 {
908 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
909 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
910
911 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
912 float triX = triNdx ? 1.0f - xf : xf;
913 float triY = triNdx ? 1.0f - yf : yf;
914
915 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
916 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
917 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
918 float lod = triLod[triNdx];
919
920 if (params.imageViewMinLod != 0.0f && params.samplerType == SAMPLERTYPE_FETCH_FLOAT)
921 lod = (float)params.lodTexelFetch;
922
923 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
924 }
925 }
926 }
927
sampleTextureProjected(const tcu::SurfaceAccess & dst,const tcu::Texture3DView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const ReferenceParams & params)928 static void sampleTextureProjected(const tcu::SurfaceAccess &dst, const tcu::Texture3DView &rawSrc, const tcu::Vec4 &sq,
929 const tcu::Vec4 &tq, const tcu::Vec4 &rq, const ReferenceParams ¶ms)
930 {
931 // Separate combined DS formats
932 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
933 const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
934
935 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
936 float dstW = (float)dst.getWidth();
937 float dstH = (float)dst.getHeight();
938
939 tcu::Vec4 uq = sq * (float)src.getWidth();
940 tcu::Vec4 vq = tq * (float)src.getHeight();
941 tcu::Vec4 wq = rq * (float)src.getDepth();
942
943 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
944 tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
945 tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
946 tcu::Vec3 triU[2] = {uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1)};
947 tcu::Vec3 triV[2] = {vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1)};
948 tcu::Vec3 triW[2] = {wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1)};
949 tcu::Vec3 triP[2] = {params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1)};
950
951 for (int py = 0; py < dst.getHeight(); py++)
952 {
953 for (int px = 0; px < dst.getWidth(); px++)
954 {
955 float wx = (float)px + 0.5f;
956 float wy = (float)py + 0.5f;
957 float nx = wx / dstW;
958 float ny = wy / dstH;
959
960 int triNdx = nx + ny >= 1.0f ? 1 : 0;
961 float triWx = triNdx ? dstW - wx : wx;
962 float triWy = triNdx ? dstH - wy : wy;
963 float triNx = triNdx ? 1.0f - nx : nx;
964 float triNy = triNdx ? 1.0f - ny : ny;
965
966 float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
967 float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
968 float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
969 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx],
970 triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight()) +
971 lodBias;
972
973 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
974 }
975 }
976 }
977
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture3DView & src,const float * texCoord,const ReferenceParams & params)978 void sampleTexture(const tcu::SurfaceAccess &dst, const tcu::Texture3DView &src, const float *texCoord,
979 const ReferenceParams ¶ms)
980 {
981 tcu::ImageViewMinLodParams minLodParams = {
982 params.baseLevel, // int baseLevel;
983 {
984 params.imageViewMinLod, // float minLod;
985 params.imageViewMinLodMode, // ImageViewMinLodMode
986 },
987 params.samplerType == SAMPLERTYPE_FETCH_FLOAT // bool intTexCoord;
988 };
989
990 const tcu::Texture3DView view =
991 getSubView(src, params.baseLevel, params.maxLevel, params.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
992 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]);
993 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]);
994 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]);
995
996 if (params.flags & ReferenceParams::PROJECTED)
997 sampleTextureProjected(dst, view, sq, tq, rq, params);
998 else
999 sampleTextureNonProjected(dst, view, sq, tq, rq, params);
1000 }
1001
sampleTextureCubeArray(const tcu::SurfaceAccess & dst,const tcu::TextureCubeArrayView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const tcu::Vec4 & qq,const ReferenceParams & params)1002 static void sampleTextureCubeArray(const tcu::SurfaceAccess &dst, const tcu::TextureCubeArrayView &rawSrc,
1003 const tcu::Vec4 &sq, const tcu::Vec4 &tq, const tcu::Vec4 &rq, const tcu::Vec4 &qq,
1004 const ReferenceParams ¶ms)
1005 {
1006 // Separate combined DS formats
1007 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1008 const tcu::TextureCubeArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
1009
1010 const float dstW = (float)dst.getWidth();
1011 const float dstH = (float)dst.getHeight();
1012
1013 // Coordinates per triangle.
1014 tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
1015 tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
1016 tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
1017 tcu::Vec3 triQ[2] = {qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1)};
1018 const tcu::Vec3 triW[2] = {params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1)};
1019
1020 const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
1021
1022 for (int py = 0; py < dst.getHeight(); py++)
1023 {
1024 for (int px = 0; px < dst.getWidth(); px++)
1025 {
1026 const float wx = (float)px + 0.5f;
1027 const float wy = (float)py + 0.5f;
1028 const float nx = wx / dstW;
1029 const float ny = wy / dstH;
1030
1031 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1032 const float triNx = triNdx ? 1.0f - nx : nx;
1033 const float triNy = triNdx ? 1.0f - ny : ny;
1034
1035 const tcu::Vec3 coord(triangleInterpolate(triS[triNdx], triNx, triNy),
1036 triangleInterpolate(triT[triNdx], triNx, triNy),
1037 triangleInterpolate(triR[triNdx], triNx, triNy));
1038
1039 const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy);
1040
1041 const tcu::Vec3 coordDx(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1042 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1043 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
1044 const tcu::Vec3 coordDy(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1045 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1046 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
1047
1048 const float lod =
1049 de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias,
1050 params.minLod, params.maxLod);
1051
1052 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale +
1053 params.colorBias,
1054 px, py);
1055 }
1056 }
1057 }
1058
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::TextureCubeArrayView & src,const float * texCoord,const ReferenceParams & params)1059 void sampleTexture(const tcu::SurfaceAccess &dst, const tcu::TextureCubeArrayView &src, const float *texCoord,
1060 const ReferenceParams ¶ms)
1061 {
1062 tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[4 + 0], texCoord[8 + 0], texCoord[12 + 0]);
1063 tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[4 + 1], texCoord[8 + 1], texCoord[12 + 1]);
1064 tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[4 + 2], texCoord[8 + 2], texCoord[12 + 2]);
1065 tcu::Vec4 qq = tcu::Vec4(texCoord[0 + 3], texCoord[4 + 3], texCoord[8 + 3], texCoord[12 + 3]);
1066
1067 sampleTextureCubeArray(dst, src, sq, tq, rq, qq, params);
1068 }
1069
fetchTexture(const tcu::SurfaceAccess & dst,const tcu::ConstPixelBufferAccess & src,const float * texCoord,const tcu::Vec4 & colorScale,const tcu::Vec4 & colorBias)1070 void fetchTexture(const tcu::SurfaceAccess &dst, const tcu::ConstPixelBufferAccess &src, const float *texCoord,
1071 const tcu::Vec4 &colorScale, const tcu::Vec4 &colorBias)
1072 {
1073 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1074 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
1075
1076 for (int y = 0; y < dst.getHeight(); y++)
1077 {
1078 for (int x = 0; x < dst.getWidth(); x++)
1079 {
1080 const float yf = ((float)y + 0.5f) / (float)dst.getHeight();
1081 const float xf = ((float)x + 0.5f) / (float)dst.getWidth();
1082
1083 const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
1084 const float triX = triNdx ? 1.0f - xf : xf;
1085 const float triY = triNdx ? 1.0f - yf : yf;
1086
1087 const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
1088
1089 dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
1090 }
1091 }
1092 }
1093
compareImages(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & rendered,tcu::RGBA threshold)1094 bool compareImages(tcu::TestLog &log, const tcu::Surface &reference, const tcu::Surface &rendered, tcu::RGBA threshold)
1095 {
1096 return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold,
1097 tcu::COMPARE_LOG_RESULT);
1098 }
1099
compareImages(tcu::TestLog & log,const char * name,const char * desc,const tcu::Surface & reference,const tcu::Surface & rendered,tcu::RGBA threshold)1100 bool compareImages(tcu::TestLog &log, const char *name, const char *desc, const tcu::Surface &reference,
1101 const tcu::Surface &rendered, tcu::RGBA threshold)
1102 {
1103 return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
1104 }
1105
measureAccuracy(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & rendered,int bestScoreDiff,int worstScoreDiff)1106 int measureAccuracy(tcu::TestLog &log, const tcu::Surface &reference, const tcu::Surface &rendered, int bestScoreDiff,
1107 int worstScoreDiff)
1108 {
1109 return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff,
1110 worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
1111 }
1112
rangeDiff(int x,int a,int b)1113 inline int rangeDiff(int x, int a, int b)
1114 {
1115 if (x < a)
1116 return a - x;
1117 else if (x > b)
1118 return x - b;
1119 else
1120 return 0;
1121 }
1122
rangeDiff(tcu::RGBA p,tcu::RGBA a,tcu::RGBA b)1123 inline tcu::RGBA rangeDiff(tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
1124 {
1125 int rMin = de::min(a.getRed(), b.getRed());
1126 int rMax = de::max(a.getRed(), b.getRed());
1127 int gMin = de::min(a.getGreen(), b.getGreen());
1128 int gMax = de::max(a.getGreen(), b.getGreen());
1129 int bMin = de::min(a.getBlue(), b.getBlue());
1130 int bMax = de::max(a.getBlue(), b.getBlue());
1131 int aMin = de::min(a.getAlpha(), b.getAlpha());
1132 int aMax = de::max(a.getAlpha(), b.getAlpha());
1133
1134 return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax), rangeDiff(p.getGreen(), gMin, gMax),
1135 rangeDiff(p.getBlue(), bMin, bMax), rangeDiff(p.getAlpha(), aMin, aMax));
1136 }
1137
rangeCompare(tcu::RGBA p,tcu::RGBA a,tcu::RGBA b,tcu::RGBA threshold)1138 inline bool rangeCompare(tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
1139 {
1140 tcu::RGBA diff = rangeDiff(p, a, b);
1141 return diff.getRed() <= threshold.getRed() && diff.getGreen() <= threshold.getGreen() &&
1142 diff.getBlue() <= threshold.getBlue() && diff.getAlpha() <= threshold.getAlpha();
1143 }
1144
computeQuadTexCoord1D(std::vector<float> & dst,float left,float right)1145 void computeQuadTexCoord1D(std::vector<float> &dst, float left, float right)
1146 {
1147 dst.resize(4);
1148
1149 dst[0] = left;
1150 dst[1] = left;
1151 dst[2] = right;
1152 dst[3] = right;
1153 }
1154
computeQuadTexCoord1DArray(std::vector<float> & dst,int layerNdx,float left,float right)1155 void computeQuadTexCoord1DArray(std::vector<float> &dst, int layerNdx, float left, float right)
1156 {
1157 dst.resize(4 * 2);
1158
1159 dst[0] = left;
1160 dst[1] = (float)layerNdx;
1161 dst[2] = left;
1162 dst[3] = (float)layerNdx;
1163 dst[4] = right;
1164 dst[5] = (float)layerNdx;
1165 dst[6] = right;
1166 dst[7] = (float)layerNdx;
1167 }
1168
computeQuadTexCoord2D(std::vector<float> & dst,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight)1169 void computeQuadTexCoord2D(std::vector<float> &dst, const tcu::Vec2 &bottomLeft, const tcu::Vec2 &topRight)
1170 {
1171 dst.resize(4 * 2);
1172
1173 dst[0] = bottomLeft.x();
1174 dst[1] = bottomLeft.y();
1175 dst[2] = bottomLeft.x();
1176 dst[3] = topRight.y();
1177 dst[4] = topRight.x();
1178 dst[5] = bottomLeft.y();
1179 dst[6] = topRight.x();
1180 dst[7] = topRight.y();
1181 }
1182
computeQuadTexCoord2DArray(std::vector<float> & dst,int layerNdx,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight)1183 void computeQuadTexCoord2DArray(std::vector<float> &dst, int layerNdx, const tcu::Vec2 &bottomLeft,
1184 const tcu::Vec2 &topRight)
1185 {
1186 dst.resize(4 * 3);
1187
1188 dst[0] = bottomLeft.x();
1189 dst[1] = bottomLeft.y();
1190 dst[2] = (float)layerNdx;
1191 dst[3] = bottomLeft.x();
1192 dst[4] = topRight.y();
1193 dst[5] = (float)layerNdx;
1194 dst[6] = topRight.x();
1195 dst[7] = bottomLeft.y();
1196 dst[8] = (float)layerNdx;
1197 dst[9] = topRight.x();
1198 dst[10] = topRight.y();
1199 dst[11] = (float)layerNdx;
1200 }
1201
computeQuadTexCoord3D(std::vector<float> & dst,const tcu::Vec3 & p0,const tcu::Vec3 & p1,const tcu::IVec3 & dirSwz)1202 void computeQuadTexCoord3D(std::vector<float> &dst, const tcu::Vec3 &p0, const tcu::Vec3 &p1, const tcu::IVec3 &dirSwz)
1203 {
1204 tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1205 tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1206 tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1207 tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1208
1209 tcu::Vec3 v0 = p0 + (p1 - p0) * f0;
1210 tcu::Vec3 v1 = p0 + (p1 - p0) * f1;
1211 tcu::Vec3 v2 = p0 + (p1 - p0) * f2;
1212 tcu::Vec3 v3 = p0 + (p1 - p0) * f3;
1213
1214 dst.resize(4 * 3);
1215
1216 dst[0] = v0.x();
1217 dst[1] = v0.y();
1218 dst[2] = v0.z();
1219 dst[3] = v1.x();
1220 dst[4] = v1.y();
1221 dst[5] = v1.z();
1222 dst[6] = v2.x();
1223 dst[7] = v2.y();
1224 dst[8] = v2.z();
1225 dst[9] = v3.x();
1226 dst[10] = v3.y();
1227 dst[11] = v3.z();
1228 }
1229
computeQuadTexCoordCube(std::vector<float> & dst,tcu::CubeFace face)1230 void computeQuadTexCoordCube(std::vector<float> &dst, tcu::CubeFace face)
1231 {
1232 static const float texCoordNegX[] = {-1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
1233 -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f};
1234 static const float texCoordPosX[] = {+1.0f, 1.0f, 1.0f, +1.0f, -1.0f, 1.0f,
1235 +1.0f, 1.0f, -1.0f, +1.0f, -1.0f, -1.0f};
1236 static const float texCoordNegY[] = {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f,
1237 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f};
1238 static const float texCoordPosY[] = {-1.0f, +1.0f, -1.0f, -1.0f, +1.0f, 1.0f,
1239 1.0f, +1.0f, -1.0f, 1.0f, +1.0f, 1.0f};
1240 static const float texCoordNegZ[] = {1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1241 -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f};
1242 static const float texCoordPosZ[] = {-1.0f, 1.0f, +1.0f, -1.0f, -1.0f, +1.0f,
1243 1.0f, 1.0f, +1.0f, 1.0f, -1.0f, +1.0f};
1244
1245 const float *texCoord = DE_NULL;
1246 int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX);
1247
1248 switch (face)
1249 {
1250 case tcu::CUBEFACE_NEGATIVE_X:
1251 texCoord = texCoordNegX;
1252 break;
1253 case tcu::CUBEFACE_POSITIVE_X:
1254 texCoord = texCoordPosX;
1255 break;
1256 case tcu::CUBEFACE_NEGATIVE_Y:
1257 texCoord = texCoordNegY;
1258 break;
1259 case tcu::CUBEFACE_POSITIVE_Y:
1260 texCoord = texCoordPosY;
1261 break;
1262 case tcu::CUBEFACE_NEGATIVE_Z:
1263 texCoord = texCoordNegZ;
1264 break;
1265 case tcu::CUBEFACE_POSITIVE_Z:
1266 texCoord = texCoordPosZ;
1267 break;
1268 default:
1269 DE_ASSERT(false);
1270 return;
1271 }
1272
1273 dst.resize(texCoordSize);
1274 std::copy(texCoord, texCoord + texCoordSize, dst.begin());
1275 }
1276
computeQuadTexCoordCube(std::vector<float> & dst,tcu::CubeFace face,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight)1277 void computeQuadTexCoordCube(std::vector<float> &dst, tcu::CubeFace face, const tcu::Vec2 &bottomLeft,
1278 const tcu::Vec2 &topRight)
1279 {
1280 int sRow = 0;
1281 int tRow = 0;
1282 int mRow = 0;
1283 float sSign = 1.0f;
1284 float tSign = 1.0f;
1285 float mSign = 1.0f;
1286
1287 switch (face)
1288 {
1289 case tcu::CUBEFACE_NEGATIVE_X:
1290 mRow = 0;
1291 sRow = 2;
1292 tRow = 1;
1293 mSign = -1.0f;
1294 tSign = -1.0f;
1295 break;
1296 case tcu::CUBEFACE_POSITIVE_X:
1297 mRow = 0;
1298 sRow = 2;
1299 tRow = 1;
1300 sSign = -1.0f;
1301 tSign = -1.0f;
1302 break;
1303 case tcu::CUBEFACE_NEGATIVE_Y:
1304 mRow = 1;
1305 sRow = 0;
1306 tRow = 2;
1307 mSign = -1.0f;
1308 tSign = -1.0f;
1309 break;
1310 case tcu::CUBEFACE_POSITIVE_Y:
1311 mRow = 1;
1312 sRow = 0;
1313 tRow = 2;
1314 break;
1315 case tcu::CUBEFACE_NEGATIVE_Z:
1316 mRow = 2;
1317 sRow = 0;
1318 tRow = 1;
1319 mSign = -1.0f;
1320 sSign = -1.0f;
1321 tSign = -1.0f;
1322 break;
1323 case tcu::CUBEFACE_POSITIVE_Z:
1324 mRow = 2;
1325 sRow = 0;
1326 tRow = 1;
1327 tSign = -1.0f;
1328 break;
1329 default:
1330 DE_ASSERT(false);
1331 return;
1332 }
1333
1334 dst.resize(3 * 4);
1335
1336 dst[0 + mRow] = mSign;
1337 dst[3 + mRow] = mSign;
1338 dst[6 + mRow] = mSign;
1339 dst[9 + mRow] = mSign;
1340
1341 dst[0 + sRow] = sSign * bottomLeft.x();
1342 dst[3 + sRow] = sSign * bottomLeft.x();
1343 dst[6 + sRow] = sSign * topRight.x();
1344 dst[9 + sRow] = sSign * topRight.x();
1345
1346 dst[0 + tRow] = tSign * bottomLeft.y();
1347 dst[3 + tRow] = tSign * topRight.y();
1348 dst[6 + tRow] = tSign * bottomLeft.y();
1349 dst[9 + tRow] = tSign * topRight.y();
1350 }
1351
computeQuadTexCoordCubeArray(std::vector<float> & dst,tcu::CubeFace face,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight,const tcu::Vec2 & layerRange)1352 void computeQuadTexCoordCubeArray(std::vector<float> &dst, tcu::CubeFace face, const tcu::Vec2 &bottomLeft,
1353 const tcu::Vec2 &topRight, const tcu::Vec2 &layerRange)
1354 {
1355 int sRow = 0;
1356 int tRow = 0;
1357 int mRow = 0;
1358 const int qRow = 3;
1359 float sSign = 1.0f;
1360 float tSign = 1.0f;
1361 float mSign = 1.0f;
1362 const float l0 = layerRange.x();
1363 const float l1 = layerRange.y();
1364
1365 switch (face)
1366 {
1367 case tcu::CUBEFACE_NEGATIVE_X:
1368 mRow = 0;
1369 sRow = 2;
1370 tRow = 1;
1371 mSign = -1.0f;
1372 tSign = -1.0f;
1373 break;
1374 case tcu::CUBEFACE_POSITIVE_X:
1375 mRow = 0;
1376 sRow = 2;
1377 tRow = 1;
1378 sSign = -1.0f;
1379 tSign = -1.0f;
1380 break;
1381 case tcu::CUBEFACE_NEGATIVE_Y:
1382 mRow = 1;
1383 sRow = 0;
1384 tRow = 2;
1385 mSign = -1.0f;
1386 tSign = -1.0f;
1387 break;
1388 case tcu::CUBEFACE_POSITIVE_Y:
1389 mRow = 1;
1390 sRow = 0;
1391 tRow = 2;
1392 break;
1393 case tcu::CUBEFACE_NEGATIVE_Z:
1394 mRow = 2;
1395 sRow = 0;
1396 tRow = 1;
1397 mSign = -1.0f;
1398 sSign = -1.0f;
1399 tSign = -1.0f;
1400 break;
1401 case tcu::CUBEFACE_POSITIVE_Z:
1402 mRow = 2;
1403 sRow = 0;
1404 tRow = 1;
1405 tSign = -1.0f;
1406 break;
1407 default:
1408 DE_ASSERT(false);
1409 return;
1410 }
1411
1412 dst.resize(4 * 4);
1413
1414 dst[0 + mRow] = mSign;
1415 dst[4 + mRow] = mSign;
1416 dst[8 + mRow] = mSign;
1417 dst[12 + mRow] = mSign;
1418
1419 dst[0 + sRow] = sSign * bottomLeft.x();
1420 dst[4 + sRow] = sSign * bottomLeft.x();
1421 dst[8 + sRow] = sSign * topRight.x();
1422 dst[12 + sRow] = sSign * topRight.x();
1423
1424 dst[0 + tRow] = tSign * bottomLeft.y();
1425 dst[4 + tRow] = tSign * topRight.y();
1426 dst[8 + tRow] = tSign * bottomLeft.y();
1427 dst[12 + tRow] = tSign * topRight.y();
1428
1429 if (l0 != l1)
1430 {
1431 dst[0 + qRow] = l0;
1432 dst[4 + qRow] = l0 * 0.5f + l1 * 0.5f;
1433 dst[8 + qRow] = l0 * 0.5f + l1 * 0.5f;
1434 dst[12 + qRow] = l1;
1435 }
1436 else
1437 {
1438 dst[0 + qRow] = l0;
1439 dst[4 + qRow] = l0;
1440 dst[8 + qRow] = l0;
1441 dst[12 + qRow] = l0;
1442 }
1443 }
1444
1445 // Texture result verification
1446
1447 //! Verifies texture lookup results and returns number of failed pixels.
computeTextureLookupDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture1DView & baseView,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,qpWatchDog * watchDog)1448 int computeTextureLookupDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
1449 const tcu::PixelBufferAccess &errorMask, const tcu::Texture1DView &baseView,
1450 const float *texCoord, const ReferenceParams &sampleParams,
1451 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
1452 qpWatchDog *watchDog)
1453 {
1454 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1455 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1456
1457 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1458 const tcu::Texture1DView src =
1459 getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel, DE_NULL),
1460 srcLevelStorage, sampleParams.sampler);
1461
1462 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1463
1464 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1465 const float dstW = float(dstSize.x());
1466 const float dstH = float(dstSize.y());
1467 const int srcSize = src.getWidth();
1468
1469 // Coordinates and lod per triangle.
1470 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
1471 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
1472
1473 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1474
1475 int numFailed = 0;
1476
1477 const tcu::Vec2 lodOffsets[] = {
1478 tcu::Vec2(-1, 0),
1479 tcu::Vec2(+1, 0),
1480 tcu::Vec2(0, -1),
1481 tcu::Vec2(0, +1),
1482 };
1483
1484 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1485
1486 for (int py = 0; py < result.getHeight(); py++)
1487 {
1488 // Ugly hack, validation can take way too long at the moment.
1489 if (watchDog)
1490 qpWatchDog_touch(watchDog);
1491
1492 for (int px = 0; px < result.getWidth(); px++)
1493 {
1494 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1495 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1496
1497 // Try comparison to ideal reference first, and if that fails use slower verificator.
1498 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1499 {
1500 const float wx = (float)px + 0.5f;
1501 const float wy = (float)py + 0.5f;
1502 const float nx = wx / dstW;
1503 const float ny = wy / dstH;
1504
1505 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1506 const float triWx = triNdx ? dstW - wx : wx;
1507 const float triWy = triNdx ? dstH - wy : wy;
1508 const float triNx = triNdx ? 1.0f - nx : nx;
1509 const float triNy = triNdx ? 1.0f - ny : ny;
1510
1511 const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1512 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1513 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1514
1515 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1516
1517 // Compute lod bounds across lodOffsets range.
1518 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1519 {
1520 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1521 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1522 const float nxo = wxo / dstW;
1523 const float nyo = wyo / dstH;
1524
1525 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1526 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1527 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1528
1529 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1530 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1531 }
1532
1533 const tcu::Vec2 clampedLod = tcu::clampLodBounds(
1534 lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1535 const bool isOk =
1536 tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1537
1538 if (!isOk)
1539 {
1540 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1541 numFailed += 1;
1542 }
1543 }
1544 }
1545 }
1546
1547 return numFailed;
1548 }
1549
computeTextureLookupDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture2DView & baseView,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,qpWatchDog * watchDog)1550 int computeTextureLookupDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
1551 const tcu::PixelBufferAccess &errorMask, const tcu::Texture2DView &baseView,
1552 const float *texCoord, const ReferenceParams &sampleParams,
1553 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
1554 qpWatchDog *watchDog)
1555 {
1556 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1557 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1558
1559 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1560 tcu::ImageViewMinLodParams minLodParams = {
1561 sampleParams.baseLevel, // int baseLevel;
1562 {
1563 sampleParams.imageViewMinLod, // float minLod;
1564 sampleParams.imageViewMinLodMode, // ImageViewMinLodMode
1565 },
1566 sampleParams.samplerType == SAMPLERTYPE_FETCH_FLOAT // bool intTexCoord;
1567 };
1568
1569 const tcu::Texture2DView view = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel,
1570 sampleParams.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL);
1571
1572 const tcu::Texture2DView src = getEffectiveTextureView(view, srcLevelStorage, sampleParams.sampler);
1573
1574 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]);
1575 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]);
1576
1577 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1578 const float dstW = float(dstSize.x());
1579 const float dstH = float(dstSize.y());
1580 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
1581
1582 // Coordinates and lod per triangle.
1583 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
1584 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
1585 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
1586
1587 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1588
1589 // imageViewMinLodRel is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
1590 // The value is relative to baseLevel as the Texture*View 'src' was created as the baseLevel being level[0].
1591 const float imageViewMinLodRel = sampleParams.imageViewMinLod - (float)sampleParams.baseLevel;
1592 // We need to adapt ImageView's minLod value to the mipmap mdoe (i.e. nearest or linear) so we clamp with the right minLod value later.
1593 const float imageViewMinLodRelMode = tcu::isSamplerMipmapModeLinear(sampleParams.sampler.minFilter) ?
1594 deFloatFloor(imageViewMinLodRel) :
1595 (float)deClamp32((int)deFloatCeil(imageViewMinLodRel + 0.5f) - 1,
1596 sampleParams.baseLevel, sampleParams.maxLevel);
1597 const float minLod = (sampleParams.imageViewMinLod != 0.0f) ? de::max(imageViewMinLodRelMode, sampleParams.minLod) :
1598 sampleParams.minLod;
1599
1600 const float posEps = 1.0f / float(1 << MIN_SUBPIXEL_BITS);
1601
1602 int numFailed = 0;
1603
1604 const tcu::Vec2 lodOffsets[] = {
1605 tcu::Vec2(-1, 0),
1606 tcu::Vec2(+1, 0),
1607 tcu::Vec2(0, -1),
1608 tcu::Vec2(0, +1),
1609 };
1610
1611 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1612
1613 for (int py = 0; py < result.getHeight(); py++)
1614 {
1615 // Ugly hack, validation can take way too long at the moment.
1616 if (watchDog)
1617 qpWatchDog_touch(watchDog);
1618
1619 for (int px = 0; px < result.getWidth(); px++)
1620 {
1621 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1622 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1623
1624 // Try comparison to ideal reference first, and if that fails use slower verificator.
1625 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1626 {
1627 const float wx = (float)px + 0.5f;
1628 const float wy = (float)py + 0.5f;
1629 const float nx = wx / dstW;
1630 const float ny = wy / dstH;
1631
1632 const bool tri0 = (wx - posEps) / dstW + (wy - posEps) / dstH <= 1.0f;
1633 const bool tri1 = (wx + posEps) / dstW + (wy + posEps) / dstH >= 1.0f;
1634
1635 bool isOk = false;
1636
1637 DE_ASSERT(tri0 || tri1);
1638
1639 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1640 for (int triNdx = (tri0 ? 0 : 1); triNdx <= (tri1 ? 1 : 0); triNdx++)
1641 {
1642 const float triWx = triNdx ? dstW - wx : wx;
1643 const float triWy = triNdx ? dstH - wy : wy;
1644 const float triNx = triNdx ? 1.0f - nx : nx;
1645 const float triNy = triNdx ? 1.0f - ny : ny;
1646
1647 const tcu::Vec2 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1648 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1649 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1650 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) *
1651 srcSize.asFloat();
1652 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1653 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) *
1654 srcSize.asFloat();
1655
1656 tcu::Vec2 lodBounds =
1657 tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1658
1659 // Compute lod bounds across lodOffsets range.
1660 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1661 {
1662 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1663 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1664 const float nxo = wxo / dstW;
1665 const float nyo = wyo / dstH;
1666
1667 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1668 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) *
1669 srcSize.asFloat();
1670 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1671 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) *
1672 srcSize.asFloat();
1673 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(),
1674 coordDyo.x(), coordDyo.y(), lodPrec);
1675
1676 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1677 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1678 }
1679
1680 const tcu::Vec2 clampedLod =
1681 tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
1682 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1683 {
1684 isOk = true;
1685 break;
1686 }
1687 }
1688
1689 if (!isOk)
1690 {
1691 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1692 numFailed += 1;
1693 }
1694 }
1695 }
1696 }
1697
1698 return numFailed;
1699 }
1700
verifyTextureResult(tcu::TestContext & testCtx,const tcu::ConstPixelBufferAccess & result,const tcu::Texture1DView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,const tcu::PixelFormat & pixelFormat)1701 bool verifyTextureResult(tcu::TestContext &testCtx, const tcu::ConstPixelBufferAccess &result,
1702 const tcu::Texture1DView &src, const float *texCoord, const ReferenceParams &sampleParams,
1703 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
1704 const tcu::PixelFormat &pixelFormat)
1705 {
1706 tcu::TestLog &log = testCtx.getLog();
1707 tcu::Surface reference(result.getWidth(), result.getHeight());
1708 tcu::Surface errorMask(result.getWidth(), result.getHeight());
1709 int numFailedPixels;
1710
1711 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1712
1713 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1714 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord,
1715 sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1716
1717 if (numFailedPixels > 0)
1718 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels
1719 << " invalid pixels!" << tcu::TestLog::EndMessage;
1720
1721 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1722 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1723
1724 if (numFailedPixels > 0)
1725 {
1726 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1727 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1728 }
1729
1730 log << tcu::TestLog::EndImageSet;
1731
1732 return numFailedPixels == 0;
1733 }
1734
verifyTextureResult(tcu::TestContext & testCtx,const tcu::ConstPixelBufferAccess & result,const tcu::Texture2DView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,const tcu::PixelFormat & pixelFormat)1735 bool verifyTextureResult(tcu::TestContext &testCtx, const tcu::ConstPixelBufferAccess &result,
1736 const tcu::Texture2DView &src, const float *texCoord, const ReferenceParams &sampleParams,
1737 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
1738 const tcu::PixelFormat &pixelFormat)
1739 {
1740 tcu::TestLog &log = testCtx.getLog();
1741 tcu::Surface reference(result.getWidth(), result.getHeight());
1742 tcu::Surface errorMask(result.getWidth(), result.getHeight());
1743 int numFailedPixels;
1744
1745 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1746
1747 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1748 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord,
1749 sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1750
1751 if (numFailedPixels > 0)
1752 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels
1753 << " invalid pixels!" << tcu::TestLog::EndMessage;
1754
1755 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1756 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1757
1758 if (numFailedPixels > 0)
1759 {
1760 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1761 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1762 }
1763
1764 log << tcu::TestLog::EndImageSet;
1765
1766 return numFailedPixels == 0;
1767 }
1768
1769 //! Verifies texture lookup results and returns number of failed pixels.
computeTextureLookupDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::TextureCubeView & baseView,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,qpWatchDog * watchDog)1770 int computeTextureLookupDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
1771 const tcu::PixelBufferAccess &errorMask, const tcu::TextureCubeView &baseView,
1772 const float *texCoord, const ReferenceParams &sampleParams,
1773 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
1774 qpWatchDog *watchDog)
1775 {
1776 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1777 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1778
1779 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1780 tcu::ImageViewMinLodParams minLodParams = {
1781 sampleParams.baseLevel, // int baseLevel;
1782 {
1783 sampleParams.imageViewMinLod, // float minLod;
1784 sampleParams.imageViewMinLodMode, // ImageViewMinLodMode
1785 },
1786 sampleParams.samplerType == SAMPLERTYPE_FETCH_FLOAT // bool intTexCoord;
1787 };
1788
1789 const tcu::TextureCubeView src =
1790 getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel,
1791 sampleParams.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL),
1792 srcLevelStorage, sampleParams.sampler);
1793
1794 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]);
1795 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]);
1796 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]);
1797
1798 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1799 const float dstW = float(dstSize.x());
1800 const float dstH = float(dstSize.y());
1801 const int srcSize = src.getSize();
1802
1803 // Coordinates per triangle.
1804 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
1805 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
1806 const tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
1807 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
1808
1809 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1810
1811 const float posEps = 1.0f / float(1 << MIN_SUBPIXEL_BITS);
1812
1813 // imageViewMinLodRel is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
1814 // The value is relative to baseLevel as the Texture*View 'src' was created as the baseLevel being level[0].
1815 const float imageViewMinLodRel = sampleParams.imageViewMinLod - (float)sampleParams.baseLevel;
1816 // We need to adapt ImageView's minLod value to the mipmap mdoe (i.e. nearest or linear) so we clamp with the right minLod value later.
1817 const float imageViewMinLodRelMode = tcu::isSamplerMipmapModeLinear(sampleParams.sampler.minFilter) ?
1818 deFloatFloor(imageViewMinLodRel) :
1819 (float)deClamp32((int)deFloatCeil(imageViewMinLodRel + 0.5f) - 1,
1820 sampleParams.baseLevel, sampleParams.maxLevel);
1821 const float minLod = (sampleParams.imageViewMinLod != 0.0f) ? de::max(imageViewMinLodRelMode, sampleParams.minLod) :
1822 sampleParams.minLod;
1823
1824 int numFailed = 0;
1825
1826 const tcu::Vec2 lodOffsets[] = {
1827 tcu::Vec2(-1, 0),
1828 tcu::Vec2(+1, 0),
1829 tcu::Vec2(0, -1),
1830 tcu::Vec2(0, +1),
1831
1832 // \note Not strictly allowed by spec, but implementations do this in practice.
1833 tcu::Vec2(-1, -1),
1834 tcu::Vec2(-1, +1),
1835 tcu::Vec2(+1, -1),
1836 tcu::Vec2(+1, +1),
1837 };
1838
1839 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1840
1841 for (int py = 0; py < result.getHeight(); py++)
1842 {
1843 // Ugly hack, validation can take way too long at the moment.
1844 if (watchDog)
1845 qpWatchDog_touch(watchDog);
1846
1847 for (int px = 0; px < result.getWidth(); px++)
1848 {
1849 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1850 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1851
1852 // Try comparison to ideal reference first, and if that fails use slower verificator.
1853 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1854 {
1855 const float wx = (float)px + 0.5f;
1856 const float wy = (float)py + 0.5f;
1857 const float nx = wx / dstW;
1858 const float ny = wy / dstH;
1859
1860 const bool tri0 = (wx - posEps) / dstW + (wy - posEps) / dstH <= 1.0f;
1861 const bool tri1 = (wx + posEps) / dstW + (wy + posEps) / dstH >= 1.0f;
1862
1863 bool isOk = false;
1864
1865 DE_ASSERT(tri0 || tri1);
1866
1867 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1868 for (int triNdx = (tri0 ? 0 : 1); triNdx <= (tri1 ? 1 : 0); triNdx++)
1869 {
1870 const float triWx = triNdx ? dstW - wx : wx;
1871 const float triWy = triNdx ? dstH - wy : wy;
1872 const float triNx = triNdx ? 1.0f - nx : nx;
1873 const float triNy = triNdx ? 1.0f - ny : ny;
1874
1875 const tcu::Vec3 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1876 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1877 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1878 const tcu::Vec3 coordDx(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1879 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1880 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
1881 const tcu::Vec3 coordDy(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1882 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1883 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
1884
1885 tcu::Vec2 lodBounds =
1886 tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
1887
1888 // Compute lod bounds across lodOffsets range.
1889 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1890 {
1891 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1892 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1893 const float nxo = wxo / dstW;
1894 const float nyo = wyo / dstH;
1895
1896 const tcu::Vec3 coordO(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
1897 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
1898 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
1899 const tcu::Vec3 coordDxo(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1900 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1901 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
1902 const tcu::Vec3 coordDyo(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1903 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1904 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
1905 const tcu::Vec2 lodO =
1906 tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
1907
1908 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1909 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1910 }
1911
1912 const tcu::Vec2 clampedLod =
1913 tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
1914
1915 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1916 {
1917 isOk = true;
1918 break;
1919 }
1920 }
1921
1922 if (!isOk)
1923 {
1924 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1925 numFailed += 1;
1926 }
1927 }
1928 }
1929 }
1930
1931 return numFailed;
1932 }
1933
verifyTextureResult(tcu::TestContext & testCtx,const tcu::ConstPixelBufferAccess & result,const tcu::TextureCubeView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,const tcu::PixelFormat & pixelFormat)1934 bool verifyTextureResult(tcu::TestContext &testCtx, const tcu::ConstPixelBufferAccess &result,
1935 const tcu::TextureCubeView &src, const float *texCoord, const ReferenceParams &sampleParams,
1936 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
1937 const tcu::PixelFormat &pixelFormat)
1938 {
1939 tcu::TestLog &log = testCtx.getLog();
1940 tcu::Surface reference(result.getWidth(), result.getHeight());
1941 tcu::Surface errorMask(result.getWidth(), result.getHeight());
1942 int numFailedPixels;
1943
1944 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1945
1946 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1947 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord,
1948 sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1949
1950 if (numFailedPixels > 0)
1951 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels
1952 << " invalid pixels!" << tcu::TestLog::EndMessage;
1953
1954 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1955 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1956
1957 if (numFailedPixels > 0)
1958 {
1959 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1960 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1961 }
1962
1963 log << tcu::TestLog::EndImageSet;
1964
1965 return numFailedPixels == 0;
1966 }
1967
1968 //! Verifies texture lookup results and returns number of failed pixels.
computeTextureLookupDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture3DView & baseView,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,qpWatchDog * watchDog)1969 int computeTextureLookupDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
1970 const tcu::PixelBufferAccess &errorMask, const tcu::Texture3DView &baseView,
1971 const float *texCoord, const ReferenceParams &sampleParams,
1972 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
1973 qpWatchDog *watchDog)
1974 {
1975 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1976 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1977
1978 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1979 tcu::ImageViewMinLodParams minLodParams = {
1980 sampleParams.baseLevel, // int baseLevel;
1981 {
1982 sampleParams.imageViewMinLod, // float minLod;
1983 sampleParams.imageViewMinLodMode, // ImageViewMinLodMode
1984 },
1985 sampleParams.samplerType == SAMPLERTYPE_FETCH_FLOAT // bool intTexCoord;
1986 };
1987
1988 const tcu::Texture3DView src =
1989 getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel,
1990 sampleParams.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL),
1991 srcLevelStorage, sampleParams.sampler);
1992
1993 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]);
1994 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]);
1995 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]);
1996
1997 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1998 const float dstW = float(dstSize.x());
1999 const float dstH = float(dstSize.y());
2000 const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
2001
2002 // Coordinates and lod per triangle.
2003 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
2004 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
2005 const tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
2006 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
2007
2008 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2009
2010 // imageViewMinLodRel is used to calculate the image level to sample from, when VK_EXT_image_view_min_lod extension is enabled.
2011 // The value is relative to baseLevel as the Texture*View 'src' was created as the baseLevel being level[0].
2012 const float imageViewMinLodRel = sampleParams.imageViewMinLod - (float)sampleParams.baseLevel;
2013 // We need to adapt ImageView's minLod value to the mipmap mdoe (i.e. nearest or linear) so we clamp with the right minLod value later.
2014 const float imageViewMinLodRelMode = tcu::isSamplerMipmapModeLinear(sampleParams.sampler.minFilter) ?
2015 deFloatFloor(imageViewMinLodRel) :
2016 (float)deClamp32((int)deFloatCeil(imageViewMinLodRel + 0.5f) - 1,
2017 sampleParams.baseLevel, sampleParams.maxLevel);
2018 const float minLod = (sampleParams.imageViewMinLod != 0.0f) ? de::max(imageViewMinLodRelMode, sampleParams.minLod) :
2019 sampleParams.minLod;
2020
2021 const float posEps = 1.0f / float(1 << MIN_SUBPIXEL_BITS);
2022
2023 int numFailed = 0;
2024
2025 const tcu::Vec2 lodOffsets[] = {
2026 tcu::Vec2(-1, 0),
2027 tcu::Vec2(+1, 0),
2028 tcu::Vec2(0, -1),
2029 tcu::Vec2(0, +1),
2030 };
2031
2032 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2033
2034 for (int py = 0; py < result.getHeight(); py++)
2035 {
2036 // Ugly hack, validation can take way too long at the moment.
2037 if (watchDog)
2038 qpWatchDog_touch(watchDog);
2039
2040 for (int px = 0; px < result.getWidth(); px++)
2041 {
2042 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2043 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2044
2045 // Try comparison to ideal reference first, and if that fails use slower verificator.
2046 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2047 {
2048 const float wx = (float)px + 0.5f;
2049 const float wy = (float)py + 0.5f;
2050 const float nx = wx / dstW;
2051 const float ny = wy / dstH;
2052
2053 const bool tri0 = (wx - posEps) / dstW + (wy - posEps) / dstH <= 1.0f;
2054 const bool tri1 = (wx + posEps) / dstW + (wy + posEps) / dstH >= 1.0f;
2055
2056 bool isOk = false;
2057
2058 DE_ASSERT(tri0 || tri1);
2059
2060 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2061 for (int triNdx = (tri0 ? 0 : 1); triNdx <= (tri1 ? 1 : 0); triNdx++)
2062 {
2063 const float triWx = triNdx ? dstW - wx : wx;
2064 const float triWy = triNdx ? dstH - wy : wy;
2065 const float triNx = triNdx ? 1.0f - nx : nx;
2066 const float triNy = triNdx ? 1.0f - ny : ny;
2067
2068 const tcu::Vec3 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2069 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2070 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2071 const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2072 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2073 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) *
2074 srcSize.asFloat();
2075 const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2076 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2077 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) *
2078 srcSize.asFloat();
2079
2080 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(
2081 coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
2082
2083 // Compute lod bounds across lodOffsets range.
2084 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2085 {
2086 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2087 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2088 const float nxo = wxo / dstW;
2089 const float nyo = wyo / dstH;
2090
2091 const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2092 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2093 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) *
2094 srcSize.asFloat();
2095 const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2096 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2097 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) *
2098 srcSize.asFloat();
2099 const tcu::Vec2 lodO =
2100 tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(),
2101 coordDyo.y(), coordDyo.z(), lodPrec);
2102
2103 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2104 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2105 }
2106
2107 const tcu::Vec2 clampedLod =
2108 tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
2109
2110 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2111 {
2112 isOk = true;
2113 break;
2114 }
2115 }
2116
2117 if (!isOk)
2118 {
2119 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2120 numFailed += 1;
2121 }
2122 }
2123 }
2124 }
2125
2126 return numFailed;
2127 }
2128
verifyTextureResult(tcu::TestContext & testCtx,const tcu::ConstPixelBufferAccess & result,const tcu::Texture3DView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,const tcu::PixelFormat & pixelFormat)2129 bool verifyTextureResult(tcu::TestContext &testCtx, const tcu::ConstPixelBufferAccess &result,
2130 const tcu::Texture3DView &src, const float *texCoord, const ReferenceParams &sampleParams,
2131 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
2132 const tcu::PixelFormat &pixelFormat)
2133 {
2134 tcu::TestLog &log = testCtx.getLog();
2135 tcu::Surface reference(result.getWidth(), result.getHeight());
2136 tcu::Surface errorMask(result.getWidth(), result.getHeight());
2137 int numFailedPixels;
2138
2139 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2140
2141 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2142 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord,
2143 sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2144
2145 if (numFailedPixels > 0)
2146 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels
2147 << " invalid pixels!" << tcu::TestLog::EndMessage;
2148
2149 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2150 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2151
2152 if (numFailedPixels > 0)
2153 {
2154 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2155 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2156 }
2157
2158 log << tcu::TestLog::EndImageSet;
2159
2160 return numFailedPixels == 0;
2161 }
2162
2163 //! Verifies texture lookup results and returns number of failed pixels.
computeTextureLookupDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture1DArrayView & baseView,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,qpWatchDog * watchDog)2164 int computeTextureLookupDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
2165 const tcu::PixelBufferAccess &errorMask, const tcu::Texture1DArrayView &baseView,
2166 const float *texCoord, const ReferenceParams &sampleParams,
2167 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
2168 qpWatchDog *watchDog)
2169 {
2170 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2171 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2172
2173 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2174 const tcu::Texture1DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
2175
2176 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]);
2177 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]);
2178
2179 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2180 const float dstW = float(dstSize.x());
2181 const float dstH = float(dstSize.y());
2182 const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored.
2183
2184 // Coordinates and lod per triangle.
2185 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
2186 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
2187 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
2188
2189 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2190
2191 int numFailed = 0;
2192
2193 const tcu::Vec2 lodOffsets[] = {
2194 tcu::Vec2(-1, 0),
2195 tcu::Vec2(+1, 0),
2196 tcu::Vec2(0, -1),
2197 tcu::Vec2(0, +1),
2198 };
2199
2200 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2201
2202 for (int py = 0; py < result.getHeight(); py++)
2203 {
2204 // Ugly hack, validation can take way too long at the moment.
2205 if (watchDog)
2206 qpWatchDog_touch(watchDog);
2207
2208 for (int px = 0; px < result.getWidth(); px++)
2209 {
2210 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2211 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2212
2213 // Try comparison to ideal reference first, and if that fails use slower verificator.
2214 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2215 {
2216 const float wx = (float)px + 0.5f;
2217 const float wy = (float)py + 0.5f;
2218 const float nx = wx / dstW;
2219 const float ny = wy / dstH;
2220
2221 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2222 const float triWx = triNdx ? dstW - wx : wx;
2223 const float triWy = triNdx ? dstH - wy : wy;
2224 const float triNx = triNdx ? 1.0f - nx : nx;
2225 const float triNy = triNdx ? 1.0f - ny : ny;
2226
2227 const tcu::Vec2 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2228 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2229 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
2230 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
2231
2232 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
2233
2234 // Compute lod bounds across lodOffsets range.
2235 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2236 {
2237 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2238 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2239 const float nxo = wxo / dstW;
2240 const float nyo = wyo / dstH;
2241
2242 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
2243 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
2244 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
2245
2246 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2247 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2248 }
2249
2250 const tcu::Vec2 clampedLod = tcu::clampLodBounds(
2251 lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2252 const bool isOk =
2253 tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2254
2255 if (!isOk)
2256 {
2257 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2258 numFailed += 1;
2259 }
2260 }
2261 }
2262 }
2263
2264 return numFailed;
2265 }
2266
2267 //! Verifies texture lookup results and returns number of failed pixels.
computeTextureLookupDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture2DArrayView & baseView,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,qpWatchDog * watchDog)2268 int computeTextureLookupDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
2269 const tcu::PixelBufferAccess &errorMask, const tcu::Texture2DArrayView &baseView,
2270 const float *texCoord, const ReferenceParams &sampleParams,
2271 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
2272 qpWatchDog *watchDog)
2273 {
2274 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2275 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2276
2277 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2278 const tcu::Texture2DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
2279
2280 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]);
2281 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]);
2282 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]);
2283
2284 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2285 const float dstW = float(dstSize.x());
2286 const float dstH = float(dstSize.y());
2287 const tcu::Vec2 srcSize =
2288 tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2289
2290 // Coordinates and lod per triangle.
2291 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
2292 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
2293 const tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
2294 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
2295
2296 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2297
2298 int numFailed = 0;
2299
2300 const tcu::Vec2 lodOffsets[] = {
2301 tcu::Vec2(-1, 0),
2302 tcu::Vec2(+1, 0),
2303 tcu::Vec2(0, -1),
2304 tcu::Vec2(0, +1),
2305 };
2306
2307 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2308
2309 for (int py = 0; py < result.getHeight(); py++)
2310 {
2311 // Ugly hack, validation can take way too long at the moment.
2312 if (watchDog)
2313 qpWatchDog_touch(watchDog);
2314
2315 for (int px = 0; px < result.getWidth(); px++)
2316 {
2317 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2318 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2319
2320 // Try comparison to ideal reference first, and if that fails use slower verificator.
2321 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2322 {
2323 const float wx = (float)px + 0.5f;
2324 const float wy = (float)py + 0.5f;
2325 const float nx = wx / dstW;
2326 const float ny = wy / dstH;
2327
2328 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2329 const float triWx = triNdx ? dstW - wx : wx;
2330 const float triWy = triNdx ? dstH - wy : wy;
2331 const float triNx = triNdx ? 1.0f - nx : nx;
2332 const float triNy = triNdx ? 1.0f - ny : ny;
2333
2334 const tcu::Vec3 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2335 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2336 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2337 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2338 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) *
2339 srcSize;
2340 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2341 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) *
2342 srcSize;
2343
2344 tcu::Vec2 lodBounds =
2345 tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2346
2347 // Compute lod bounds across lodOffsets range.
2348 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2349 {
2350 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2351 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2352 const float nxo = wxo / dstW;
2353 const float nyo = wyo / dstH;
2354
2355 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2356 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) *
2357 srcSize;
2358 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2359 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) *
2360 srcSize;
2361 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(),
2362 coordDyo.y(), lodPrec);
2363
2364 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2365 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2366 }
2367
2368 const tcu::Vec2 clampedLod = tcu::clampLodBounds(
2369 lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2370 const bool isOk =
2371 tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2372
2373 if (!isOk)
2374 {
2375 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2376 numFailed += 1;
2377 }
2378 }
2379 }
2380 }
2381
2382 return numFailed;
2383 }
2384
verifyTextureResult(tcu::TestContext & testCtx,const tcu::ConstPixelBufferAccess & result,const tcu::Texture1DArrayView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,const tcu::PixelFormat & pixelFormat)2385 bool verifyTextureResult(tcu::TestContext &testCtx, const tcu::ConstPixelBufferAccess &result,
2386 const tcu::Texture1DArrayView &src, const float *texCoord, const ReferenceParams &sampleParams,
2387 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
2388 const tcu::PixelFormat &pixelFormat)
2389 {
2390 tcu::TestLog &log = testCtx.getLog();
2391 tcu::Surface reference(result.getWidth(), result.getHeight());
2392 tcu::Surface errorMask(result.getWidth(), result.getHeight());
2393 int numFailedPixels;
2394
2395 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2396
2397 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2398 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord,
2399 sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2400
2401 if (numFailedPixels > 0)
2402 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels
2403 << " invalid pixels!" << tcu::TestLog::EndMessage;
2404
2405 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2406 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2407
2408 if (numFailedPixels > 0)
2409 {
2410 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2411 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2412 }
2413
2414 log << tcu::TestLog::EndImageSet;
2415
2416 return numFailedPixels == 0;
2417 }
2418
verifyTextureResult(tcu::TestContext & testCtx,const tcu::ConstPixelBufferAccess & result,const tcu::Texture2DArrayView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::LodPrecision & lodPrec,const tcu::PixelFormat & pixelFormat)2419 bool verifyTextureResult(tcu::TestContext &testCtx, const tcu::ConstPixelBufferAccess &result,
2420 const tcu::Texture2DArrayView &src, const float *texCoord, const ReferenceParams &sampleParams,
2421 const tcu::LookupPrecision &lookupPrec, const tcu::LodPrecision &lodPrec,
2422 const tcu::PixelFormat &pixelFormat)
2423 {
2424 tcu::TestLog &log = testCtx.getLog();
2425 tcu::Surface reference(result.getWidth(), result.getHeight());
2426 tcu::Surface errorMask(result.getWidth(), result.getHeight());
2427 int numFailedPixels;
2428
2429 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2430
2431 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2432 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord,
2433 sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2434
2435 if (numFailedPixels > 0)
2436 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels
2437 << " invalid pixels!" << tcu::TestLog::EndMessage;
2438
2439 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2440 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2441
2442 if (numFailedPixels > 0)
2443 {
2444 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2445 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2446 }
2447
2448 log << tcu::TestLog::EndImageSet;
2449
2450 return numFailedPixels == 0;
2451 }
2452
2453 //! Verifies texture lookup results and returns number of failed pixels.
computeTextureLookupDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::TextureCubeArrayView & baseView,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::IVec4 & coordBits,const tcu::LodPrecision & lodPrec,qpWatchDog * watchDog)2454 int computeTextureLookupDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
2455 const tcu::PixelBufferAccess &errorMask, const tcu::TextureCubeArrayView &baseView,
2456 const float *texCoord, const ReferenceParams &sampleParams,
2457 const tcu::LookupPrecision &lookupPrec, const tcu::IVec4 &coordBits,
2458 const tcu::LodPrecision &lodPrec, qpWatchDog *watchDog)
2459 {
2460 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2461 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2462
2463 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2464 tcu::ImageViewMinLodParams minLodParams = {
2465 sampleParams.baseLevel, // int baseLevel;
2466 {
2467 sampleParams.imageViewMinLod, // float minLod;
2468 sampleParams.imageViewMinLodMode, // ImageViewMinLodMode
2469 },
2470 sampleParams.samplerType == SAMPLERTYPE_FETCH_FLOAT // bool intTexCoord;
2471 };
2472
2473 const tcu::TextureCubeArrayView src =
2474 getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel,
2475 sampleParams.imageViewMinLod != 0.0f ? &minLodParams : DE_NULL),
2476 srcLevelStorage, sampleParams.sampler);
2477
2478 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[4 + 0], texCoord[8 + 0], texCoord[12 + 0]);
2479 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[4 + 1], texCoord[8 + 1], texCoord[12 + 1]);
2480 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[4 + 2], texCoord[8 + 2], texCoord[12 + 2]);
2481 const tcu::Vec4 qq = tcu::Vec4(texCoord[0 + 3], texCoord[4 + 3], texCoord[8 + 3], texCoord[12 + 3]);
2482
2483 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2484 const float dstW = float(dstSize.x());
2485 const float dstH = float(dstSize.y());
2486 const int srcSize = src.getSize();
2487
2488 // Coordinates per triangle.
2489 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
2490 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
2491 const tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
2492 const tcu::Vec3 triQ[2] = {qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1)};
2493 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
2494
2495 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2496
2497 const float posEps = 1.0f / float((1 << 4) + 1); // ES3 requires at least 4 subpixel bits.
2498
2499 int numFailed = 0;
2500
2501 const tcu::Vec2 lodOffsets[] = {
2502 tcu::Vec2(-1, 0),
2503 tcu::Vec2(+1, 0),
2504 tcu::Vec2(0, -1),
2505 tcu::Vec2(0, +1),
2506
2507 // \note Not strictly allowed by spec, but implementations do this in practice.
2508 tcu::Vec2(-1, -1),
2509 tcu::Vec2(-1, +1),
2510 tcu::Vec2(+1, -1),
2511 tcu::Vec2(+1, +1),
2512 };
2513
2514 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2515
2516 for (int py = 0; py < result.getHeight(); py++)
2517 {
2518 // Ugly hack, validation can take way too long at the moment.
2519 if (watchDog)
2520 qpWatchDog_touch(watchDog);
2521
2522 for (int px = 0; px < result.getWidth(); px++)
2523 {
2524 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2525 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2526
2527 // Try comparison to ideal reference first, and if that fails use slower verificator.
2528 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2529 {
2530 const float wx = (float)px + 0.5f;
2531 const float wy = (float)py + 0.5f;
2532 const float nx = wx / dstW;
2533 const float ny = wy / dstH;
2534
2535 const bool tri0 = nx + ny - posEps <= 1.0f;
2536 const bool tri1 = nx + ny + posEps >= 1.0f;
2537
2538 bool isOk = false;
2539
2540 DE_ASSERT(tri0 || tri1);
2541
2542 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2543 for (int triNdx = (tri0 ? 0 : 1); triNdx <= (tri1 ? 1 : 0); triNdx++)
2544 {
2545 const float triWx = triNdx ? dstW - wx : wx;
2546 const float triWy = triNdx ? dstH - wy : wy;
2547 const float triNx = triNdx ? 1.0f - nx : nx;
2548 const float triNy = triNdx ? 1.0f - ny : ny;
2549
2550 const tcu::Vec4 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2551 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2552 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2553 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2554 const tcu::Vec3 coordDx(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2555 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2556 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2557 const tcu::Vec3 coordDy(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2558 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2559 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2560
2561 tcu::Vec2 lodBounds =
2562 tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2563
2564 // Compute lod bounds across lodOffsets range.
2565 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2566 {
2567 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2568 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2569 const float nxo = wxo / dstW;
2570 const float nyo = wyo / dstH;
2571
2572 const tcu::Vec3 coordO(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2573 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2574 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2575 const tcu::Vec3 coordDxo(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2576 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2577 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2578 const tcu::Vec3 coordDyo(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2579 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2580 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2581 const tcu::Vec2 lodO =
2582 tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2583
2584 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2585 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2586 }
2587
2588 const tcu::Vec2 clampedLod = tcu::clampLodBounds(
2589 lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2590
2591 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod,
2592 resPix))
2593 {
2594 isOk = true;
2595 break;
2596 }
2597 }
2598
2599 if (!isOk)
2600 {
2601 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2602 numFailed += 1;
2603 }
2604 }
2605 }
2606 }
2607
2608 return numFailed;
2609 }
2610
verifyTextureResult(tcu::TestContext & testCtx,const tcu::ConstPixelBufferAccess & result,const tcu::TextureCubeArrayView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::LookupPrecision & lookupPrec,const tcu::IVec4 & coordBits,const tcu::LodPrecision & lodPrec,const tcu::PixelFormat & pixelFormat)2611 bool verifyTextureResult(tcu::TestContext &testCtx, const tcu::ConstPixelBufferAccess &result,
2612 const tcu::TextureCubeArrayView &src, const float *texCoord,
2613 const ReferenceParams &sampleParams, const tcu::LookupPrecision &lookupPrec,
2614 const tcu::IVec4 &coordBits, const tcu::LodPrecision &lodPrec,
2615 const tcu::PixelFormat &pixelFormat)
2616 {
2617 tcu::TestLog &log = testCtx.getLog();
2618 tcu::Surface reference(result.getWidth(), result.getHeight());
2619 tcu::Surface errorMask(result.getWidth(), result.getHeight());
2620 int numFailedPixels;
2621
2622 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2623
2624 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2625 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord,
2626 sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2627
2628 if (numFailedPixels > 0)
2629 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels
2630 << " invalid pixels!" << tcu::TestLog::EndMessage;
2631
2632 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2633 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2634
2635 if (numFailedPixels > 0)
2636 {
2637 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2638 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2639 }
2640
2641 log << tcu::TestLog::EndImageSet;
2642
2643 return numFailedPixels == 0;
2644 }
2645
2646 // Shadow lookup verification
2647
computeTextureCompareDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture2DView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::TexComparePrecision & comparePrec,const tcu::LodPrecision & lodPrec,const tcu::Vec3 & nonShadowThreshold)2648 int computeTextureCompareDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
2649 const tcu::PixelBufferAccess &errorMask, const tcu::Texture2DView &src,
2650 const float *texCoord, const ReferenceParams &sampleParams,
2651 const tcu::TexComparePrecision &comparePrec, const tcu::LodPrecision &lodPrec,
2652 const tcu::Vec3 &nonShadowThreshold)
2653 {
2654 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2655 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2656
2657 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]);
2658 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]);
2659
2660 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2661 const float dstW = float(dstSize.x());
2662 const float dstH = float(dstSize.y());
2663 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2664
2665 // Coordinates and lod per triangle.
2666 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
2667 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
2668 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
2669
2670 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2671
2672 const float minLod = (sampleParams.imageViewMinLod != 0.0f) ?
2673 de::max(deFloatFloor(sampleParams.imageViewMinLod), sampleParams.minLod) :
2674 sampleParams.minLod;
2675
2676 int numFailed = 0;
2677
2678 const tcu::Vec2 lodOffsets[] = {
2679 tcu::Vec2(-1, 0),
2680 tcu::Vec2(+1, 0),
2681 tcu::Vec2(0, -1),
2682 tcu::Vec2(0, +1),
2683 };
2684
2685 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2686
2687 for (int py = 0; py < result.getHeight(); py++)
2688 {
2689 for (int px = 0; px < result.getWidth(); px++)
2690 {
2691 const tcu::Vec4 resPix = result.getPixel(px, py);
2692 const tcu::Vec4 refPix = reference.getPixel(px, py);
2693
2694 // Other channels should trivially match to reference.
2695 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1, 2, 3) - resPix.swizzle(1, 2, 3)),
2696 nonShadowThreshold)))
2697 {
2698 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2699 numFailed += 1;
2700 continue;
2701 }
2702
2703 // Reference result is known to be a valid result, we can
2704 // skip verification if thes results are equal
2705 if (resPix.x() != refPix.x())
2706 {
2707 const float wx = (float)px + 0.5f;
2708 const float wy = (float)py + 0.5f;
2709 const float nx = wx / dstW;
2710 const float ny = wy / dstH;
2711
2712 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2713 const float triWx = triNdx ? dstW - wx : wx;
2714 const float triWy = triNdx ? dstH - wy : wy;
2715 const float triNx = triNdx ? 1.0f - nx : nx;
2716 const float triNy = triNdx ? 1.0f - ny : ny;
2717
2718 const tcu::Vec2 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2719 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2720 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2721 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) *
2722 srcSize.asFloat();
2723 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2724 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) *
2725 srcSize.asFloat();
2726
2727 tcu::Vec2 lodBounds =
2728 tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2729
2730 // Compute lod bounds across lodOffsets range.
2731 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2732 {
2733 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2734 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2735 const float nxo = wxo / dstW;
2736 const float nyo = wyo / dstH;
2737
2738 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2739 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) *
2740 srcSize.asFloat();
2741 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2742 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) *
2743 srcSize.asFloat();
2744 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(),
2745 coordDyo.y(), lodPrec);
2746
2747 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2748 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2749 }
2750
2751 const tcu::Vec2 clampedLod =
2752 tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
2753 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord,
2754 clampedLod, sampleParams.ref, resPix.x());
2755
2756 if (!isOk)
2757 {
2758 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2759 numFailed += 1;
2760 }
2761 }
2762 }
2763 }
2764
2765 return numFailed;
2766 }
2767
computeTextureCompareDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::TextureCubeView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::TexComparePrecision & comparePrec,const tcu::LodPrecision & lodPrec,const tcu::Vec3 & nonShadowThreshold)2768 int computeTextureCompareDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
2769 const tcu::PixelBufferAccess &errorMask, const tcu::TextureCubeView &src,
2770 const float *texCoord, const ReferenceParams &sampleParams,
2771 const tcu::TexComparePrecision &comparePrec, const tcu::LodPrecision &lodPrec,
2772 const tcu::Vec3 &nonShadowThreshold)
2773 {
2774 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2775 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2776
2777 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]);
2778 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]);
2779 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]);
2780
2781 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2782 const float dstW = float(dstSize.x());
2783 const float dstH = float(dstSize.y());
2784 const int srcSize = src.getSize();
2785
2786 // Coordinates per triangle.
2787 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
2788 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
2789 const tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
2790 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
2791
2792 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2793
2794 const float minLod = (sampleParams.imageViewMinLod != 0.0f) ?
2795 de::max(deFloatFloor(sampleParams.imageViewMinLod), sampleParams.minLod) :
2796 sampleParams.minLod;
2797
2798 int numFailed = 0;
2799
2800 const tcu::Vec2 lodOffsets[] = {
2801 tcu::Vec2(-1, 0),
2802 tcu::Vec2(+1, 0),
2803 tcu::Vec2(0, -1),
2804 tcu::Vec2(0, +1),
2805 };
2806
2807 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2808
2809 for (int py = 0; py < result.getHeight(); py++)
2810 {
2811 for (int px = 0; px < result.getWidth(); px++)
2812 {
2813 const tcu::Vec4 resPix = result.getPixel(px, py);
2814 const tcu::Vec4 refPix = reference.getPixel(px, py);
2815
2816 // Other channels should trivially match to reference.
2817 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1, 2, 3) - resPix.swizzle(1, 2, 3)),
2818 nonShadowThreshold)))
2819 {
2820 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2821 numFailed += 1;
2822 continue;
2823 }
2824
2825 // Reference result is known to be a valid result, we can
2826 // skip verification if thes results are equal
2827 if (resPix.x() != refPix.x())
2828 {
2829 const float wx = (float)px + 0.5f;
2830 const float wy = (float)py + 0.5f;
2831 const float nx = wx / dstW;
2832 const float ny = wy / dstH;
2833
2834 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2835 const float triWx = triNdx ? dstW - wx : wx;
2836 const float triWy = triNdx ? dstH - wy : wy;
2837 const float triNx = triNdx ? 1.0f - nx : nx;
2838 const float triNy = triNdx ? 1.0f - ny : ny;
2839
2840 const tcu::Vec3 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2841 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2842 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2843 const tcu::Vec3 coordDx(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2844 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2845 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2846 const tcu::Vec3 coordDy(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2847 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2848 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2849
2850 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2851
2852 // Compute lod bounds across lodOffsets range.
2853 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2854 {
2855 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2856 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2857 const float nxo = wxo / dstW;
2858 const float nyo = wyo / dstH;
2859
2860 const tcu::Vec3 coordO(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2861 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2862 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2863 const tcu::Vec3 coordDxo(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2864 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2865 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2866 const tcu::Vec3 coordDyo(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2867 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2868 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2869 const tcu::Vec2 lodO =
2870 tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2871
2872 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2873 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2874 }
2875
2876 const tcu::Vec2 clampedLod =
2877 tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(minLod, sampleParams.maxLod), lodPrec);
2878 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord,
2879 clampedLod, sampleParams.ref, resPix.x());
2880
2881 if (!isOk)
2882 {
2883 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2884 numFailed += 1;
2885 }
2886 }
2887 }
2888 }
2889
2890 return numFailed;
2891 }
2892
computeTextureCompareDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture2DArrayView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::TexComparePrecision & comparePrec,const tcu::LodPrecision & lodPrec,const tcu::Vec3 & nonShadowThreshold)2893 int computeTextureCompareDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
2894 const tcu::PixelBufferAccess &errorMask, const tcu::Texture2DArrayView &src,
2895 const float *texCoord, const ReferenceParams &sampleParams,
2896 const tcu::TexComparePrecision &comparePrec, const tcu::LodPrecision &lodPrec,
2897 const tcu::Vec3 &nonShadowThreshold)
2898 {
2899 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2900 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2901
2902 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]);
2903 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]);
2904 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]);
2905
2906 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2907 const float dstW = float(dstSize.x());
2908 const float dstH = float(dstSize.y());
2909 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2910
2911 // Coordinates and lod per triangle.
2912 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
2913 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
2914 const tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
2915 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
2916
2917 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2918
2919 int numFailed = 0;
2920
2921 const tcu::Vec2 lodOffsets[] = {
2922 tcu::Vec2(-1, 0),
2923 tcu::Vec2(+1, 0),
2924 tcu::Vec2(0, -1),
2925 tcu::Vec2(0, +1),
2926 };
2927
2928 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2929
2930 for (int py = 0; py < result.getHeight(); py++)
2931 {
2932 for (int px = 0; px < result.getWidth(); px++)
2933 {
2934 const tcu::Vec4 resPix = result.getPixel(px, py);
2935 const tcu::Vec4 refPix = reference.getPixel(px, py);
2936
2937 // Other channels should trivially match to reference.
2938 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1, 2, 3) - resPix.swizzle(1, 2, 3)),
2939 nonShadowThreshold)))
2940 {
2941 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2942 numFailed += 1;
2943 continue;
2944 }
2945
2946 // Reference result is known to be a valid result, we can
2947 // skip verification if thes results are equal
2948 if (resPix.x() != refPix.x())
2949 {
2950 const float wx = (float)px + 0.5f;
2951 const float wy = (float)py + 0.5f;
2952 const float nx = wx / dstW;
2953 const float ny = wy / dstH;
2954
2955 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2956 const float triWx = triNdx ? dstW - wx : wx;
2957 const float triWy = triNdx ? dstH - wy : wy;
2958 const float triNx = triNdx ? 1.0f - nx : nx;
2959 const float triNy = triNdx ? 1.0f - ny : ny;
2960
2961 const tcu::Vec3 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2962 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2963 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2964 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2965 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) *
2966 srcSize.asFloat();
2967 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2968 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) *
2969 srcSize.asFloat();
2970
2971 tcu::Vec2 lodBounds =
2972 tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2973
2974 // Compute lod bounds across lodOffsets range.
2975 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2976 {
2977 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2978 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2979 const float nxo = wxo / dstW;
2980 const float nyo = wyo / dstH;
2981
2982 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2983 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) *
2984 srcSize.asFloat();
2985 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2986 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) *
2987 srcSize.asFloat();
2988 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(),
2989 coordDyo.y(), lodPrec);
2990
2991 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2992 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2993 }
2994
2995 const tcu::Vec2 clampedLod = tcu::clampLodBounds(
2996 lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2997 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord,
2998 clampedLod, sampleParams.ref, resPix.x());
2999
3000 if (!isOk)
3001 {
3002 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3003 numFailed += 1;
3004 }
3005 }
3006 }
3007 }
3008
3009 return numFailed;
3010 }
3011
computeTextureCompareDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture1DView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::TexComparePrecision & comparePrec,const tcu::LodPrecision & lodPrec,const tcu::Vec3 & nonShadowThreshold)3012 int computeTextureCompareDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
3013 const tcu::PixelBufferAccess &errorMask, const tcu::Texture1DView &src,
3014 const float *texCoord, const ReferenceParams &sampleParams,
3015 const tcu::TexComparePrecision &comparePrec, const tcu::LodPrecision &lodPrec,
3016 const tcu::Vec3 &nonShadowThreshold)
3017 {
3018 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3019 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3020 DE_ASSERT(result.getHeight() == 1);
3021
3022 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
3023
3024 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), 1);
3025 const float dstW = float(dstSize.x());
3026 const float dstH = float(dstSize.y());
3027 const float srcSize = float(src.getWidth());
3028
3029 // Coordinates and lod per triangle.
3030 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
3031 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
3032
3033 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3034
3035 int numFailed = 0;
3036
3037 const tcu::Vec2 lodOffsets[] = {
3038 tcu::Vec2(-1, 0),
3039 tcu::Vec2(+1, 0),
3040 tcu::Vec2(0, -1),
3041 tcu::Vec2(0, +1),
3042 };
3043
3044 tcu::clear(errorMask, tcu::RGBA::green().toVec());
3045
3046 const int py = 0;
3047 {
3048 for (int px = 0; px < result.getWidth(); px++)
3049 {
3050 const tcu::Vec4 resPix = result.getPixel(px, py);
3051 const tcu::Vec4 refPix = reference.getPixel(px, py);
3052
3053 // Other channels should trivially match to reference.
3054 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1, 2, 3) - resPix.swizzle(1, 2, 3)),
3055 nonShadowThreshold)))
3056 {
3057 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3058 numFailed += 1;
3059 continue;
3060 }
3061
3062 // Reference result is known to be a valid result, we can
3063 // skip verification if thes results are equal
3064 if (resPix.x() != refPix.x())
3065 {
3066 const float wx = (float)px + 0.5f;
3067 const float wy = (float)py + 0.5f;
3068 const float nx = wx / dstW;
3069 const float ny = wy / dstH;
3070
3071 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
3072 const float triWx = triNdx ? dstW - wx : wx;
3073 const float triWy = triNdx ? dstH - wy : wy;
3074 const float triNx = triNdx ? 1.0f - nx : nx;
3075 const float triNy = triNdx ? 1.0f - ny : ny;
3076
3077 const float coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy));
3078 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
3079
3080 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDx, lodPrec);
3081
3082 // Compute lod bounds across lodOffsets range.
3083 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3084 {
3085 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
3086 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
3087 const float nxo = wxo / dstW;
3088 const float nyo = wyo / dstH;
3089
3090 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
3091 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
3092 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
3093
3094 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3095 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3096 }
3097
3098 const tcu::Vec2 clampedLod = tcu::clampLodBounds(
3099 lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3100 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, tcu::Vec1(coord),
3101 clampedLod, sampleParams.ref, resPix.x());
3102
3103 if (!isOk)
3104 {
3105 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3106 numFailed += 1;
3107 }
3108 }
3109 }
3110 }
3111
3112 return numFailed;
3113 }
3114
computeTextureCompareDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::Texture1DArrayView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::TexComparePrecision & comparePrec,const tcu::LodPrecision & lodPrec,const tcu::Vec3 & nonShadowThreshold)3115 int computeTextureCompareDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
3116 const tcu::PixelBufferAccess &errorMask, const tcu::Texture1DArrayView &src,
3117 const float *texCoord, const ReferenceParams &sampleParams,
3118 const tcu::TexComparePrecision &comparePrec, const tcu::LodPrecision &lodPrec,
3119 const tcu::Vec3 &nonShadowThreshold)
3120 {
3121 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3122 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3123 DE_ASSERT(result.getHeight() == 1);
3124
3125 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]);
3126 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]);
3127
3128 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), 1);
3129 const float dstW = float(dstSize.x());
3130 const float dstH = float(dstSize.y());
3131 const float srcSize = float(src.getWidth());
3132
3133 // Coordinates and lod per triangle.
3134 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
3135 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
3136 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
3137
3138 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3139
3140 int numFailed = 0;
3141
3142 const tcu::Vec2 lodOffsets[] = {
3143 tcu::Vec2(-1, 0),
3144 tcu::Vec2(+1, 0),
3145 tcu::Vec2(0, -1),
3146 tcu::Vec2(0, +1),
3147 };
3148
3149 tcu::clear(errorMask, tcu::RGBA::green().toVec());
3150
3151 const int py = 0;
3152 {
3153 for (int px = 0; px < result.getWidth(); px++)
3154 {
3155 const tcu::Vec4 resPix = result.getPixel(px, py);
3156 const tcu::Vec4 refPix = reference.getPixel(px, py);
3157
3158 // Other channels should trivially match to reference.
3159 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1, 2, 3) - resPix.swizzle(1, 2, 3)),
3160 nonShadowThreshold)))
3161 {
3162 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3163 numFailed += 1;
3164 continue;
3165 }
3166
3167 // Reference result is known to be a valid result, we can
3168 // skip verification if these results are equal
3169 if (resPix.x() != refPix.x())
3170 {
3171 const float wx = (float)px + 0.5f;
3172 const float wy = (float)py + 0.5f;
3173 const float nx = wx / dstW;
3174 const float ny = wy / dstH;
3175
3176 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
3177 const float triWx = triNdx ? dstW - wx : wx;
3178 const float triWy = triNdx ? dstH - wy : wy;
3179 const float triNx = triNdx ? 1.0f - nx : nx;
3180 const float triNy = triNdx ? 1.0f - ny : ny;
3181
3182 const tcu::Vec2 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3183 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
3184 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
3185
3186 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDx, lodPrec);
3187
3188 // Compute lod bounds across lodOffsets range.
3189 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3190 {
3191 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
3192 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
3193 const float nxo = wxo / dstW;
3194 const float nyo = wyo / dstH;
3195
3196 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
3197 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
3198 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
3199
3200 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3201 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3202 }
3203
3204 const tcu::Vec2 clampedLod = tcu::clampLodBounds(
3205 lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3206 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord,
3207 clampedLod, sampleParams.ref, resPix.x());
3208
3209 if (!isOk)
3210 {
3211 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3212 numFailed += 1;
3213 }
3214 }
3215 }
3216 }
3217
3218 return numFailed;
3219 }
3220
computeTextureCompareDiff(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,const tcu::TextureCubeArrayView & src,const float * texCoord,const ReferenceParams & sampleParams,const tcu::TexComparePrecision & comparePrec,const tcu::LodPrecision & lodPrec,const tcu::Vec3 & nonShadowThreshold)3221 int computeTextureCompareDiff(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
3222 const tcu::PixelBufferAccess &errorMask, const tcu::TextureCubeArrayView &src,
3223 const float *texCoord, const ReferenceParams &sampleParams,
3224 const tcu::TexComparePrecision &comparePrec, const tcu::LodPrecision &lodPrec,
3225 const tcu::Vec3 &nonShadowThreshold)
3226 {
3227 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3228 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3229
3230 const tcu::Vec4 sq = tcu::Vec4(texCoord[0 + 0], texCoord[4 + 0], texCoord[8 + 0], texCoord[12 + 0]);
3231 const tcu::Vec4 tq = tcu::Vec4(texCoord[0 + 1], texCoord[4 + 1], texCoord[8 + 1], texCoord[12 + 1]);
3232 const tcu::Vec4 rq = tcu::Vec4(texCoord[0 + 2], texCoord[4 + 2], texCoord[8 + 2], texCoord[12 + 2]);
3233 const tcu::Vec4 qq = tcu::Vec4(texCoord[0 + 3], texCoord[4 + 3], texCoord[8 + 3], texCoord[12 + 3]);
3234
3235 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
3236 const float dstW = float(dstSize.x());
3237 const float dstH = float(dstSize.y());
3238 const int srcSize = src.getSize();
3239
3240 // Coordinates per triangle.
3241 const tcu::Vec3 triS[2] = {sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1)};
3242 const tcu::Vec3 triT[2] = {tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1)};
3243 const tcu::Vec3 triR[2] = {rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1)};
3244 const tcu::Vec3 triQ[2] = {qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1)};
3245 const tcu::Vec3 triW[2] = {sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1)};
3246
3247 const tcu::Vec2 lodBias((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3248
3249 int numFailed = 0;
3250
3251 const tcu::Vec2 lodOffsets[] = {
3252 tcu::Vec2(-1, 0),
3253 tcu::Vec2(+1, 0),
3254 tcu::Vec2(0, -1),
3255 tcu::Vec2(0, +1),
3256 };
3257
3258 tcu::clear(errorMask, tcu::RGBA::green().toVec());
3259
3260 for (int py = 0; py < result.getHeight(); py++)
3261 {
3262 for (int px = 0; px < result.getWidth(); px++)
3263 {
3264 const tcu::Vec4 resPix = result.getPixel(px, py);
3265 const tcu::Vec4 refPix = reference.getPixel(px, py);
3266
3267 // Other channels should trivially match to reference.
3268 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1, 2, 3) - resPix.swizzle(1, 2, 3)),
3269 nonShadowThreshold)))
3270 {
3271 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3272 numFailed += 1;
3273 continue;
3274 }
3275
3276 // Reference result is known to be a valid result, we can
3277 // skip verification if thes results are equal
3278 if (resPix.x() != refPix.x())
3279 {
3280 const float wx = (float)px + 0.5f;
3281 const float wy = (float)py + 0.5f;
3282 const float nx = wx / dstW;
3283 const float ny = wy / dstH;
3284
3285 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
3286 const float triWx = triNdx ? dstW - wx : wx;
3287 const float triWy = triNdx ? dstH - wy : wy;
3288 const float triNx = triNdx ? 1.0f - nx : nx;
3289 const float triNy = triNdx ? 1.0f - ny : ny;
3290
3291 const tcu::Vec4 coord(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3292 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
3293 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
3294 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
3295 const tcu::Vec3 coordDx(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
3296 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
3297 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
3298 const tcu::Vec3 coordDy(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
3299 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
3300 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
3301
3302 tcu::Vec2 lodBounds =
3303 tcu::computeCubeLodBoundsFromDerivates(coord.swizzle(0, 1, 2), coordDx, coordDy, srcSize, lodPrec);
3304
3305 // Compute lod bounds across lodOffsets range.
3306 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3307 {
3308 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
3309 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
3310 const float nxo = wxo / dstW;
3311 const float nyo = wyo / dstH;
3312
3313 const tcu::Vec3 coordO(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
3314 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
3315 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
3316 const tcu::Vec3 coordDxo(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
3317 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
3318 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
3319 const tcu::Vec3 coordDyo(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
3320 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
3321 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
3322 const tcu::Vec2 lodO =
3323 tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
3324
3325 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3326 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3327 }
3328
3329 const tcu::Vec2 clampedLod = tcu::clampLodBounds(
3330 lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3331 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord,
3332 clampedLod, sampleParams.ref, resPix.x());
3333
3334 if (!isOk)
3335 {
3336 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3337 numFailed += 1;
3338 }
3339 }
3340 }
3341 }
3342
3343 return numFailed;
3344 }
3345
3346 // Mipmap generation comparison.
3347
compareGenMipmapBilinear(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)3348 static int compareGenMipmapBilinear(const tcu::ConstPixelBufferAccess &dst, const tcu::ConstPixelBufferAccess &src,
3349 const tcu::PixelBufferAccess &errorMask, const GenMipmapPrecision &precision)
3350 {
3351 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3352
3353 const float dstW = float(dst.getWidth());
3354 const float dstH = float(dst.getHeight());
3355 const float srcW = float(src.getWidth());
3356 const float srcH = float(src.getHeight());
3357 int numFailed = 0;
3358
3359 // Translation to lookup verification parameters.
3360 const tcu::Sampler sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3361 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3362 tcu::LookupPrecision lookupPrec;
3363
3364 lookupPrec.colorThreshold = precision.colorThreshold;
3365 lookupPrec.colorMask = precision.colorMask;
3366 lookupPrec.coordBits = tcu::IVec3(22);
3367 lookupPrec.uvwBits = precision.filterBits;
3368
3369 for (int y = 0; y < dst.getHeight(); y++)
3370 for (int x = 0; x < dst.getWidth(); x++)
3371 {
3372 const tcu::Vec4 result = dst.getPixel(x, y);
3373 const float cx = (float(x) + 0.5f) / dstW * srcW;
3374 const float cy = (float(y) + 0.5f) / dstH * srcH;
3375 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3376
3377 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3378 if (!isOk)
3379 numFailed += 1;
3380 }
3381
3382 return numFailed;
3383 }
3384
compareGenMipmapBox(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)3385 static int compareGenMipmapBox(const tcu::ConstPixelBufferAccess &dst, const tcu::ConstPixelBufferAccess &src,
3386 const tcu::PixelBufferAccess &errorMask, const GenMipmapPrecision &precision)
3387 {
3388 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3389
3390 const float dstW = float(dst.getWidth());
3391 const float dstH = float(dst.getHeight());
3392 const float srcW = float(src.getWidth());
3393 const float srcH = float(src.getHeight());
3394 int numFailed = 0;
3395
3396 // Translation to lookup verification parameters.
3397 const tcu::Sampler sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3398 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3399 tcu::LookupPrecision lookupPrec;
3400
3401 lookupPrec.colorThreshold = precision.colorThreshold;
3402 lookupPrec.colorMask = precision.colorMask;
3403 lookupPrec.coordBits = tcu::IVec3(22);
3404 lookupPrec.uvwBits = precision.filterBits;
3405
3406 for (int y = 0; y < dst.getHeight(); y++)
3407 for (int x = 0; x < dst.getWidth(); x++)
3408 {
3409 const tcu::Vec4 result = dst.getPixel(x, y);
3410 const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
3411 const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
3412 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3413
3414 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3415 if (!isOk)
3416 numFailed += 1;
3417 }
3418
3419 return numFailed;
3420 }
3421
compareGenMipmapVeryLenient(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)3422 static int compareGenMipmapVeryLenient(const tcu::ConstPixelBufferAccess &dst, const tcu::ConstPixelBufferAccess &src,
3423 const tcu::PixelBufferAccess &errorMask, const GenMipmapPrecision &precision)
3424 {
3425 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3426 DE_UNREF(precision);
3427
3428 const float dstW = float(dst.getWidth());
3429 const float dstH = float(dst.getHeight());
3430 const float srcW = float(src.getWidth());
3431 const float srcH = float(src.getHeight());
3432 int numFailed = 0;
3433
3434 for (int y = 0; y < dst.getHeight(); y++)
3435 for (int x = 0; x < dst.getWidth(); x++)
3436 {
3437 const tcu::Vec4 result = dst.getPixel(x, y);
3438 const int minX = deFloorFloatToInt32(((float)x - 0.5f) / dstW * srcW);
3439 const int minY = deFloorFloatToInt32(((float)y - 0.5f) / dstH * srcH);
3440 const int maxX = deCeilFloatToInt32(((float)x + 1.5f) / dstW * srcW);
3441 const int maxY = deCeilFloatToInt32(((float)y + 1.5f) / dstH * srcH);
3442 tcu::Vec4 minVal, maxVal;
3443 bool isOk;
3444
3445 DE_ASSERT(minX < maxX && minY < maxY);
3446
3447 for (int ky = minY; ky <= maxY; ky++)
3448 {
3449 for (int kx = minX; kx <= maxX; kx++)
3450 {
3451 const int sx = de::clamp(kx, 0, src.getWidth() - 1);
3452 const int sy = de::clamp(ky, 0, src.getHeight() - 1);
3453 const tcu::Vec4 sample = src.getPixel(sx, sy);
3454
3455 if (ky == minY && kx == minX)
3456 {
3457 minVal = sample;
3458 maxVal = sample;
3459 }
3460 else
3461 {
3462 minVal = min(sample, minVal);
3463 maxVal = max(sample, maxVal);
3464 }
3465 }
3466 }
3467
3468 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
3469
3470 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3471 if (!isOk)
3472 numFailed += 1;
3473 }
3474
3475 return numFailed;
3476 }
3477
compareGenMipmapResult(tcu::TestLog & log,const tcu::Texture2D & resultTexture,const tcu::Texture2D & level0Reference,const GenMipmapPrecision & precision)3478 qpTestResult compareGenMipmapResult(tcu::TestLog &log, const tcu::Texture2D &resultTexture,
3479 const tcu::Texture2D &level0Reference, const GenMipmapPrecision &precision)
3480 {
3481 qpTestResult result = QP_TEST_RESULT_PASS;
3482
3483 // Special comparison for level 0.
3484 {
3485 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3486 const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0),
3487 resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
3488
3489 if (!level0Ok)
3490 {
3491 log << tcu::TestLog::Message << "ERROR: Level 0 comparison failed!" << tcu::TestLog::EndMessage;
3492 result = QP_TEST_RESULT_FAIL;
3493 }
3494 }
3495
3496 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3497 {
3498 const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx - 1);
3499 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx);
3500 tcu::Surface errorMask(dst.getWidth(), dst.getHeight());
3501 bool levelOk = false;
3502
3503 // Try different comparisons in quality order.
3504
3505 if (!levelOk)
3506 {
3507 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3508 if (numFailed == 0)
3509 levelOk = true;
3510 else
3511 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx
3512 << " comparison to bilinear method failed, found " << numFailed << " invalid pixels."
3513 << tcu::TestLog::EndMessage;
3514 }
3515
3516 if (!levelOk)
3517 {
3518 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3519 if (numFailed == 0)
3520 levelOk = true;
3521 else
3522 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx
3523 << " comparison to box method failed, found " << numFailed << " invalid pixels."
3524 << tcu::TestLog::EndMessage;
3525 }
3526
3527 // At this point all high-quality methods have been used.
3528 if (!levelOk && result == QP_TEST_RESULT_PASS)
3529 result = QP_TEST_RESULT_QUALITY_WARNING;
3530
3531 if (!levelOk)
3532 {
3533 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3534 if (numFailed == 0)
3535 levelOk = true;
3536 else
3537 log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed
3538 << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
3539 }
3540
3541 if (!levelOk)
3542 result = QP_TEST_RESULT_FAIL;
3543
3544 log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx),
3545 string("Level ") + de::toString(levelNdx) + " result")
3546 << tcu::TestLog::Image("Result", "Result", dst);
3547
3548 if (!levelOk)
3549 log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
3550
3551 log << tcu::TestLog::EndImageSet;
3552 }
3553
3554 return result;
3555 }
3556
compareGenMipmapResult(tcu::TestLog & log,const tcu::TextureCube & resultTexture,const tcu::TextureCube & level0Reference,const GenMipmapPrecision & precision)3557 qpTestResult compareGenMipmapResult(tcu::TestLog &log, const tcu::TextureCube &resultTexture,
3558 const tcu::TextureCube &level0Reference, const GenMipmapPrecision &precision)
3559 {
3560 qpTestResult result = QP_TEST_RESULT_PASS;
3561
3562 static const char *s_faceNames[] = {"-X", "+X", "-Y", "+Y", "-Z", "+Z"};
3563 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
3564
3565 // Special comparison for level 0.
3566 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3567 {
3568 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3569 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3570 const bool level0Ok = tcu::floatThresholdCompare(
3571 log, ("Level0Face" + de::toString(faceNdx)).c_str(), (string("Level 0, face ") + s_faceNames[face]).c_str(),
3572 level0Reference.getLevelFace(0, face), resultTexture.getLevelFace(0, face), threshold,
3573 tcu::COMPARE_LOG_RESULT);
3574
3575 if (!level0Ok)
3576 {
3577 log << tcu::TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!"
3578 << tcu::TestLog::EndMessage;
3579 result = QP_TEST_RESULT_FAIL;
3580 }
3581 }
3582
3583 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3584 {
3585 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3586 {
3587 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3588 const char *faceName = s_faceNames[face];
3589 const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx - 1, face);
3590 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face);
3591 tcu::Surface errorMask(dst.getWidth(), dst.getHeight());
3592 bool levelOk = false;
3593
3594 // Try different comparisons in quality order.
3595
3596 if (!levelOk)
3597 {
3598 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3599 if (numFailed == 0)
3600 levelOk = true;
3601 else
3602 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName
3603 << " comparison to bilinear method failed, found " << numFailed << " invalid pixels."
3604 << tcu::TestLog::EndMessage;
3605 }
3606
3607 if (!levelOk)
3608 {
3609 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3610 if (numFailed == 0)
3611 levelOk = true;
3612 else
3613 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName
3614 << " comparison to box method failed, found " << numFailed << " invalid pixels."
3615 << tcu::TestLog::EndMessage;
3616 }
3617
3618 // At this point all high-quality methods have been used.
3619 if (!levelOk && result == QP_TEST_RESULT_PASS)
3620 result = QP_TEST_RESULT_QUALITY_WARNING;
3621
3622 if (!levelOk)
3623 {
3624 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3625 if (numFailed == 0)
3626 levelOk = true;
3627 else
3628 log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName
3629 << " appears to contain " << numFailed << " completely wrong pixels, failing case!"
3630 << tcu::TestLog::EndMessage;
3631 }
3632
3633 if (!levelOk)
3634 result = QP_TEST_RESULT_FAIL;
3635
3636 log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx),
3637 string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) +
3638 " result")
3639 << tcu::TestLog::Image("Result", "Result", dst);
3640
3641 if (!levelOk)
3642 log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
3643
3644 log << tcu::TestLog::EndImageSet;
3645 }
3646 }
3647
3648 return result;
3649 }
3650
3651 // Logging utilities.
3652
operator <<(std::ostream & str,const LogGradientFmt & fmt)3653 std::ostream &operator<<(std::ostream &str, const LogGradientFmt &fmt)
3654 {
3655 return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
3656 << "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
3657 << "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
3658 << "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3659 }
3660
3661 } // namespace TextureTestUtil
3662 } // namespace glu
3663