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