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