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