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)103 static tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLevel, int maxLevel)
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)111 static tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLevel, int maxLevel)
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);
117 }
118
getSubView(const tcu::TextureCubeView & view,int baseLevel,int maxLevel)119 static tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int baseLevel, int maxLevel)
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);
130 }
131
getSubView(const tcu::Texture3DView & view,int baseLevel,int maxLevel)132 static tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLevel, int maxLevel)
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);
138 }
139
getSubView(const tcu::TextureCubeArrayView & view,int baseLevel,int maxLevel)140 static tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel)
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 inline 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 inline 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 static 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 static 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 static 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
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture2DView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const ReferenceParams & params)427 static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
428 {
429 // Separate combined DS formats
430 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
431 const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
432
433 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
434
435 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
436 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
437
438 // Coordinates and lod per triangle.
439 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
440 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
441 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
442 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
443
444 for (int y = 0; y < dst.getHeight(); y++)
445 {
446 for (int x = 0; x < dst.getWidth(); x++)
447 {
448 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
449 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
450
451 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
452 float triX = triNdx ? 1.0f-xf : xf;
453 float triY = triNdx ? 1.0f-yf : yf;
454
455 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
456 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
457 float lod = triLod[triNdx];
458
459 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
460 }
461 }
462 }
463
sampleTextureProjected(const tcu::SurfaceAccess & dst,const tcu::Texture1DView & rawSrc,const tcu::Vec4 & sq,const ReferenceParams & params)464 static void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
465 {
466 // Separate combined DS formats
467 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
468 const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
469
470 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
471 float dstW = (float)dst.getWidth();
472 float dstH = (float)dst.getHeight();
473
474 tcu::Vec4 uq = sq * (float)src.getWidth();
475
476 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
477 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
478 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
479
480 for (int py = 0; py < dst.getHeight(); py++)
481 {
482 for (int px = 0; px < dst.getWidth(); px++)
483 {
484 float wx = (float)px + 0.5f;
485 float wy = (float)py + 0.5f;
486 float nx = wx / dstW;
487 float ny = wy / dstH;
488
489 int triNdx = nx + ny >= 1.0f ? 1 : 0;
490 float triWx = triNdx ? dstW - wx : wx;
491 float triWy = triNdx ? dstH - wy : wy;
492 float triNx = triNdx ? 1.0f - nx : nx;
493 float triNy = triNdx ? 1.0f - ny : ny;
494
495 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
496 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
497 + lodBias;
498
499 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
500 }
501 }
502 }
503
sampleTextureProjected(const tcu::SurfaceAccess & dst,const tcu::Texture2DView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const ReferenceParams & params)504 static void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
505 {
506 // Separate combined DS formats
507 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
508 const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
509
510 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
511 float dstW = (float)dst.getWidth();
512 float dstH = (float)dst.getHeight();
513
514 tcu::Vec4 uq = sq * (float)src.getWidth();
515 tcu::Vec4 vq = tq * (float)src.getHeight();
516
517 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
518 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
519 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
520 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
521 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
522
523 for (int py = 0; py < dst.getHeight(); py++)
524 {
525 for (int px = 0; px < dst.getWidth(); px++)
526 {
527 float wx = (float)px + 0.5f;
528 float wy = (float)py + 0.5f;
529 float nx = wx / dstW;
530 float ny = wy / dstH;
531
532 int triNdx = nx + ny >= 1.0f ? 1 : 0;
533 float triWx = triNdx ? dstW - wx : wx;
534 float triWy = triNdx ? dstH - wy : wy;
535 float triNx = triNdx ? 1.0f - nx : nx;
536 float triNy = triNdx ? 1.0f - ny : ny;
537
538 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
539 float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
540 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
541 + lodBias;
542
543 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
544 }
545 }
546 }
547
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture2DView & src,const float * texCoord,const ReferenceParams & params)548 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
549 {
550 const tcu::Texture2DView view = getSubView(src, params.baseLevel, params.maxLevel);
551 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
552 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
553
554 if (params.flags & ReferenceParams::PROJECTED)
555 sampleTextureProjected(dst, view, sq, tq, params);
556 else
557 sampleTextureNonProjected(dst, view, sq, tq, params);
558 }
559
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture1DView & src,const float * texCoord,const ReferenceParams & params)560 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params)
561 {
562 const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel);
563 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
564
565 if (params.flags & ReferenceParams::PROJECTED)
566 sampleTextureProjected(dst, view, sq, params);
567 else
568 sampleTextureNonProjected(dst, view, sq, params);
569 }
570
computeCubeLodFromDerivates(LodMode lodMode,const tcu::Vec3 & coord,const tcu::Vec3 & coordDx,const tcu::Vec3 & coordDy,const int faceSize)571 static float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize)
572 {
573 const tcu::CubeFace face = tcu::selectCubeFace(coord);
574 int maNdx = 0;
575 int sNdx = 0;
576 int tNdx = 0;
577
578 // \note Derivate signs don't matter when computing lod
579 switch (face)
580 {
581 case tcu::CUBEFACE_NEGATIVE_X:
582 case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
583 case tcu::CUBEFACE_NEGATIVE_Y:
584 case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
585 case tcu::CUBEFACE_NEGATIVE_Z:
586 case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
587 default:
588 DE_ASSERT(DE_FALSE);
589 }
590
591 {
592 const float sc = coord[sNdx];
593 const float tc = coord[tNdx];
594 const float ma = de::abs(coord[maNdx]);
595 const float scdx = coordDx[sNdx];
596 const float tcdx = coordDx[tNdx];
597 const float madx = de::abs(coordDx[maNdx]);
598 const float scdy = coordDy[sNdx];
599 const float tcdy = coordDy[tNdx];
600 const float mady = de::abs(coordDy[maNdx]);
601 const float dudx = float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma);
602 const float dvdx = float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma);
603 const float dudy = float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma);
604 const float dvdy = float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma);
605
606 return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
607 }
608 }
609
sampleTextureCube(const tcu::SurfaceAccess & dst,const tcu::TextureCubeView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const ReferenceParams & params)610 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)
611 {
612 // Separate combined DS formats
613 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
614 const tcu::TextureCubeView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
615
616 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
617 const float dstW = float(dstSize.x());
618 const float dstH = float(dstSize.y());
619 const int srcSize = src.getSize();
620
621 // Coordinates per triangle.
622 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
623 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
624 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
625 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
626
627 const float lodBias ((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
628
629 for (int py = 0; py < dst.getHeight(); py++)
630 {
631 for (int px = 0; px < dst.getWidth(); px++)
632 {
633 const float wx = (float)px + 0.5f;
634 const float wy = (float)py + 0.5f;
635 const float nx = wx / dstW;
636 const float ny = wy / dstH;
637
638 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
639 const float triNx = triNdx ? 1.0f - nx : nx;
640 const float triNy = triNdx ? 1.0f - ny : ny;
641
642 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
643 triangleInterpolate(triT[triNdx], triNx, triNy),
644 triangleInterpolate(triR[triNdx], triNx, triNy));
645 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
646 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
647 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
648 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
649 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
650 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
651
652 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod);
653
654 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py);
655 }
656 }
657 }
658
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::TextureCubeView & src,const float * texCoord,const ReferenceParams & params)659 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
660 {
661 const tcu::TextureCubeView view = getSubView(src, params.baseLevel, params.maxLevel);
662 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
663 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
664 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
665
666 return sampleTextureCube(dst, view, sq, tq, rq, params);
667 }
668
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture2DArrayView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const ReferenceParams & params)669 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)
670 {
671 // Separate combined DS formats
672 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
673 const tcu::Texture2DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
674
675 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
676
677 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
678 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
679
680 // Coordinates and lod per triangle.
681 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
682 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
683 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
684 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
685 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
686
687 for (int y = 0; y < dst.getHeight(); y++)
688 {
689 for (int x = 0; x < dst.getWidth(); x++)
690 {
691 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
692 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
693
694 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
695 float triX = triNdx ? 1.0f-xf : xf;
696 float triY = triNdx ? 1.0f-yf : yf;
697
698 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
699 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
700 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
701 float lod = triLod[triNdx];
702
703 dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
704 }
705 }
706 }
707
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture2DArrayView & src,const float * texCoord,const ReferenceParams & params)708 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params)
709 {
710 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
711 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
712 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
713
714 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
715 sampleTextureNonProjected(dst, src, sq, tq, rq, params);
716 }
717
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture1DArrayView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const ReferenceParams & params)718 static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
719 {
720 // Separate combined DS formats
721 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
722 const tcu::Texture1DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
723
724 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
725
726 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
727 deInt32 srcSize = src.getWidth();
728
729 // Coordinates and lod per triangle.
730 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
731 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
732 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
733 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
734
735 for (int y = 0; y < dst.getHeight(); y++)
736 {
737 for (int x = 0; x < dst.getWidth(); x++)
738 {
739 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
740 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
741
742 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
743 float triX = triNdx ? 1.0f-xf : xf;
744 float triY = triNdx ? 1.0f-yf : yf;
745
746 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
747 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
748 float lod = triLod[triNdx];
749
750 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
751 }
752 }
753 }
754
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture1DArrayView & src,const float * texCoord,const ReferenceParams & params)755 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params)
756 {
757 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
758 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
759
760 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
761 sampleTextureNonProjected(dst, src, sq, tq, params);
762 }
763
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture3DView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const ReferenceParams & params)764 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)
765 {
766 // Separate combined DS formats
767 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
768 const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
769
770 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
771
772 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
773 tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
774
775 // Coordinates and lod per triangle.
776 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
777 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
778 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
779 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod),
780 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) };
781
782 for (int y = 0; y < dst.getHeight(); y++)
783 {
784 for (int x = 0; x < dst.getWidth(); x++)
785 {
786 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
787 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
788
789 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
790 float triX = triNdx ? 1.0f-xf : xf;
791 float triY = triNdx ? 1.0f-yf : yf;
792
793 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
794 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
795 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
796 float lod = triLod[triNdx];
797
798 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
799 }
800 }
801 }
802
sampleTextureProjected(const tcu::SurfaceAccess & dst,const tcu::Texture3DView & rawSrc,const tcu::Vec4 & sq,const tcu::Vec4 & tq,const tcu::Vec4 & rq,const ReferenceParams & params)803 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)
804 {
805 // Separate combined DS formats
806 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
807 const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
808
809 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
810 float dstW = (float)dst.getWidth();
811 float dstH = (float)dst.getHeight();
812
813 tcu::Vec4 uq = sq * (float)src.getWidth();
814 tcu::Vec4 vq = tq * (float)src.getHeight();
815 tcu::Vec4 wq = rq * (float)src.getDepth();
816
817 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
818 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
819 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
820 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
821 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
822 tcu::Vec3 triW[2] = { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) };
823 tcu::Vec3 triP[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
824
825 for (int py = 0; py < dst.getHeight(); py++)
826 {
827 for (int px = 0; px < dst.getWidth(); px++)
828 {
829 float wx = (float)px + 0.5f;
830 float wy = (float)py + 0.5f;
831 float nx = wx / dstW;
832 float ny = wy / dstH;
833
834 int triNdx = nx + ny >= 1.0f ? 1 : 0;
835 float triWx = triNdx ? dstW - wx : wx;
836 float triWy = triNdx ? dstH - wy : wy;
837 float triNx = triNdx ? 1.0f - nx : nx;
838 float triNy = triNdx ? 1.0f - ny : ny;
839
840 float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
841 float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
842 float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
843 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
844 + lodBias;
845
846 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
847 }
848 }
849 }
850
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::Texture3DView & src,const float * texCoord,const ReferenceParams & params)851 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params)
852 {
853 const tcu::Texture3DView view = getSubView(src, params.baseLevel, params.maxLevel);
854 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
855 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
856 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
857
858 if (params.flags & ReferenceParams::PROJECTED)
859 sampleTextureProjected(dst, view, sq, tq, rq, params);
860 else
861 sampleTextureNonProjected(dst, view, sq, tq, rq, params);
862 }
863
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)864 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)
865 {
866 // Separate combined DS formats
867 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
868 const tcu::TextureCubeArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
869
870 const float dstW = (float)dst.getWidth();
871 const float dstH = (float)dst.getHeight();
872
873 // Coordinates per triangle.
874 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
875 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
876 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
877 tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
878 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
879
880 const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
881
882 for (int py = 0; py < dst.getHeight(); py++)
883 {
884 for (int px = 0; px < dst.getWidth(); px++)
885 {
886 const float wx = (float)px + 0.5f;
887 const float wy = (float)py + 0.5f;
888 const float nx = wx / dstW;
889 const float ny = wy / dstH;
890
891 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
892 const float triNx = triNdx ? 1.0f - nx : nx;
893 const float triNy = triNdx ? 1.0f - ny : ny;
894
895 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
896 triangleInterpolate(triT[triNdx], triNx, triNy),
897 triangleInterpolate(triR[triNdx], triNx, triNy));
898
899 const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy);
900
901 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
902 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
903 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
904 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
905 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
906 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
907
908 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
909
910 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
911 }
912 }
913 }
914
sampleTexture(const tcu::SurfaceAccess & dst,const tcu::TextureCubeArrayView & src,const float * texCoord,const ReferenceParams & params)915 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params)
916 {
917 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
918 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
919 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
920 tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
921
922 sampleTextureCubeArray(dst, src, sq, tq, rq, qq, params);
923 }
924
fetchTexture(const tcu::SurfaceAccess & dst,const tcu::ConstPixelBufferAccess & src,const float * texCoord,const tcu::Vec4 & colorScale,const tcu::Vec4 & colorBias)925 void fetchTexture (const tcu::SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias)
926 {
927 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
928 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
929
930 for (int y = 0; y < dst.getHeight(); y++)
931 {
932 for (int x = 0; x < dst.getWidth(); x++)
933 {
934 const float yf = ((float)y + 0.5f) / (float)dst.getHeight();
935 const float xf = ((float)x + 0.5f) / (float)dst.getWidth();
936
937 const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
938 const float triX = triNdx ? 1.0f-xf : xf;
939 const float triY = triNdx ? 1.0f-yf : yf;
940
941 const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
942
943 dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
944 }
945 }
946 }
947
compareImages(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & rendered,tcu::RGBA threshold)948 bool compareImages (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
949 {
950 return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
951 }
952
compareImages(tcu::TestLog & log,const char * name,const char * desc,const tcu::Surface & reference,const tcu::Surface & rendered,tcu::RGBA threshold)953 bool compareImages (tcu::TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
954 {
955 return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
956 }
957
measureAccuracy(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & rendered,int bestScoreDiff,int worstScoreDiff)958 int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
959 {
960 return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
961 }
962
rangeDiff(int x,int a,int b)963 inline int rangeDiff (int x, int a, int b)
964 {
965 if (x < a)
966 return a-x;
967 else if (x > b)
968 return x-b;
969 else
970 return 0;
971 }
972
rangeDiff(tcu::RGBA p,tcu::RGBA a,tcu::RGBA b)973 inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
974 {
975 int rMin = de::min(a.getRed(), b.getRed());
976 int rMax = de::max(a.getRed(), b.getRed());
977 int gMin = de::min(a.getGreen(), b.getGreen());
978 int gMax = de::max(a.getGreen(), b.getGreen());
979 int bMin = de::min(a.getBlue(), b.getBlue());
980 int bMax = de::max(a.getBlue(), b.getBlue());
981 int aMin = de::min(a.getAlpha(), b.getAlpha());
982 int aMax = de::max(a.getAlpha(), b.getAlpha());
983
984 return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax),
985 rangeDiff(p.getGreen(), gMin, gMax),
986 rangeDiff(p.getBlue(), bMin, bMax),
987 rangeDiff(p.getAlpha(), aMin, aMax));
988 }
989
rangeCompare(tcu::RGBA p,tcu::RGBA a,tcu::RGBA b,tcu::RGBA threshold)990 inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
991 {
992 tcu::RGBA diff = rangeDiff(p, a, b);
993 return diff.getRed() <= threshold.getRed() &&
994 diff.getGreen() <= threshold.getGreen() &&
995 diff.getBlue() <= threshold.getBlue() &&
996 diff.getAlpha() <= threshold.getAlpha();
997 }
998
computeQuadTexCoord1D(std::vector<float> & dst,float left,float right)999 void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
1000 {
1001 dst.resize(4);
1002
1003 dst[0] = left;
1004 dst[1] = left;
1005 dst[2] = right;
1006 dst[3] = right;
1007 }
1008
computeQuadTexCoord1DArray(std::vector<float> & dst,int layerNdx,float left,float right)1009 void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
1010 {
1011 dst.resize(4*2);
1012
1013 dst[0] = left; dst[1] = (float)layerNdx;
1014 dst[2] = left; dst[3] = (float)layerNdx;
1015 dst[4] = right; dst[5] = (float)layerNdx;
1016 dst[6] = right; dst[7] = (float)layerNdx;
1017 }
1018
computeQuadTexCoord2D(std::vector<float> & dst,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight)1019 void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1020 {
1021 dst.resize(4*2);
1022
1023 dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y();
1024 dst[2] = bottomLeft.x(); dst[3] = topRight.y();
1025 dst[4] = topRight.x(); dst[5] = bottomLeft.y();
1026 dst[6] = topRight.x(); dst[7] = topRight.y();
1027 }
1028
computeQuadTexCoord2DArray(std::vector<float> & dst,int layerNdx,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight)1029 void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1030 {
1031 dst.resize(4*3);
1032
1033 dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx;
1034 dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx;
1035 dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx;
1036 dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx;
1037 }
1038
computeQuadTexCoord3D(std::vector<float> & dst,const tcu::Vec3 & p0,const tcu::Vec3 & p1,const tcu::IVec3 & dirSwz)1039 void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
1040 {
1041 tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1042 tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1043 tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1044 tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1045
1046 tcu::Vec3 v0 = p0 + (p1-p0)*f0;
1047 tcu::Vec3 v1 = p0 + (p1-p0)*f1;
1048 tcu::Vec3 v2 = p0 + (p1-p0)*f2;
1049 tcu::Vec3 v3 = p0 + (p1-p0)*f3;
1050
1051 dst.resize(4*3);
1052
1053 dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
1054 dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
1055 dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
1056 dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
1057 }
1058
computeQuadTexCoordCube(std::vector<float> & dst,tcu::CubeFace face)1059 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
1060 {
1061 static const float texCoordNegX[] =
1062 {
1063 -1.0f, 1.0f, -1.0f,
1064 -1.0f, -1.0f, -1.0f,
1065 -1.0f, 1.0f, 1.0f,
1066 -1.0f, -1.0f, 1.0f
1067 };
1068 static const float texCoordPosX[] =
1069 {
1070 +1.0f, 1.0f, 1.0f,
1071 +1.0f, -1.0f, 1.0f,
1072 +1.0f, 1.0f, -1.0f,
1073 +1.0f, -1.0f, -1.0f
1074 };
1075 static const float texCoordNegY[] =
1076 {
1077 -1.0f, -1.0f, 1.0f,
1078 -1.0f, -1.0f, -1.0f,
1079 1.0f, -1.0f, 1.0f,
1080 1.0f, -1.0f, -1.0f
1081 };
1082 static const float texCoordPosY[] =
1083 {
1084 -1.0f, +1.0f, -1.0f,
1085 -1.0f, +1.0f, 1.0f,
1086 1.0f, +1.0f, -1.0f,
1087 1.0f, +1.0f, 1.0f
1088 };
1089 static const float texCoordNegZ[] =
1090 {
1091 1.0f, 1.0f, -1.0f,
1092 1.0f, -1.0f, -1.0f,
1093 -1.0f, 1.0f, -1.0f,
1094 -1.0f, -1.0f, -1.0f
1095 };
1096 static const float texCoordPosZ[] =
1097 {
1098 -1.0f, 1.0f, +1.0f,
1099 -1.0f, -1.0f, +1.0f,
1100 1.0f, 1.0f, +1.0f,
1101 1.0f, -1.0f, +1.0f
1102 };
1103
1104 const float* texCoord = DE_NULL;
1105 int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX);
1106
1107 switch (face)
1108 {
1109 case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
1110 case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
1111 case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
1112 case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
1113 case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
1114 case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
1115 default:
1116 DE_ASSERT(DE_FALSE);
1117 return;
1118 }
1119
1120 dst.resize(texCoordSize);
1121 std::copy(texCoord, texCoord+texCoordSize, dst.begin());
1122 }
1123
computeQuadTexCoordCube(std::vector<float> & dst,tcu::CubeFace face,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight)1124 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1125 {
1126 int sRow = 0;
1127 int tRow = 0;
1128 int mRow = 0;
1129 float sSign = 1.0f;
1130 float tSign = 1.0f;
1131 float mSign = 1.0f;
1132
1133 switch (face)
1134 {
1135 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1136 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1137 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1138 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1139 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1140 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1141 default:
1142 DE_ASSERT(DE_FALSE);
1143 return;
1144 }
1145
1146 dst.resize(3*4);
1147
1148 dst[0+mRow] = mSign;
1149 dst[3+mRow] = mSign;
1150 dst[6+mRow] = mSign;
1151 dst[9+mRow] = mSign;
1152
1153 dst[0+sRow] = sSign * bottomLeft.x();
1154 dst[3+sRow] = sSign * bottomLeft.x();
1155 dst[6+sRow] = sSign * topRight.x();
1156 dst[9+sRow] = sSign * topRight.x();
1157
1158 dst[0+tRow] = tSign * bottomLeft.y();
1159 dst[3+tRow] = tSign * topRight.y();
1160 dst[6+tRow] = tSign * bottomLeft.y();
1161 dst[9+tRow] = tSign * topRight.y();
1162 }
1163
computeQuadTexCoordCubeArray(std::vector<float> & dst,tcu::CubeFace face,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight,const tcu::Vec2 & layerRange)1164 void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
1165 {
1166 int sRow = 0;
1167 int tRow = 0;
1168 int mRow = 0;
1169 const int qRow = 3;
1170 float sSign = 1.0f;
1171 float tSign = 1.0f;
1172 float mSign = 1.0f;
1173 const float l0 = layerRange.x();
1174 const float l1 = layerRange.y();
1175
1176 switch (face)
1177 {
1178 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1179 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1180 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1181 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1182 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1183 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1184 default:
1185 DE_ASSERT(DE_FALSE);
1186 return;
1187 }
1188
1189 dst.resize(4*4);
1190
1191 dst[ 0+mRow] = mSign;
1192 dst[ 4+mRow] = mSign;
1193 dst[ 8+mRow] = mSign;
1194 dst[12+mRow] = mSign;
1195
1196 dst[ 0+sRow] = sSign * bottomLeft.x();
1197 dst[ 4+sRow] = sSign * bottomLeft.x();
1198 dst[ 8+sRow] = sSign * topRight.x();
1199 dst[12+sRow] = sSign * topRight.x();
1200
1201 dst[ 0+tRow] = tSign * bottomLeft.y();
1202 dst[ 4+tRow] = tSign * topRight.y();
1203 dst[ 8+tRow] = tSign * bottomLeft.y();
1204 dst[12+tRow] = tSign * topRight.y();
1205
1206 if (l0 != l1)
1207 {
1208 dst[ 0+qRow] = l0;
1209 dst[ 4+qRow] = l0*0.5f + l1*0.5f;
1210 dst[ 8+qRow] = l0*0.5f + l1*0.5f;
1211 dst[12+qRow] = l1;
1212 }
1213 else
1214 {
1215 dst[ 0+qRow] = l0;
1216 dst[ 4+qRow] = l0;
1217 dst[ 8+qRow] = l0;
1218 dst[12+qRow] = l0;
1219 }
1220 }
1221
1222 // Texture result verification
1223
1224 //! 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)1225 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1226 const tcu::ConstPixelBufferAccess& reference,
1227 const tcu::PixelBufferAccess& errorMask,
1228 const tcu::Texture1DView& baseView,
1229 const float* texCoord,
1230 const ReferenceParams& sampleParams,
1231 const tcu::LookupPrecision& lookupPrec,
1232 const tcu::LodPrecision& lodPrec,
1233 qpWatchDog* watchDog)
1234 {
1235 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1236 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1237
1238 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1239 const tcu::Texture1DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1240
1241 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1242
1243 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1244 const float dstW = float(dstSize.x());
1245 const float dstH = float(dstSize.y());
1246 const int srcSize = src.getWidth();
1247
1248 // Coordinates and lod per triangle.
1249 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1250 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1251
1252 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1253
1254 int numFailed = 0;
1255
1256 const tcu::Vec2 lodOffsets[] =
1257 {
1258 tcu::Vec2(-1, 0),
1259 tcu::Vec2(+1, 0),
1260 tcu::Vec2( 0, -1),
1261 tcu::Vec2( 0, +1),
1262 };
1263
1264 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1265
1266 for (int py = 0; py < result.getHeight(); py++)
1267 {
1268 // Ugly hack, validation can take way too long at the moment.
1269 if (watchDog)
1270 qpWatchDog_touch(watchDog);
1271
1272 for (int px = 0; px < result.getWidth(); px++)
1273 {
1274 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1275 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1276
1277 // Try comparison to ideal reference first, and if that fails use slower verificator.
1278 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1279 {
1280 const float wx = (float)px + 0.5f;
1281 const float wy = (float)py + 0.5f;
1282 const float nx = wx / dstW;
1283 const float ny = wy / dstH;
1284
1285 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1286 const float triWx = triNdx ? dstW - wx : wx;
1287 const float triWy = triNdx ? dstH - wy : wy;
1288 const float triNx = triNdx ? 1.0f - nx : nx;
1289 const float triNy = triNdx ? 1.0f - ny : ny;
1290
1291 const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1292 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1293 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1294
1295 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1296
1297 // Compute lod bounds across lodOffsets range.
1298 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1299 {
1300 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1301 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1302 const float nxo = wxo/dstW;
1303 const float nyo = wyo/dstH;
1304
1305 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1306 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1307 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1308
1309 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1310 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1311 }
1312
1313 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1314 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1315
1316 if (!isOk)
1317 {
1318 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1319 numFailed += 1;
1320 }
1321 }
1322 }
1323 }
1324
1325 return numFailed;
1326 }
1327
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)1328 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1329 const tcu::ConstPixelBufferAccess& reference,
1330 const tcu::PixelBufferAccess& errorMask,
1331 const tcu::Texture2DView& baseView,
1332 const float* texCoord,
1333 const ReferenceParams& sampleParams,
1334 const tcu::LookupPrecision& lookupPrec,
1335 const tcu::LodPrecision& lodPrec,
1336 qpWatchDog* watchDog)
1337 {
1338 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1339 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1340
1341 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1342 const tcu::Texture2DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1343
1344 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1345 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1346
1347 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1348 const float dstW = float(dstSize.x());
1349 const float dstH = float(dstSize.y());
1350 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
1351
1352 // Coordinates and lod per triangle.
1353 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1354 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1355 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1356
1357 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1358
1359 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1360
1361 int numFailed = 0;
1362
1363 const tcu::Vec2 lodOffsets[] =
1364 {
1365 tcu::Vec2(-1, 0),
1366 tcu::Vec2(+1, 0),
1367 tcu::Vec2( 0, -1),
1368 tcu::Vec2( 0, +1),
1369 };
1370
1371 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1372
1373 for (int py = 0; py < result.getHeight(); py++)
1374 {
1375 // Ugly hack, validation can take way too long at the moment.
1376 if (watchDog)
1377 qpWatchDog_touch(watchDog);
1378
1379 for (int px = 0; px < result.getWidth(); px++)
1380 {
1381 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1382 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1383
1384 // Try comparison to ideal reference first, and if that fails use slower verificator.
1385 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1386 {
1387 const float wx = (float)px + 0.5f;
1388 const float wy = (float)py + 0.5f;
1389 const float nx = wx / dstW;
1390 const float ny = wy / dstH;
1391
1392 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1393 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1394
1395 bool isOk = false;
1396
1397 DE_ASSERT(tri0 || tri1);
1398
1399 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1400 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1401 {
1402 const float triWx = triNdx ? dstW - wx : wx;
1403 const float triWy = triNdx ? dstH - wy : wy;
1404 const float triNx = triNdx ? 1.0f - nx : nx;
1405 const float triNy = triNdx ? 1.0f - ny : ny;
1406
1407 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1408 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1409 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1410 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1411 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1412 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1413
1414 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1415
1416 // Compute lod bounds across lodOffsets range.
1417 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1418 {
1419 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1420 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1421 const float nxo = wxo/dstW;
1422 const float nyo = wyo/dstH;
1423
1424 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1425 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1426 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1427 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1428 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1429
1430 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1431 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1432 }
1433
1434 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1435 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1436 {
1437 isOk = true;
1438 break;
1439 }
1440 }
1441
1442 if (!isOk)
1443 {
1444 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1445 numFailed += 1;
1446 }
1447 }
1448 }
1449 }
1450
1451 return numFailed;
1452 }
1453
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)1454 bool verifyTextureResult (tcu::TestContext& testCtx,
1455 const tcu::ConstPixelBufferAccess& result,
1456 const tcu::Texture1DView& src,
1457 const float* texCoord,
1458 const ReferenceParams& sampleParams,
1459 const tcu::LookupPrecision& lookupPrec,
1460 const tcu::LodPrecision& lodPrec,
1461 const tcu::PixelFormat& pixelFormat)
1462 {
1463 tcu::TestLog& log = testCtx.getLog();
1464 tcu::Surface reference (result.getWidth(), result.getHeight());
1465 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1466 int numFailedPixels;
1467
1468 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1469
1470 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1471 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1472
1473 if (numFailedPixels > 0)
1474 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1475
1476 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1477 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1478
1479 if (numFailedPixels > 0)
1480 {
1481 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1482 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1483 }
1484
1485 log << tcu::TestLog::EndImageSet;
1486
1487 return numFailedPixels == 0;
1488 }
1489
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)1490 bool verifyTextureResult (tcu::TestContext& testCtx,
1491 const tcu::ConstPixelBufferAccess& result,
1492 const tcu::Texture2DView& src,
1493 const float* texCoord,
1494 const ReferenceParams& sampleParams,
1495 const tcu::LookupPrecision& lookupPrec,
1496 const tcu::LodPrecision& lodPrec,
1497 const tcu::PixelFormat& pixelFormat)
1498 {
1499 tcu::TestLog& log = testCtx.getLog();
1500 tcu::Surface reference (result.getWidth(), result.getHeight());
1501 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1502 int numFailedPixels;
1503
1504 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1505
1506 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1507 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1508
1509 if (numFailedPixels > 0)
1510 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1511
1512 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1513 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1514
1515 if (numFailedPixels > 0)
1516 {
1517 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1518 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1519 }
1520
1521 log << tcu::TestLog::EndImageSet;
1522
1523 return numFailedPixels == 0;
1524 }
1525
1526 //! 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)1527 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1528 const tcu::ConstPixelBufferAccess& reference,
1529 const tcu::PixelBufferAccess& errorMask,
1530 const tcu::TextureCubeView& baseView,
1531 const float* texCoord,
1532 const ReferenceParams& sampleParams,
1533 const tcu::LookupPrecision& lookupPrec,
1534 const tcu::LodPrecision& lodPrec,
1535 qpWatchDog* watchDog)
1536 {
1537 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1538 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1539
1540 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1541 const tcu::TextureCubeView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1542
1543 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1544 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1545 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1546
1547 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1548 const float dstW = float(dstSize.x());
1549 const float dstH = float(dstSize.y());
1550 const int srcSize = src.getSize();
1551
1552 // Coordinates per triangle.
1553 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1554 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1555 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1556 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1557
1558 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1559
1560 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1561
1562 int numFailed = 0;
1563
1564 const tcu::Vec2 lodOffsets[] =
1565 {
1566 tcu::Vec2(-1, 0),
1567 tcu::Vec2(+1, 0),
1568 tcu::Vec2( 0, -1),
1569 tcu::Vec2( 0, +1),
1570
1571 // \note Not strictly allowed by spec, but implementations do this in practice.
1572 tcu::Vec2(-1, -1),
1573 tcu::Vec2(-1, +1),
1574 tcu::Vec2(+1, -1),
1575 tcu::Vec2(+1, +1),
1576 };
1577
1578 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1579
1580 for (int py = 0; py < result.getHeight(); py++)
1581 {
1582 // Ugly hack, validation can take way too long at the moment.
1583 if (watchDog)
1584 qpWatchDog_touch(watchDog);
1585
1586 for (int px = 0; px < result.getWidth(); px++)
1587 {
1588 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1589 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1590
1591 // Try comparison to ideal reference first, and if that fails use slower verificator.
1592 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1593 {
1594 const float wx = (float)px + 0.5f;
1595 const float wy = (float)py + 0.5f;
1596 const float nx = wx / dstW;
1597 const float ny = wy / dstH;
1598
1599 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1600 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1601
1602 bool isOk = false;
1603
1604 DE_ASSERT(tri0 || tri1);
1605
1606 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1607 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1608 {
1609 const float triWx = triNdx ? dstW - wx : wx;
1610 const float triWy = triNdx ? dstH - wy : wy;
1611 const float triNx = triNdx ? 1.0f - nx : nx;
1612 const float triNy = triNdx ? 1.0f - ny : ny;
1613
1614 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1615 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1616 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1617 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1618 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1619 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
1620 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1621 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1622 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
1623
1624 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
1625
1626 // Compute lod bounds across lodOffsets range.
1627 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1628 {
1629 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1630 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1631 const float nxo = wxo/dstW;
1632 const float nyo = wyo/dstH;
1633
1634 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
1635 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
1636 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
1637 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1638 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1639 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
1640 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1641 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1642 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
1643 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
1644
1645 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1646 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1647 }
1648
1649 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1650
1651 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1652 {
1653 isOk = true;
1654 break;
1655 }
1656 }
1657
1658 if (!isOk)
1659 {
1660 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1661 numFailed += 1;
1662 }
1663 }
1664 }
1665 }
1666
1667 return numFailed;
1668 }
1669
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)1670 bool verifyTextureResult (tcu::TestContext& testCtx,
1671 const tcu::ConstPixelBufferAccess& result,
1672 const tcu::TextureCubeView& src,
1673 const float* texCoord,
1674 const ReferenceParams& sampleParams,
1675 const tcu::LookupPrecision& lookupPrec,
1676 const tcu::LodPrecision& lodPrec,
1677 const tcu::PixelFormat& pixelFormat)
1678 {
1679 tcu::TestLog& log = testCtx.getLog();
1680 tcu::Surface reference (result.getWidth(), result.getHeight());
1681 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1682 int numFailedPixels;
1683
1684 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1685
1686 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1687 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1688
1689 if (numFailedPixels > 0)
1690 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1691
1692 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1693 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1694
1695 if (numFailedPixels > 0)
1696 {
1697 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1698 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1699 }
1700
1701 log << tcu::TestLog::EndImageSet;
1702
1703 return numFailedPixels == 0;
1704 }
1705
1706 //! 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)1707 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1708 const tcu::ConstPixelBufferAccess& reference,
1709 const tcu::PixelBufferAccess& errorMask,
1710 const tcu::Texture3DView& baseView,
1711 const float* texCoord,
1712 const ReferenceParams& sampleParams,
1713 const tcu::LookupPrecision& lookupPrec,
1714 const tcu::LodPrecision& lodPrec,
1715 qpWatchDog* watchDog)
1716 {
1717 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1718 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1719
1720 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1721 const tcu::Texture3DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1722
1723 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1724 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1725 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1726
1727 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1728 const float dstW = float(dstSize.x());
1729 const float dstH = float(dstSize.y());
1730 const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
1731
1732 // Coordinates and lod per triangle.
1733 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1734 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1735 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1736 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1737
1738 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1739
1740 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1741
1742 int numFailed = 0;
1743
1744 const tcu::Vec2 lodOffsets[] =
1745 {
1746 tcu::Vec2(-1, 0),
1747 tcu::Vec2(+1, 0),
1748 tcu::Vec2( 0, -1),
1749 tcu::Vec2( 0, +1),
1750 };
1751
1752 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1753
1754 for (int py = 0; py < result.getHeight(); py++)
1755 {
1756 // Ugly hack, validation can take way too long at the moment.
1757 if (watchDog)
1758 qpWatchDog_touch(watchDog);
1759
1760 for (int px = 0; px < result.getWidth(); px++)
1761 {
1762 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1763 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1764
1765 // Try comparison to ideal reference first, and if that fails use slower verificator.
1766 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1767 {
1768 const float wx = (float)px + 0.5f;
1769 const float wy = (float)py + 0.5f;
1770 const float nx = wx / dstW;
1771 const float ny = wy / dstH;
1772
1773 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1774 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1775
1776 bool isOk = false;
1777
1778 DE_ASSERT(tri0 || tri1);
1779
1780 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1781 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1782 {
1783 const float triWx = triNdx ? dstW - wx : wx;
1784 const float triWy = triNdx ? dstH - wy : wy;
1785 const float triNx = triNdx ? 1.0f - nx : nx;
1786 const float triNy = triNdx ? 1.0f - ny : ny;
1787
1788 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1789 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1790 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1791 const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1792 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1793 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1794 const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1795 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1796 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1797
1798 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
1799
1800 // Compute lod bounds across lodOffsets range.
1801 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1802 {
1803 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1804 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1805 const float nxo = wxo/dstW;
1806 const float nyo = wyo/dstH;
1807
1808 const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1809 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1810 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1811 const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1812 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1813 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1814 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
1815
1816 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1817 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1818 }
1819
1820 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1821
1822 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1823 {
1824 isOk = true;
1825 break;
1826 }
1827 }
1828
1829 if (!isOk)
1830 {
1831 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1832 numFailed += 1;
1833 }
1834 }
1835 }
1836 }
1837
1838 return numFailed;
1839 }
1840
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)1841 bool verifyTextureResult (tcu::TestContext& testCtx,
1842 const tcu::ConstPixelBufferAccess& result,
1843 const tcu::Texture3DView& src,
1844 const float* texCoord,
1845 const ReferenceParams& sampleParams,
1846 const tcu::LookupPrecision& lookupPrec,
1847 const tcu::LodPrecision& lodPrec,
1848 const tcu::PixelFormat& pixelFormat)
1849 {
1850 tcu::TestLog& log = testCtx.getLog();
1851 tcu::Surface reference (result.getWidth(), result.getHeight());
1852 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1853 int numFailedPixels;
1854
1855 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1856
1857 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1858 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1859
1860 if (numFailedPixels > 0)
1861 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1862
1863 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1864 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1865
1866 if (numFailedPixels > 0)
1867 {
1868 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1869 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1870 }
1871
1872 log << tcu::TestLog::EndImageSet;
1873
1874 return numFailedPixels == 0;
1875 }
1876
1877 //! 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)1878 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1879 const tcu::ConstPixelBufferAccess& reference,
1880 const tcu::PixelBufferAccess& errorMask,
1881 const tcu::Texture1DArrayView& baseView,
1882 const float* texCoord,
1883 const ReferenceParams& sampleParams,
1884 const tcu::LookupPrecision& lookupPrec,
1885 const tcu::LodPrecision& lodPrec,
1886 qpWatchDog* watchDog)
1887 {
1888 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1889 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1890
1891 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1892 const tcu::Texture1DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
1893
1894 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1895 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1896
1897 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1898 const float dstW = float(dstSize.x());
1899 const float dstH = float(dstSize.y());
1900 const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored.
1901
1902 // Coordinates and lod per triangle.
1903 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1904 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1905 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1906
1907 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1908
1909 int numFailed = 0;
1910
1911 const tcu::Vec2 lodOffsets[] =
1912 {
1913 tcu::Vec2(-1, 0),
1914 tcu::Vec2(+1, 0),
1915 tcu::Vec2( 0, -1),
1916 tcu::Vec2( 0, +1),
1917 };
1918
1919 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1920
1921 for (int py = 0; py < result.getHeight(); py++)
1922 {
1923 // Ugly hack, validation can take way too long at the moment.
1924 if (watchDog)
1925 qpWatchDog_touch(watchDog);
1926
1927 for (int px = 0; px < result.getWidth(); px++)
1928 {
1929 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1930 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1931
1932 // Try comparison to ideal reference first, and if that fails use slower verificator.
1933 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1934 {
1935 const float wx = (float)px + 0.5f;
1936 const float wy = (float)py + 0.5f;
1937 const float nx = wx / dstW;
1938 const float ny = wy / dstH;
1939
1940 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1941 const float triWx = triNdx ? dstW - wx : wx;
1942 const float triWy = triNdx ? dstH - wy : wy;
1943 const float triNx = triNdx ? 1.0f - nx : nx;
1944 const float triNy = triNdx ? 1.0f - ny : ny;
1945
1946 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1947 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1948 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
1949 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
1950
1951 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1952
1953 // Compute lod bounds across lodOffsets range.
1954 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1955 {
1956 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1957 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1958 const float nxo = wxo/dstW;
1959 const float nyo = wyo/dstH;
1960
1961 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
1962 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
1963 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1964
1965 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1966 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1967 }
1968
1969 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1970 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1971
1972 if (!isOk)
1973 {
1974 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1975 numFailed += 1;
1976 }
1977 }
1978 }
1979 }
1980
1981 return numFailed;
1982 }
1983
1984 //! 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)1985 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1986 const tcu::ConstPixelBufferAccess& reference,
1987 const tcu::PixelBufferAccess& errorMask,
1988 const tcu::Texture2DArrayView& baseView,
1989 const float* texCoord,
1990 const ReferenceParams& sampleParams,
1991 const tcu::LookupPrecision& lookupPrec,
1992 const tcu::LodPrecision& lodPrec,
1993 qpWatchDog* watchDog)
1994 {
1995 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1996 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1997
1998 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1999 const tcu::Texture2DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
2000
2001 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2002 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2003 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2004
2005 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2006 const float dstW = float(dstSize.x());
2007 const float dstH = float(dstSize.y());
2008 const tcu::Vec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2009
2010 // Coordinates and lod per triangle.
2011 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2012 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2013 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2014 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2015
2016 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2017
2018 int numFailed = 0;
2019
2020 const tcu::Vec2 lodOffsets[] =
2021 {
2022 tcu::Vec2(-1, 0),
2023 tcu::Vec2(+1, 0),
2024 tcu::Vec2( 0, -1),
2025 tcu::Vec2( 0, +1),
2026 };
2027
2028 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2029
2030 for (int py = 0; py < result.getHeight(); py++)
2031 {
2032 // Ugly hack, validation can take way too long at the moment.
2033 if (watchDog)
2034 qpWatchDog_touch(watchDog);
2035
2036 for (int px = 0; px < result.getWidth(); px++)
2037 {
2038 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2039 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2040
2041 // Try comparison to ideal reference first, and if that fails use slower verificator.
2042 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2043 {
2044 const float wx = (float)px + 0.5f;
2045 const float wy = (float)py + 0.5f;
2046 const float nx = wx / dstW;
2047 const float ny = wy / dstH;
2048
2049 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2050 const float triWx = triNdx ? dstW - wx : wx;
2051 const float triWy = triNdx ? dstH - wy : wy;
2052 const float triNx = triNdx ? 1.0f - nx : nx;
2053 const float triNy = triNdx ? 1.0f - ny : ny;
2054
2055 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2056 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2057 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2058 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2059 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2060 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2061 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2062
2063 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2064
2065 // Compute lod bounds across lodOffsets range.
2066 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2067 {
2068 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2069 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2070 const float nxo = wxo/dstW;
2071 const float nyo = wyo/dstH;
2072
2073 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2074 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2075 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2076 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2077 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2078
2079 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2080 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2081 }
2082
2083 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2084 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2085
2086 if (!isOk)
2087 {
2088 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2089 numFailed += 1;
2090 }
2091 }
2092 }
2093 }
2094
2095 return numFailed;
2096 }
2097
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)2098 bool verifyTextureResult (tcu::TestContext& testCtx,
2099 const tcu::ConstPixelBufferAccess& result,
2100 const tcu::Texture1DArrayView& src,
2101 const float* texCoord,
2102 const ReferenceParams& sampleParams,
2103 const tcu::LookupPrecision& lookupPrec,
2104 const tcu::LodPrecision& lodPrec,
2105 const tcu::PixelFormat& pixelFormat)
2106 {
2107 tcu::TestLog& log = testCtx.getLog();
2108 tcu::Surface reference (result.getWidth(), result.getHeight());
2109 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2110 int numFailedPixels;
2111
2112 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2113
2114 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2115 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2116
2117 if (numFailedPixels > 0)
2118 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2119
2120 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2121 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2122
2123 if (numFailedPixels > 0)
2124 {
2125 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2126 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2127 }
2128
2129 log << tcu::TestLog::EndImageSet;
2130
2131 return numFailedPixels == 0;
2132 }
2133
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)2134 bool verifyTextureResult (tcu::TestContext& testCtx,
2135 const tcu::ConstPixelBufferAccess& result,
2136 const tcu::Texture2DArrayView& src,
2137 const float* texCoord,
2138 const ReferenceParams& sampleParams,
2139 const tcu::LookupPrecision& lookupPrec,
2140 const tcu::LodPrecision& lodPrec,
2141 const tcu::PixelFormat& pixelFormat)
2142 {
2143 tcu::TestLog& log = testCtx.getLog();
2144 tcu::Surface reference (result.getWidth(), result.getHeight());
2145 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2146 int numFailedPixels;
2147
2148 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2149
2150 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2151 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2152
2153 if (numFailedPixels > 0)
2154 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2155
2156 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2157 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2158
2159 if (numFailedPixels > 0)
2160 {
2161 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2162 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2163 }
2164
2165 log << tcu::TestLog::EndImageSet;
2166
2167 return numFailedPixels == 0;
2168 }
2169
2170 //! 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)2171 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2172 const tcu::ConstPixelBufferAccess& reference,
2173 const tcu::PixelBufferAccess& errorMask,
2174 const tcu::TextureCubeArrayView& baseView,
2175 const float* texCoord,
2176 const ReferenceParams& sampleParams,
2177 const tcu::LookupPrecision& lookupPrec,
2178 const tcu::IVec4& coordBits,
2179 const tcu::LodPrecision& lodPrec,
2180 qpWatchDog* watchDog)
2181 {
2182 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2183 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2184
2185 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2186 const tcu::TextureCubeArrayView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
2187
2188 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2189 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2190 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2191 const tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2192
2193 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2194 const float dstW = float(dstSize.x());
2195 const float dstH = float(dstSize.y());
2196 const int srcSize = src.getSize();
2197
2198 // Coordinates per triangle.
2199 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2200 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2201 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2202 const tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2203 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2204
2205 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2206
2207 const float posEps = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2208
2209 int numFailed = 0;
2210
2211 const tcu::Vec2 lodOffsets[] =
2212 {
2213 tcu::Vec2(-1, 0),
2214 tcu::Vec2(+1, 0),
2215 tcu::Vec2( 0, -1),
2216 tcu::Vec2( 0, +1),
2217
2218 // \note Not strictly allowed by spec, but implementations do this in practice.
2219 tcu::Vec2(-1, -1),
2220 tcu::Vec2(-1, +1),
2221 tcu::Vec2(+1, -1),
2222 tcu::Vec2(+1, +1),
2223 };
2224
2225 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2226
2227 for (int py = 0; py < result.getHeight(); py++)
2228 {
2229 // Ugly hack, validation can take way too long at the moment.
2230 if (watchDog)
2231 qpWatchDog_touch(watchDog);
2232
2233 for (int px = 0; px < result.getWidth(); px++)
2234 {
2235 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2236 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2237
2238 // Try comparison to ideal reference first, and if that fails use slower verificator.
2239 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2240 {
2241 const float wx = (float)px + 0.5f;
2242 const float wy = (float)py + 0.5f;
2243 const float nx = wx / dstW;
2244 const float ny = wy / dstH;
2245
2246 const bool tri0 = nx + ny - posEps <= 1.0f;
2247 const bool tri1 = nx + ny + posEps >= 1.0f;
2248
2249 bool isOk = false;
2250
2251 DE_ASSERT(tri0 || tri1);
2252
2253 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2254 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2255 {
2256 const float triWx = triNdx ? dstW - wx : wx;
2257 const float triWy = triNdx ? dstH - wy : wy;
2258 const float triNx = triNdx ? 1.0f - nx : nx;
2259 const float triNy = triNdx ? 1.0f - ny : ny;
2260
2261 const tcu::Vec4 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2262 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2263 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2264 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2265 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2266 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2267 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2268 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2269 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2270 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2271
2272 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2273
2274 // Compute lod bounds across lodOffsets range.
2275 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2276 {
2277 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2278 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2279 const float nxo = wxo/dstW;
2280 const float nyo = wyo/dstH;
2281
2282 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2283 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2284 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2285 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2286 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2287 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2288 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2289 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2290 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2291 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2292
2293 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2294 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2295 }
2296
2297 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2298
2299 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2300 {
2301 isOk = true;
2302 break;
2303 }
2304 }
2305
2306 if (!isOk)
2307 {
2308 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2309 numFailed += 1;
2310 }
2311 }
2312 }
2313 }
2314
2315 return numFailed;
2316 }
2317
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)2318 bool verifyTextureResult (tcu::TestContext& testCtx,
2319 const tcu::ConstPixelBufferAccess& result,
2320 const tcu::TextureCubeArrayView& src,
2321 const float* texCoord,
2322 const ReferenceParams& sampleParams,
2323 const tcu::LookupPrecision& lookupPrec,
2324 const tcu::IVec4& coordBits,
2325 const tcu::LodPrecision& lodPrec,
2326 const tcu::PixelFormat& pixelFormat)
2327 {
2328 tcu::TestLog& log = testCtx.getLog();
2329 tcu::Surface reference (result.getWidth(), result.getHeight());
2330 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2331 int numFailedPixels;
2332
2333 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2334
2335 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2336 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2337
2338 if (numFailedPixels > 0)
2339 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2340
2341 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2342 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2343
2344 if (numFailedPixels > 0)
2345 {
2346 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2347 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2348 }
2349
2350 log << tcu::TestLog::EndImageSet;
2351
2352 return numFailedPixels == 0;
2353 }
2354
2355 // Shadow lookup verification
2356
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)2357 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2358 const tcu::ConstPixelBufferAccess& reference,
2359 const tcu::PixelBufferAccess& errorMask,
2360 const tcu::Texture2DView& src,
2361 const float* texCoord,
2362 const ReferenceParams& sampleParams,
2363 const tcu::TexComparePrecision& comparePrec,
2364 const tcu::LodPrecision& lodPrec,
2365 const tcu::Vec3& nonShadowThreshold)
2366 {
2367 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2368 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2369
2370 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2371 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2372
2373 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2374 const float dstW = float(dstSize.x());
2375 const float dstH = float(dstSize.y());
2376 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2377
2378 // Coordinates and lod per triangle.
2379 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2380 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2381 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2382
2383 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2384
2385 int numFailed = 0;
2386
2387 const tcu::Vec2 lodOffsets[] =
2388 {
2389 tcu::Vec2(-1, 0),
2390 tcu::Vec2(+1, 0),
2391 tcu::Vec2( 0, -1),
2392 tcu::Vec2( 0, +1),
2393 };
2394
2395 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2396
2397 for (int py = 0; py < result.getHeight(); py++)
2398 {
2399 for (int px = 0; px < result.getWidth(); px++)
2400 {
2401 const tcu::Vec4 resPix = result.getPixel(px, py);
2402 const tcu::Vec4 refPix = reference.getPixel(px, py);
2403
2404 // Other channels should trivially match to reference.
2405 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2406 {
2407 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2408 numFailed += 1;
2409 continue;
2410 }
2411
2412 // Reference result is known to be a valid result, we can
2413 // skip verification if thes results are equal
2414 if (resPix.x() != refPix.x())
2415 {
2416 const float wx = (float)px + 0.5f;
2417 const float wy = (float)py + 0.5f;
2418 const float nx = wx / dstW;
2419 const float ny = wy / dstH;
2420
2421 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2422 const float triWx = triNdx ? dstW - wx : wx;
2423 const float triWy = triNdx ? dstH - wy : wy;
2424 const float triNx = triNdx ? 1.0f - nx : nx;
2425 const float triNy = triNdx ? 1.0f - ny : ny;
2426
2427 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2428 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2429 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2430 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2431 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2432 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2433
2434 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2435
2436 // Compute lod bounds across lodOffsets range.
2437 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2438 {
2439 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2440 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2441 const float nxo = wxo/dstW;
2442 const float nyo = wyo/dstH;
2443
2444 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2445 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2446 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2447 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2448 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2449
2450 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2451 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2452 }
2453
2454 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2455 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2456
2457 if (!isOk)
2458 {
2459 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2460 numFailed += 1;
2461 }
2462 }
2463 }
2464 }
2465
2466 return numFailed;
2467 }
2468
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)2469 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2470 const tcu::ConstPixelBufferAccess& reference,
2471 const tcu::PixelBufferAccess& errorMask,
2472 const tcu::TextureCubeView& src,
2473 const float* texCoord,
2474 const ReferenceParams& sampleParams,
2475 const tcu::TexComparePrecision& comparePrec,
2476 const tcu::LodPrecision& lodPrec,
2477 const tcu::Vec3& nonShadowThreshold)
2478 {
2479 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2480 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2481
2482 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2483 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2484 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2485
2486 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2487 const float dstW = float(dstSize.x());
2488 const float dstH = float(dstSize.y());
2489 const int srcSize = src.getSize();
2490
2491 // Coordinates per triangle.
2492 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2493 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2494 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2495 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2496
2497 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2498
2499 int numFailed = 0;
2500
2501 const tcu::Vec2 lodOffsets[] =
2502 {
2503 tcu::Vec2(-1, 0),
2504 tcu::Vec2(+1, 0),
2505 tcu::Vec2( 0, -1),
2506 tcu::Vec2( 0, +1),
2507 };
2508
2509 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2510
2511 for (int py = 0; py < result.getHeight(); py++)
2512 {
2513 for (int px = 0; px < result.getWidth(); px++)
2514 {
2515 const tcu::Vec4 resPix = result.getPixel(px, py);
2516 const tcu::Vec4 refPix = reference.getPixel(px, py);
2517
2518 // Other channels should trivially match to reference.
2519 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2520 {
2521 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2522 numFailed += 1;
2523 continue;
2524 }
2525
2526 // Reference result is known to be a valid result, we can
2527 // skip verification if thes results are equal
2528 if (resPix.x() != refPix.x())
2529 {
2530 const float wx = (float)px + 0.5f;
2531 const float wy = (float)py + 0.5f;
2532 const float nx = wx / dstW;
2533 const float ny = wy / dstH;
2534
2535 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2536 const float triWx = triNdx ? dstW - wx : wx;
2537 const float triWy = triNdx ? dstH - wy : wy;
2538 const float triNx = triNdx ? 1.0f - nx : nx;
2539 const float triNy = triNdx ? 1.0f - ny : ny;
2540
2541 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2542 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2543 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2544 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2545 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2546 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2547 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2548 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2549 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2550
2551 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2552
2553 // Compute lod bounds across lodOffsets range.
2554 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2555 {
2556 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2557 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2558 const float nxo = wxo/dstW;
2559 const float nyo = wyo/dstH;
2560
2561 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2562 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2563 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2564 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2565 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2566 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2567 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2568 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2569 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2570 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2571
2572 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2573 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2574 }
2575
2576 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2577 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2578
2579 if (!isOk)
2580 {
2581 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2582 numFailed += 1;
2583 }
2584 }
2585 }
2586 }
2587
2588 return numFailed;
2589 }
2590
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)2591 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2592 const tcu::ConstPixelBufferAccess& reference,
2593 const tcu::PixelBufferAccess& errorMask,
2594 const tcu::Texture2DArrayView& src,
2595 const float* texCoord,
2596 const ReferenceParams& sampleParams,
2597 const tcu::TexComparePrecision& comparePrec,
2598 const tcu::LodPrecision& lodPrec,
2599 const tcu::Vec3& nonShadowThreshold)
2600 {
2601 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2602 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2603
2604 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2605 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2606 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2607
2608 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2609 const float dstW = float(dstSize.x());
2610 const float dstH = float(dstSize.y());
2611 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2612
2613 // Coordinates and lod per triangle.
2614 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2615 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2616 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2617 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2618
2619 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2620
2621 int numFailed = 0;
2622
2623 const tcu::Vec2 lodOffsets[] =
2624 {
2625 tcu::Vec2(-1, 0),
2626 tcu::Vec2(+1, 0),
2627 tcu::Vec2( 0, -1),
2628 tcu::Vec2( 0, +1),
2629 };
2630
2631 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2632
2633 for (int py = 0; py < result.getHeight(); py++)
2634 {
2635 for (int px = 0; px < result.getWidth(); px++)
2636 {
2637 const tcu::Vec4 resPix = result.getPixel(px, py);
2638 const tcu::Vec4 refPix = reference.getPixel(px, py);
2639
2640 // Other channels should trivially match to reference.
2641 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2642 {
2643 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2644 numFailed += 1;
2645 continue;
2646 }
2647
2648 // Reference result is known to be a valid result, we can
2649 // skip verification if thes results are equal
2650 if (resPix.x() != refPix.x())
2651 {
2652 const float wx = (float)px + 0.5f;
2653 const float wy = (float)py + 0.5f;
2654 const float nx = wx / dstW;
2655 const float ny = wy / dstH;
2656
2657 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2658 const float triWx = triNdx ? dstW - wx : wx;
2659 const float triWy = triNdx ? dstH - wy : wy;
2660 const float triNx = triNdx ? 1.0f - nx : nx;
2661 const float triNy = triNdx ? 1.0f - ny : ny;
2662
2663 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2664 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2665 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2666 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2667 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2668 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2669 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2670
2671 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2672
2673 // Compute lod bounds across lodOffsets range.
2674 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2675 {
2676 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2677 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2678 const float nxo = wxo/dstW;
2679 const float nyo = wyo/dstH;
2680
2681 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2682 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2683 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2684 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2685 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2686
2687 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2688 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2689 }
2690
2691 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2692 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2693
2694 if (!isOk)
2695 {
2696 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2697 numFailed += 1;
2698 }
2699 }
2700 }
2701 }
2702
2703 return numFailed;
2704 }
2705
2706 // Mipmap generation comparison.
2707
compareGenMipmapBilinear(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)2708 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2709 {
2710 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2711
2712 const float dstW = float(dst.getWidth());
2713 const float dstH = float(dst.getHeight());
2714 const float srcW = float(src.getWidth());
2715 const float srcH = float(src.getHeight());
2716 int numFailed = 0;
2717
2718 // Translation to lookup verification parameters.
2719 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
2720 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
2721 tcu::LookupPrecision lookupPrec;
2722
2723 lookupPrec.colorThreshold = precision.colorThreshold;
2724 lookupPrec.colorMask = precision.colorMask;
2725 lookupPrec.coordBits = tcu::IVec3(22);
2726 lookupPrec.uvwBits = precision.filterBits;
2727
2728 for (int y = 0; y < dst.getHeight(); y++)
2729 for (int x = 0; x < dst.getWidth(); x++)
2730 {
2731 const tcu::Vec4 result = dst.getPixel(x, y);
2732 const float cx = (float(x)+0.5f) / dstW * srcW;
2733 const float cy = (float(y)+0.5f) / dstH * srcH;
2734 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
2735
2736 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2737 if (!isOk)
2738 numFailed += 1;
2739 }
2740
2741 return numFailed;
2742 }
2743
compareGenMipmapBox(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)2744 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2745 {
2746 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2747
2748 const float dstW = float(dst.getWidth());
2749 const float dstH = float(dst.getHeight());
2750 const float srcW = float(src.getWidth());
2751 const float srcH = float(src.getHeight());
2752 int numFailed = 0;
2753
2754 // Translation to lookup verification parameters.
2755 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
2756 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
2757 tcu::LookupPrecision lookupPrec;
2758
2759 lookupPrec.colorThreshold = precision.colorThreshold;
2760 lookupPrec.colorMask = precision.colorMask;
2761 lookupPrec.coordBits = tcu::IVec3(22);
2762 lookupPrec.uvwBits = precision.filterBits;
2763
2764 for (int y = 0; y < dst.getHeight(); y++)
2765 for (int x = 0; x < dst.getWidth(); x++)
2766 {
2767 const tcu::Vec4 result = dst.getPixel(x, y);
2768 const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
2769 const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
2770 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
2771
2772 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2773 if (!isOk)
2774 numFailed += 1;
2775 }
2776
2777 return numFailed;
2778 }
2779
compareGenMipmapVeryLenient(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)2780 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2781 {
2782 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2783 DE_UNREF(precision);
2784
2785 const float dstW = float(dst.getWidth());
2786 const float dstH = float(dst.getHeight());
2787 const float srcW = float(src.getWidth());
2788 const float srcH = float(src.getHeight());
2789 int numFailed = 0;
2790
2791 for (int y = 0; y < dst.getHeight(); y++)
2792 for (int x = 0; x < dst.getWidth(); x++)
2793 {
2794 const tcu::Vec4 result = dst.getPixel(x, y);
2795 const int minX = deFloorFloatToInt32(((float)x-0.5f) / dstW * srcW);
2796 const int minY = deFloorFloatToInt32(((float)y-0.5f) / dstH * srcH);
2797 const int maxX = deCeilFloatToInt32(((float)x+1.5f) / dstW * srcW);
2798 const int maxY = deCeilFloatToInt32(((float)y+1.5f) / dstH * srcH);
2799 tcu::Vec4 minVal, maxVal;
2800 bool isOk;
2801
2802 DE_ASSERT(minX < maxX && minY < maxY);
2803
2804 for (int ky = minY; ky <= maxY; ky++)
2805 {
2806 for (int kx = minX; kx <= maxX; kx++)
2807 {
2808 const int sx = de::clamp(kx, 0, src.getWidth()-1);
2809 const int sy = de::clamp(ky, 0, src.getHeight()-1);
2810 const tcu::Vec4 sample = src.getPixel(sx, sy);
2811
2812 if (ky == minY && kx == minX)
2813 {
2814 minVal = sample;
2815 maxVal = sample;
2816 }
2817 else
2818 {
2819 minVal = min(sample, minVal);
2820 maxVal = max(sample, maxVal);
2821 }
2822 }
2823 }
2824
2825 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
2826
2827 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2828 if (!isOk)
2829 numFailed += 1;
2830 }
2831
2832 return numFailed;
2833 }
2834
compareGenMipmapResult(tcu::TestLog & log,const tcu::Texture2D & resultTexture,const tcu::Texture2D & level0Reference,const GenMipmapPrecision & precision)2835 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
2836 {
2837 qpTestResult result = QP_TEST_RESULT_PASS;
2838
2839 // Special comparison for level 0.
2840 {
2841 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
2842 const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
2843
2844 if (!level0Ok)
2845 {
2846 log << tcu::TestLog::Message << "ERROR: Level 0 comparison failed!" << tcu::TestLog::EndMessage;
2847 result = QP_TEST_RESULT_FAIL;
2848 }
2849 }
2850
2851 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
2852 {
2853 const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx-1);
2854 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx);
2855 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
2856 bool levelOk = false;
2857
2858 // Try different comparisons in quality order.
2859
2860 if (!levelOk)
2861 {
2862 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
2863 if (numFailed == 0)
2864 levelOk = true;
2865 else
2866 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2867 }
2868
2869 if (!levelOk)
2870 {
2871 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
2872 if (numFailed == 0)
2873 levelOk = true;
2874 else
2875 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2876 }
2877
2878 // At this point all high-quality methods have been used.
2879 if (!levelOk && result == QP_TEST_RESULT_PASS)
2880 result = QP_TEST_RESULT_QUALITY_WARNING;
2881
2882 if (!levelOk)
2883 {
2884 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
2885 if (numFailed == 0)
2886 levelOk = true;
2887 else
2888 log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
2889 }
2890
2891 if (!levelOk)
2892 result = QP_TEST_RESULT_FAIL;
2893
2894 log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
2895 << tcu::TestLog::Image("Result", "Result", dst);
2896
2897 if (!levelOk)
2898 log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2899
2900 log << tcu::TestLog::EndImageSet;
2901 }
2902
2903 return result;
2904 }
2905
compareGenMipmapResult(tcu::TestLog & log,const tcu::TextureCube & resultTexture,const tcu::TextureCube & level0Reference,const GenMipmapPrecision & precision)2906 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
2907 {
2908 qpTestResult result = QP_TEST_RESULT_PASS;
2909
2910 static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
2911 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
2912
2913 // Special comparison for level 0.
2914 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
2915 {
2916 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
2917 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
2918 const bool level0Ok = tcu::floatThresholdCompare(log,
2919 ("Level0Face" + de::toString(faceNdx)).c_str(),
2920 (string("Level 0, face ") + s_faceNames[face]).c_str(),
2921 level0Reference.getLevelFace(0, face),
2922 resultTexture.getLevelFace(0, face),
2923 threshold, tcu::COMPARE_LOG_RESULT);
2924
2925 if (!level0Ok)
2926 {
2927 log << tcu::TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << tcu::TestLog::EndMessage;
2928 result = QP_TEST_RESULT_FAIL;
2929 }
2930 }
2931
2932 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
2933 {
2934 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
2935 {
2936 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
2937 const char* faceName = s_faceNames[face];
2938 const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx-1, face);
2939 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face);
2940 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
2941 bool levelOk = false;
2942
2943 // Try different comparisons in quality order.
2944
2945 if (!levelOk)
2946 {
2947 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
2948 if (numFailed == 0)
2949 levelOk = true;
2950 else
2951 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2952 }
2953
2954 if (!levelOk)
2955 {
2956 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
2957 if (numFailed == 0)
2958 levelOk = true;
2959 else
2960 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2961 }
2962
2963 // At this point all high-quality methods have been used.
2964 if (!levelOk && result == QP_TEST_RESULT_PASS)
2965 result = QP_TEST_RESULT_QUALITY_WARNING;
2966
2967 if (!levelOk)
2968 {
2969 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
2970 if (numFailed == 0)
2971 levelOk = true;
2972 else
2973 log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
2974 }
2975
2976 if (!levelOk)
2977 result = QP_TEST_RESULT_FAIL;
2978
2979 log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
2980 << tcu::TestLog::Image("Result", "Result", dst);
2981
2982 if (!levelOk)
2983 log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2984
2985 log << tcu::TestLog::EndImageSet;
2986 }
2987 }
2988
2989 return result;
2990 }
2991
2992 // Logging utilities.
2993
operator <<(std::ostream & str,const LogGradientFmt & fmt)2994 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
2995 {
2996 return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
2997 << "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
2998 << "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
2999 << "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3000 }
3001
3002 } // TextureTestUtil
3003 } // glu
3004