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