1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Utility functions and structures for texture tests. This code
22 * is originated from the modules/glshared/glsTextureTestUtil.hpp and it
23 * is tightly coupled with the GLES and Vulkan texture tests!
24 *//*--------------------------------------------------------------------*/
26 #include "gluTextureTestUtil.hpp"
28 #include "tcuFloat.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuVectorUtil.hpp"
34 #include "deStringUtil.hpp"
43 namespace TextureTestUtil
51 SamplerType getSamplerType (tcu::TextureFormat format)
53 using tcu::TextureFormat;
57 case TextureFormat::SIGNED_INT8:
58 case TextureFormat::SIGNED_INT16:
59 case TextureFormat::SIGNED_INT32:
60 return SAMPLERTYPE_INT;
62 case TextureFormat::UNSIGNED_INT8:
63 case TextureFormat::UNSIGNED_INT32:
64 case TextureFormat::UNSIGNED_INT_1010102_REV:
65 return SAMPLERTYPE_UINT;
67 // Texture formats used in depth/stencil textures.
68 case TextureFormat::UNSIGNED_INT16:
69 case TextureFormat::UNSIGNED_INT_24_8:
70 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FLOAT : SAMPLERTYPE_UINT;
73 return SAMPLERTYPE_FLOAT;
77 SamplerType getFetchSamplerType (tcu::TextureFormat format)
79 using tcu::TextureFormat;
83 case TextureFormat::SIGNED_INT8:
84 case TextureFormat::SIGNED_INT16:
85 case TextureFormat::SIGNED_INT32:
86 return SAMPLERTYPE_FETCH_INT;
88 case TextureFormat::UNSIGNED_INT8:
89 case TextureFormat::UNSIGNED_INT32:
90 case TextureFormat::UNSIGNED_INT_1010102_REV:
91 return SAMPLERTYPE_FETCH_UINT;
93 // Texture formats used in depth/stencil textures.
94 case TextureFormat::UNSIGNED_INT16:
95 case TextureFormat::UNSIGNED_INT_24_8:
96 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FETCH_FLOAT : SAMPLERTYPE_FETCH_UINT;
99 return SAMPLERTYPE_FETCH_FLOAT;
103 static tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLevel, int maxLevel)
105 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
106 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
107 const int numLevels = clampedMax-clampedBase+1;
108 return tcu::Texture1DView(numLevels, view.getLevels()+clampedBase);
111 static tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLevel, int maxLevel)
113 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
114 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
115 const int numLevels = clampedMax-clampedBase+1;
116 return tcu::Texture2DView(numLevels, view.getLevels()+clampedBase);
119 static tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int baseLevel, int maxLevel)
121 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
122 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
123 const int numLevels = clampedMax-clampedBase+1;
124 const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST];
126 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
127 levels[face] = view.getFaceLevels((tcu::CubeFace)face) + clampedBase;
129 return tcu::TextureCubeView(numLevels, levels);
132 static tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLevel, int maxLevel)
134 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
135 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
136 const int numLevels = clampedMax-clampedBase+1;
137 return tcu::Texture3DView(numLevels, view.getLevels()+clampedBase);
140 static tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel)
142 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
143 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
144 const int numLevels = clampedMax-clampedBase+1;
145 return tcu::TextureCubeArrayView(numLevels, view.getLevels()+clampedBase);
148 inline float linearInterpolate (float t, float minVal, float maxVal)
150 return minVal + (maxVal - minVal) * t;
153 inline tcu::Vec4 linearInterpolate (float t, const tcu::Vec4& a, const tcu::Vec4& b)
155 return a + (b - a) * t;
158 inline float bilinearInterpolate (float x, float y, const tcu::Vec4& quad)
160 float w00 = (1.0f-x)*(1.0f-y);
161 float w01 = (1.0f-x)*y;
162 float w10 = x*(1.0f-y);
164 return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
167 inline float triangleInterpolate (float v0, float v1, float v2, float x, float y)
169 return v0 + (v2-v0)*x + (v1-v0)*y;
172 inline float triangleInterpolate (const tcu::Vec3& v, float x, float y)
174 return triangleInterpolate(v.x(), v.y(), v.z(), x, y);
177 // 1D lookup LOD computation.
179 float computeLodFromDerivates (LodMode mode, float dudx, float dudy)
184 // \note [mika] Min and max bounds equal to exact with 1D textures
186 case LODMODE_MIN_BOUND:
187 case LODMODE_MAX_BOUND:
188 p = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
195 return deFloatLog2(p);
198 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, deInt32 srcSize, const tcu::Vec3& sq)
200 float dux = (sq.z() - sq.x()) * (float)srcSize;
201 float duy = (sq.y() - sq.x()) * (float)srcSize;
202 float dx = (float)dstSize.x();
203 float dy = (float)dstSize.y();
205 return computeLodFromDerivates(mode, dux/dx, duy/dy);
208 // 2D lookup LOD computation.
210 float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dudy, float dvdy)
216 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx), deFloatSqrt(dudy*dudy + dvdy*dvdy));
219 case LODMODE_MIN_BOUND:
220 case LODMODE_MAX_BOUND:
222 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
223 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
225 p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv;
233 return deFloatLog2(p);
236 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec2& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq)
238 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
239 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
240 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
241 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
242 float dx = (float)dstSize.x();
243 float dy = (float)dstSize.y();
245 return computeLodFromDerivates(mode, dux/dx, dvx/dx, duy/dy, dvy/dy);
248 // 3D lookup LOD computation.
250 float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy)
256 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx + dwdx*dwdx), deFloatSqrt(dudy*dudy + dvdy*dvdy + dwdy*dwdy));
259 case LODMODE_MIN_BOUND:
260 case LODMODE_MAX_BOUND:
262 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
263 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
264 float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy));
266 p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw);
274 return deFloatLog2(p);
277 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec3& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq, const tcu::Vec3& rq)
279 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
280 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
281 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
282 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
283 float dwx = (rq.z() - rq.x()) * (float)srcSize.z();
284 float dwy = (rq.y() - rq.x()) * (float)srcSize.z();
285 float dx = (float)dstSize.x();
286 float dy = (float)dstSize.y();
288 return computeLodFromDerivates(mode, dux/dx, dvx/dx, dwx/dx, duy/dy, dvy/dy, dwy/dy);
291 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
293 return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
296 static inline float triDerivateX (const tcu::Vec3& s, const tcu::Vec3& w, float wx, float width, float ny)
298 float d = w[1]*w[2]*(width*(ny - 1.0f) + wx) - w[0]*(w[2]*width*ny + w[1]*wx);
299 return (w[0]*w[1]*w[2]*width * (w[1]*(s[0] - s[2])*(ny - 1.0f) + ny*(w[2]*(s[1] - s[0]) + w[0]*(s[2] - s[1])))) / (d*d);
302 static inline float triDerivateY (const tcu::Vec3& s, const tcu::Vec3& w, float wy, float height, float nx)
304 float d = w[1]*w[2]*(height*(nx - 1.0f) + wy) - w[0]*(w[1]*height*nx + w[2]*wy);
305 return (w[0]*w[1]*w[2]*height * (w[2]*(s[0] - s[1])*(nx - 1.0f) + nx*(w[0]*(s[1] - s[2]) + w[1]*(s[2] - s[0])))) / (d*d);
309 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& projection, float wx, float wy, float width, float height)
311 // Exact derivatives.
312 float dudx = triDerivateX(u, projection, wx, width, wy/height);
313 float dudy = triDerivateY(u, projection, wy, height, wx/width);
315 return computeLodFromDerivates(mode, dudx, dudy);
319 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& projection, float wx, float wy, float width, float height)
321 // Exact derivatives.
322 float dudx = triDerivateX(u, projection, wx, width, wy/height);
323 float dvdx = triDerivateX(v, projection, wx, width, wy/height);
324 float dudy = triDerivateY(u, projection, wy, height, wx/width);
325 float dvdy = triDerivateY(v, projection, wy, height, wx/width);
327 return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy);
331 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& w, const tcu::Vec3& projection, float wx, float wy, float width, float height)
333 // Exact derivatives.
334 float dudx = triDerivateX(u, projection, wx, width, wy/height);
335 float dvdx = triDerivateX(v, projection, wx, width, wy/height);
336 float dwdx = triDerivateX(w, projection, wx, width, wy/height);
337 float dudy = triDerivateY(u, projection, wy, height, wx/width);
338 float dvdy = triDerivateY(v, projection, wy, height, wx/width);
339 float dwdy = triDerivateY(w, projection, wy, height, wx/width);
341 return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy);
344 static inline tcu::Vec4 execSample (const tcu::Texture1DView& src, const ReferenceParams& params, float s, float lod)
346 if (params.samplerType == SAMPLERTYPE_SHADOW)
347 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f);
349 return src.sample(params.sampler, s, lod);
352 static inline tcu::Vec4 execSample (const tcu::Texture2DView& src, const ReferenceParams& params, float s, float t, float lod)
354 if (params.samplerType == SAMPLERTYPE_SHADOW)
355 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
357 return src.sample(params.sampler, s, t, lod);
360 static inline tcu::Vec4 execSample (const tcu::TextureCubeView& src, const ReferenceParams& params, float s, float t, float r, float lod)
362 if (params.samplerType == SAMPLERTYPE_SHADOW)
363 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
365 return src.sample(params.sampler, s, t, r, lod);
368 static inline tcu::Vec4 execSample (const tcu::Texture2DArrayView& src, const ReferenceParams& params, float s, float t, float r, float lod)
370 if (params.samplerType == SAMPLERTYPE_SHADOW)
371 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
373 return src.sample(params.sampler, s, t, r, lod);
376 static inline tcu::Vec4 execSample (const tcu::TextureCubeArrayView& src, const ReferenceParams& params, float s, float t, float r, float q, float lod)
378 if (params.samplerType == SAMPLERTYPE_SHADOW)
379 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f);
381 return src.sample(params.sampler, s, t, r, q, lod);
384 static inline tcu::Vec4 execSample (const tcu::Texture1DArrayView& src, const ReferenceParams& params, float s, float t, float lod)
386 if (params.samplerType == SAMPLERTYPE_SHADOW)
387 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
389 return src.sample(params.sampler, s, t, lod);
392 static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
394 // Separate combined DS formats
395 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
396 const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
398 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
400 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
401 int srcSize = src.getWidth();
403 // Coordinates and lod per triangle.
404 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
405 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod),
406 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) };
408 for (int y = 0; y < dst.getHeight(); y++)
410 for (int x = 0; x < dst.getWidth(); x++)
412 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
413 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
415 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
416 float triX = triNdx ? 1.0f-xf : xf;
417 float triY = triNdx ? 1.0f-yf : yf;
419 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
420 float lod = triLod[triNdx];
422 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
427 static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
429 // Separate combined DS formats
430 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
431 const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
433 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
435 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
436 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
438 // Coordinates and lod per triangle.
439 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
440 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
441 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
442 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
444 for (int y = 0; y < dst.getHeight(); y++)
446 for (int x = 0; x < dst.getWidth(); x++)
448 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
449 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
451 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
452 float triX = triNdx ? 1.0f-xf : xf;
453 float triY = triNdx ? 1.0f-yf : yf;
455 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
456 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
457 float lod = triLod[triNdx];
459 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
464 static void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
466 // Separate combined DS formats
467 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
468 const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
470 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
471 float dstW = (float)dst.getWidth();
472 float dstH = (float)dst.getHeight();
474 tcu::Vec4 uq = sq * (float)src.getWidth();
476 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
477 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
478 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
480 for (int py = 0; py < dst.getHeight(); py++)
482 for (int px = 0; px < dst.getWidth(); px++)
484 float wx = (float)px + 0.5f;
485 float wy = (float)py + 0.5f;
486 float nx = wx / dstW;
487 float ny = wy / dstH;
489 int triNdx = nx + ny >= 1.0f ? 1 : 0;
490 float triWx = triNdx ? dstW - wx : wx;
491 float triWy = triNdx ? dstH - wy : wy;
492 float triNx = triNdx ? 1.0f - nx : nx;
493 float triNy = triNdx ? 1.0f - ny : ny;
495 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
496 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
499 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
504 static void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
506 // Separate combined DS formats
507 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
508 const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
510 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
511 float dstW = (float)dst.getWidth();
512 float dstH = (float)dst.getHeight();
514 tcu::Vec4 uq = sq * (float)src.getWidth();
515 tcu::Vec4 vq = tq * (float)src.getHeight();
517 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
518 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
519 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
520 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
521 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
523 for (int py = 0; py < dst.getHeight(); py++)
525 for (int px = 0; px < dst.getWidth(); px++)
527 float wx = (float)px + 0.5f;
528 float wy = (float)py + 0.5f;
529 float nx = wx / dstW;
530 float ny = wy / dstH;
532 int triNdx = nx + ny >= 1.0f ? 1 : 0;
533 float triWx = triNdx ? dstW - wx : wx;
534 float triWy = triNdx ? dstH - wy : wy;
535 float triNx = triNdx ? 1.0f - nx : nx;
536 float triNy = triNdx ? 1.0f - ny : ny;
538 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
539 float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
540 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
543 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
548 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
550 const tcu::Texture2DView view = getSubView(src, params.baseLevel, params.maxLevel);
551 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
552 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
554 if (params.flags & ReferenceParams::PROJECTED)
555 sampleTextureProjected(dst, view, sq, tq, params);
557 sampleTextureNonProjected(dst, view, sq, tq, params);
560 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params)
562 const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel);
563 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
565 if (params.flags & ReferenceParams::PROJECTED)
566 sampleTextureProjected(dst, view, sq, params);
568 sampleTextureNonProjected(dst, view, sq, params);
571 static float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize)
573 const tcu::CubeFace face = tcu::selectCubeFace(coord);
578 // \note Derivate signs don't matter when computing lod
581 case tcu::CUBEFACE_NEGATIVE_X:
582 case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
583 case tcu::CUBEFACE_NEGATIVE_Y:
584 case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
585 case tcu::CUBEFACE_NEGATIVE_Z:
586 case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
592 const float sc = coord[sNdx];
593 const float tc = coord[tNdx];
594 const float ma = de::abs(coord[maNdx]);
595 const float scdx = coordDx[sNdx];
596 const float tcdx = coordDx[tNdx];
597 const float madx = de::abs(coordDx[maNdx]);
598 const float scdy = coordDy[sNdx];
599 const float tcdy = coordDy[tNdx];
600 const float mady = de::abs(coordDy[maNdx]);
601 const float dudx = float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma);
602 const float dvdx = float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma);
603 const float dudy = float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma);
604 const float dvdy = float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma);
606 return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
610 static void sampleTextureCube (const tcu::SurfaceAccess& dst, const tcu::TextureCubeView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
612 // Separate combined DS formats
613 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
614 const tcu::TextureCubeView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
616 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
617 const float dstW = float(dstSize.x());
618 const float dstH = float(dstSize.y());
619 const int srcSize = src.getSize();
621 // Coordinates per triangle.
622 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
623 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
624 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
625 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
627 const float lodBias ((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
629 for (int py = 0; py < dst.getHeight(); py++)
631 for (int px = 0; px < dst.getWidth(); px++)
633 const float wx = (float)px + 0.5f;
634 const float wy = (float)py + 0.5f;
635 const float nx = wx / dstW;
636 const float ny = wy / dstH;
638 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
639 const float triNx = triNdx ? 1.0f - nx : nx;
640 const float triNy = triNdx ? 1.0f - ny : ny;
642 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
643 triangleInterpolate(triT[triNdx], triNx, triNy),
644 triangleInterpolate(triR[triNdx], triNx, triNy));
645 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
646 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
647 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
648 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
649 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
650 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
652 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod);
654 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py);
659 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
661 const tcu::TextureCubeView view = getSubView(src, params.baseLevel, params.maxLevel);
662 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
663 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
664 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
666 return sampleTextureCube(dst, view, sq, tq, rq, params);
669 static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
671 // Separate combined DS formats
672 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
673 const tcu::Texture2DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
675 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
677 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
678 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
680 // Coordinates and lod per triangle.
681 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
682 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
683 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
684 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
685 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
687 for (int y = 0; y < dst.getHeight(); y++)
689 for (int x = 0; x < dst.getWidth(); x++)
691 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
692 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
694 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
695 float triX = triNdx ? 1.0f-xf : xf;
696 float triY = triNdx ? 1.0f-yf : yf;
698 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
699 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
700 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
701 float lod = triLod[triNdx];
703 dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
708 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params)
710 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
711 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
712 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
714 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
715 sampleTextureNonProjected(dst, src, sq, tq, rq, params);
718 static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
720 // Separate combined DS formats
721 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
722 const tcu::Texture1DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
724 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
726 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
727 deInt32 srcSize = src.getWidth();
729 // Coordinates and lod per triangle.
730 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
731 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
732 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
733 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
735 for (int y = 0; y < dst.getHeight(); y++)
737 for (int x = 0; x < dst.getWidth(); x++)
739 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
740 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
742 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
743 float triX = triNdx ? 1.0f-xf : xf;
744 float triY = triNdx ? 1.0f-yf : yf;
746 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
747 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
748 float lod = triLod[triNdx];
750 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
755 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params)
757 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
758 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
760 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
761 sampleTextureNonProjected(dst, src, sq, tq, params);
764 static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
766 // Separate combined DS formats
767 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
768 const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
770 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
772 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
773 tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
775 // Coordinates and lod per triangle.
776 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
777 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
778 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
779 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod),
780 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) };
782 for (int y = 0; y < dst.getHeight(); y++)
784 for (int x = 0; x < dst.getWidth(); x++)
786 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
787 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
789 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
790 float triX = triNdx ? 1.0f-xf : xf;
791 float triY = triNdx ? 1.0f-yf : yf;
793 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
794 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
795 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
796 float lod = triLod[triNdx];
798 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
803 static void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
805 // Separate combined DS formats
806 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
807 const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
809 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
810 float dstW = (float)dst.getWidth();
811 float dstH = (float)dst.getHeight();
813 tcu::Vec4 uq = sq * (float)src.getWidth();
814 tcu::Vec4 vq = tq * (float)src.getHeight();
815 tcu::Vec4 wq = rq * (float)src.getDepth();
817 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
818 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
819 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
820 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
821 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
822 tcu::Vec3 triW[2] = { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) };
823 tcu::Vec3 triP[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
825 for (int py = 0; py < dst.getHeight(); py++)
827 for (int px = 0; px < dst.getWidth(); px++)
829 float wx = (float)px + 0.5f;
830 float wy = (float)py + 0.5f;
831 float nx = wx / dstW;
832 float ny = wy / dstH;
834 int triNdx = nx + ny >= 1.0f ? 1 : 0;
835 float triWx = triNdx ? dstW - wx : wx;
836 float triWy = triNdx ? dstH - wy : wy;
837 float triNx = triNdx ? 1.0f - nx : nx;
838 float triNy = triNdx ? 1.0f - ny : ny;
840 float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
841 float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
842 float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
843 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
846 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
851 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params)
853 const tcu::Texture3DView view = getSubView(src, params.baseLevel, params.maxLevel);
854 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
855 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
856 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
858 if (params.flags & ReferenceParams::PROJECTED)
859 sampleTextureProjected(dst, view, sq, tq, rq, params);
861 sampleTextureNonProjected(dst, view, sq, tq, rq, params);
864 static void sampleTextureCubeArray (const tcu::SurfaceAccess& dst, const tcu::TextureCubeArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const tcu::Vec4& qq, const ReferenceParams& params)
866 // Separate combined DS formats
867 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
868 const tcu::TextureCubeArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
870 const float dstW = (float)dst.getWidth();
871 const float dstH = (float)dst.getHeight();
873 // Coordinates per triangle.
874 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
875 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
876 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
877 tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
878 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
880 const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
882 for (int py = 0; py < dst.getHeight(); py++)
884 for (int px = 0; px < dst.getWidth(); px++)
886 const float wx = (float)px + 0.5f;
887 const float wy = (float)py + 0.5f;
888 const float nx = wx / dstW;
889 const float ny = wy / dstH;
891 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
892 const float triNx = triNdx ? 1.0f - nx : nx;
893 const float triNy = triNdx ? 1.0f - ny : ny;
895 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
896 triangleInterpolate(triT[triNdx], triNx, triNy),
897 triangleInterpolate(triR[triNdx], triNx, triNy));
899 const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy);
901 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
902 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
903 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
904 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
905 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
906 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
908 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
910 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
915 void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params)
917 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
918 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
919 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
920 tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
922 sampleTextureCubeArray(dst, src, sq, tq, rq, qq, params);
925 void fetchTexture (const tcu::SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias)
927 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
928 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
930 for (int y = 0; y < dst.getHeight(); y++)
932 for (int x = 0; x < dst.getWidth(); x++)
934 const float yf = ((float)y + 0.5f) / (float)dst.getHeight();
935 const float xf = ((float)x + 0.5f) / (float)dst.getWidth();
937 const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
938 const float triX = triNdx ? 1.0f-xf : xf;
939 const float triY = triNdx ? 1.0f-yf : yf;
941 const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
943 dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
948 bool compareImages (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
950 return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
953 bool compareImages (tcu::TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
955 return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
958 int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
960 return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
963 inline int rangeDiff (int x, int a, int b)
973 inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
975 int rMin = de::min(a.getRed(), b.getRed());
976 int rMax = de::max(a.getRed(), b.getRed());
977 int gMin = de::min(a.getGreen(), b.getGreen());
978 int gMax = de::max(a.getGreen(), b.getGreen());
979 int bMin = de::min(a.getBlue(), b.getBlue());
980 int bMax = de::max(a.getBlue(), b.getBlue());
981 int aMin = de::min(a.getAlpha(), b.getAlpha());
982 int aMax = de::max(a.getAlpha(), b.getAlpha());
984 return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax),
985 rangeDiff(p.getGreen(), gMin, gMax),
986 rangeDiff(p.getBlue(), bMin, bMax),
987 rangeDiff(p.getAlpha(), aMin, aMax));
990 inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
992 tcu::RGBA diff = rangeDiff(p, a, b);
993 return diff.getRed() <= threshold.getRed() &&
994 diff.getGreen() <= threshold.getGreen() &&
995 diff.getBlue() <= threshold.getBlue() &&
996 diff.getAlpha() <= threshold.getAlpha();
999 void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
1009 void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
1013 dst[0] = left; dst[1] = (float)layerNdx;
1014 dst[2] = left; dst[3] = (float)layerNdx;
1015 dst[4] = right; dst[5] = (float)layerNdx;
1016 dst[6] = right; dst[7] = (float)layerNdx;
1019 void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1023 dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y();
1024 dst[2] = bottomLeft.x(); dst[3] = topRight.y();
1025 dst[4] = topRight.x(); dst[5] = bottomLeft.y();
1026 dst[6] = topRight.x(); dst[7] = topRight.y();
1029 void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1033 dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx;
1034 dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx;
1035 dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx;
1036 dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx;
1039 void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
1041 tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1042 tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1043 tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1044 tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1046 tcu::Vec3 v0 = p0 + (p1-p0)*f0;
1047 tcu::Vec3 v1 = p0 + (p1-p0)*f1;
1048 tcu::Vec3 v2 = p0 + (p1-p0)*f2;
1049 tcu::Vec3 v3 = p0 + (p1-p0)*f3;
1053 dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
1054 dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
1055 dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
1056 dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
1059 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
1061 static const float texCoordNegX[] =
1064 -1.0f, -1.0f, -1.0f,
1068 static const float texCoordPosX[] =
1075 static const float texCoordNegY[] =
1078 -1.0f, -1.0f, -1.0f,
1082 static const float texCoordPosY[] =
1084 -1.0f, +1.0f, -1.0f,
1089 static const float texCoordNegZ[] =
1096 static const float texCoordPosZ[] =
1099 -1.0f, -1.0f, +1.0f,
1104 const float* texCoord = DE_NULL;
1105 int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX);
1109 case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
1110 case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
1111 case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
1112 case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
1113 case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
1114 case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
1116 DE_ASSERT(DE_FALSE);
1120 dst.resize(texCoordSize);
1121 std::copy(texCoord, texCoord+texCoordSize, dst.begin());
1124 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1135 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1136 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1137 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1138 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1139 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1140 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1142 DE_ASSERT(DE_FALSE);
1148 dst[0+mRow] = mSign;
1149 dst[3+mRow] = mSign;
1150 dst[6+mRow] = mSign;
1151 dst[9+mRow] = mSign;
1153 dst[0+sRow] = sSign * bottomLeft.x();
1154 dst[3+sRow] = sSign * bottomLeft.x();
1155 dst[6+sRow] = sSign * topRight.x();
1156 dst[9+sRow] = sSign * topRight.x();
1158 dst[0+tRow] = tSign * bottomLeft.y();
1159 dst[3+tRow] = tSign * topRight.y();
1160 dst[6+tRow] = tSign * bottomLeft.y();
1161 dst[9+tRow] = tSign * topRight.y();
1164 void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
1173 const float l0 = layerRange.x();
1174 const float l1 = layerRange.y();
1178 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1179 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1180 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1181 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1182 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1183 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1185 DE_ASSERT(DE_FALSE);
1191 dst[ 0+mRow] = mSign;
1192 dst[ 4+mRow] = mSign;
1193 dst[ 8+mRow] = mSign;
1194 dst[12+mRow] = mSign;
1196 dst[ 0+sRow] = sSign * bottomLeft.x();
1197 dst[ 4+sRow] = sSign * bottomLeft.x();
1198 dst[ 8+sRow] = sSign * topRight.x();
1199 dst[12+sRow] = sSign * topRight.x();
1201 dst[ 0+tRow] = tSign * bottomLeft.y();
1202 dst[ 4+tRow] = tSign * topRight.y();
1203 dst[ 8+tRow] = tSign * bottomLeft.y();
1204 dst[12+tRow] = tSign * topRight.y();
1209 dst[ 4+qRow] = l0*0.5f + l1*0.5f;
1210 dst[ 8+qRow] = l0*0.5f + l1*0.5f;
1222 // Texture result verification
1224 //! Verifies texture lookup results and returns number of failed pixels.
1225 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1226 const tcu::ConstPixelBufferAccess& reference,
1227 const tcu::PixelBufferAccess& errorMask,
1228 const tcu::Texture1DView& baseView,
1229 const float* texCoord,
1230 const ReferenceParams& sampleParams,
1231 const tcu::LookupPrecision& lookupPrec,
1232 const tcu::LodPrecision& lodPrec,
1233 qpWatchDog* watchDog)
1235 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1236 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1238 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1239 const tcu::Texture1DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1241 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1243 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1244 const float dstW = float(dstSize.x());
1245 const float dstH = float(dstSize.y());
1246 const int srcSize = src.getWidth();
1248 // Coordinates and lod per triangle.
1249 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1250 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1252 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1256 const tcu::Vec2 lodOffsets[] =
1264 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1266 for (int py = 0; py < result.getHeight(); py++)
1268 // Ugly hack, validation can take way too long at the moment.
1270 qpWatchDog_touch(watchDog);
1272 for (int px = 0; px < result.getWidth(); px++)
1274 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1275 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1277 // Try comparison to ideal reference first, and if that fails use slower verificator.
1278 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1280 const float wx = (float)px + 0.5f;
1281 const float wy = (float)py + 0.5f;
1282 const float nx = wx / dstW;
1283 const float ny = wy / dstH;
1285 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1286 const float triWx = triNdx ? dstW - wx : wx;
1287 const float triWy = triNdx ? dstH - wy : wy;
1288 const float triNx = triNdx ? 1.0f - nx : nx;
1289 const float triNy = triNdx ? 1.0f - ny : ny;
1291 const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1292 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1293 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1295 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1297 // Compute lod bounds across lodOffsets range.
1298 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1300 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1301 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1302 const float nxo = wxo/dstW;
1303 const float nyo = wyo/dstH;
1305 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1306 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1307 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1309 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1310 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1313 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1314 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1318 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1328 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1329 const tcu::ConstPixelBufferAccess& reference,
1330 const tcu::PixelBufferAccess& errorMask,
1331 const tcu::Texture2DView& baseView,
1332 const float* texCoord,
1333 const ReferenceParams& sampleParams,
1334 const tcu::LookupPrecision& lookupPrec,
1335 const tcu::LodPrecision& lodPrec,
1336 qpWatchDog* watchDog)
1338 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1339 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1341 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1342 const tcu::Texture2DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1344 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1345 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1347 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1348 const float dstW = float(dstSize.x());
1349 const float dstH = float(dstSize.y());
1350 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
1352 // Coordinates and lod per triangle.
1353 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1354 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1355 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1357 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1361 const tcu::Vec2 lodOffsets[] =
1369 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1371 for (int py = 0; py < result.getHeight(); py++)
1373 // Ugly hack, validation can take way too long at the moment.
1375 qpWatchDog_touch(watchDog);
1377 for (int px = 0; px < result.getWidth(); px++)
1379 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1380 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1382 // Try comparison to ideal reference first, and if that fails use slower verificator.
1383 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1385 const float wx = (float)px + 0.5f;
1386 const float wy = (float)py + 0.5f;
1387 const float nx = wx / dstW;
1388 const float ny = wy / dstH;
1390 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1391 const float triWx = triNdx ? dstW - wx : wx;
1392 const float triWy = triNdx ? dstH - wy : wy;
1393 const float triNx = triNdx ? 1.0f - nx : nx;
1394 const float triNy = triNdx ? 1.0f - ny : ny;
1396 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1397 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1398 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1399 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1400 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1401 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1403 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1405 // Compute lod bounds across lodOffsets range.
1406 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1408 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1409 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1410 const float nxo = wxo/dstW;
1411 const float nyo = wyo/dstH;
1413 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1414 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1415 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1416 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1417 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1419 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1420 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1423 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1424 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1428 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1438 bool verifyTextureResult (tcu::TestContext& testCtx,
1439 const tcu::ConstPixelBufferAccess& result,
1440 const tcu::Texture1DView& src,
1441 const float* texCoord,
1442 const ReferenceParams& sampleParams,
1443 const tcu::LookupPrecision& lookupPrec,
1444 const tcu::LodPrecision& lodPrec,
1445 const tcu::PixelFormat& pixelFormat)
1447 tcu::TestLog& log = testCtx.getLog();
1448 tcu::Surface reference (result.getWidth(), result.getHeight());
1449 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1450 int numFailedPixels;
1452 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1454 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1455 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1457 if (numFailedPixels > 0)
1458 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1460 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1461 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1463 if (numFailedPixels > 0)
1465 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1466 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1469 log << tcu::TestLog::EndImageSet;
1471 return numFailedPixels == 0;
1474 bool verifyTextureResult (tcu::TestContext& testCtx,
1475 const tcu::ConstPixelBufferAccess& result,
1476 const tcu::Texture2DView& src,
1477 const float* texCoord,
1478 const ReferenceParams& sampleParams,
1479 const tcu::LookupPrecision& lookupPrec,
1480 const tcu::LodPrecision& lodPrec,
1481 const tcu::PixelFormat& pixelFormat)
1483 tcu::TestLog& log = testCtx.getLog();
1484 tcu::Surface reference (result.getWidth(), result.getHeight());
1485 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1486 int numFailedPixels;
1488 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1490 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1491 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1493 if (numFailedPixels > 0)
1494 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1496 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1497 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1499 if (numFailedPixels > 0)
1501 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1502 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1505 log << tcu::TestLog::EndImageSet;
1507 return numFailedPixels == 0;
1510 //! Verifies texture lookup results and returns number of failed pixels.
1511 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1512 const tcu::ConstPixelBufferAccess& reference,
1513 const tcu::PixelBufferAccess& errorMask,
1514 const tcu::TextureCubeView& baseView,
1515 const float* texCoord,
1516 const ReferenceParams& sampleParams,
1517 const tcu::LookupPrecision& lookupPrec,
1518 const tcu::LodPrecision& lodPrec,
1519 qpWatchDog* watchDog)
1521 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1522 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1524 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1525 const tcu::TextureCubeView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1527 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1528 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1529 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1531 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1532 const float dstW = float(dstSize.x());
1533 const float dstH = float(dstSize.y());
1534 const int srcSize = src.getSize();
1536 // Coordinates per triangle.
1537 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1538 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1539 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1540 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1542 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1544 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1548 const tcu::Vec2 lodOffsets[] =
1555 // \note Not strictly allowed by spec, but implementations do this in practice.
1562 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1564 for (int py = 0; py < result.getHeight(); py++)
1566 // Ugly hack, validation can take way too long at the moment.
1568 qpWatchDog_touch(watchDog);
1570 for (int px = 0; px < result.getWidth(); px++)
1572 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1573 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1575 // Try comparison to ideal reference first, and if that fails use slower verificator.
1576 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1578 const float wx = (float)px + 0.5f;
1579 const float wy = (float)py + 0.5f;
1580 const float nx = wx / dstW;
1581 const float ny = wy / dstH;
1583 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1584 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1588 DE_ASSERT(tri0 || tri1);
1590 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1591 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1593 const float triWx = triNdx ? dstW - wx : wx;
1594 const float triWy = triNdx ? dstH - wy : wy;
1595 const float triNx = triNdx ? 1.0f - nx : nx;
1596 const float triNy = triNdx ? 1.0f - ny : ny;
1598 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1599 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1600 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1601 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1602 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1603 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
1604 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1605 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1606 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
1608 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
1610 // Compute lod bounds across lodOffsets range.
1611 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1613 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1614 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1615 const float nxo = wxo/dstW;
1616 const float nyo = wyo/dstH;
1618 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
1619 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
1620 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
1621 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1622 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1623 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
1624 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1625 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1626 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
1627 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
1629 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1630 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1633 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1635 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1644 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1654 bool verifyTextureResult (tcu::TestContext& testCtx,
1655 const tcu::ConstPixelBufferAccess& result,
1656 const tcu::TextureCubeView& src,
1657 const float* texCoord,
1658 const ReferenceParams& sampleParams,
1659 const tcu::LookupPrecision& lookupPrec,
1660 const tcu::LodPrecision& lodPrec,
1661 const tcu::PixelFormat& pixelFormat)
1663 tcu::TestLog& log = testCtx.getLog();
1664 tcu::Surface reference (result.getWidth(), result.getHeight());
1665 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1666 int numFailedPixels;
1668 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1670 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1671 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1673 if (numFailedPixels > 0)
1674 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1676 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1677 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1679 if (numFailedPixels > 0)
1681 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1682 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1685 log << tcu::TestLog::EndImageSet;
1687 return numFailedPixels == 0;
1690 //! Verifies texture lookup results and returns number of failed pixels.
1691 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1692 const tcu::ConstPixelBufferAccess& reference,
1693 const tcu::PixelBufferAccess& errorMask,
1694 const tcu::Texture3DView& baseView,
1695 const float* texCoord,
1696 const ReferenceParams& sampleParams,
1697 const tcu::LookupPrecision& lookupPrec,
1698 const tcu::LodPrecision& lodPrec,
1699 qpWatchDog* watchDog)
1701 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1702 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1704 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1705 const tcu::Texture3DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1707 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1708 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1709 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1711 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1712 const float dstW = float(dstSize.x());
1713 const float dstH = float(dstSize.y());
1714 const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
1716 // Coordinates and lod per triangle.
1717 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1718 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1719 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1720 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1722 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1724 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1728 const tcu::Vec2 lodOffsets[] =
1736 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1738 for (int py = 0; py < result.getHeight(); py++)
1740 // Ugly hack, validation can take way too long at the moment.
1742 qpWatchDog_touch(watchDog);
1744 for (int px = 0; px < result.getWidth(); px++)
1746 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1747 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1749 // Try comparison to ideal reference first, and if that fails use slower verificator.
1750 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1752 const float wx = (float)px + 0.5f;
1753 const float wy = (float)py + 0.5f;
1754 const float nx = wx / dstW;
1755 const float ny = wy / dstH;
1757 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1758 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1762 DE_ASSERT(tri0 || tri1);
1764 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1765 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1767 const float triWx = triNdx ? dstW - wx : wx;
1768 const float triWy = triNdx ? dstH - wy : wy;
1769 const float triNx = triNdx ? 1.0f - nx : nx;
1770 const float triNy = triNdx ? 1.0f - ny : ny;
1772 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1773 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1774 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1775 const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1776 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1777 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1778 const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1779 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1780 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1782 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
1784 // Compute lod bounds across lodOffsets range.
1785 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1787 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1788 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1789 const float nxo = wxo/dstW;
1790 const float nyo = wyo/dstH;
1792 const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1793 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1794 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1795 const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1796 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1797 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1798 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
1800 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1801 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1804 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1806 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1815 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1825 bool verifyTextureResult (tcu::TestContext& testCtx,
1826 const tcu::ConstPixelBufferAccess& result,
1827 const tcu::Texture3DView& src,
1828 const float* texCoord,
1829 const ReferenceParams& sampleParams,
1830 const tcu::LookupPrecision& lookupPrec,
1831 const tcu::LodPrecision& lodPrec,
1832 const tcu::PixelFormat& pixelFormat)
1834 tcu::TestLog& log = testCtx.getLog();
1835 tcu::Surface reference (result.getWidth(), result.getHeight());
1836 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1837 int numFailedPixels;
1839 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1841 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1842 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1844 if (numFailedPixels > 0)
1845 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1847 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1848 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1850 if (numFailedPixels > 0)
1852 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1853 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1856 log << tcu::TestLog::EndImageSet;
1858 return numFailedPixels == 0;
1861 //! Verifies texture lookup results and returns number of failed pixels.
1862 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1863 const tcu::ConstPixelBufferAccess& reference,
1864 const tcu::PixelBufferAccess& errorMask,
1865 const tcu::Texture1DArrayView& baseView,
1866 const float* texCoord,
1867 const ReferenceParams& sampleParams,
1868 const tcu::LookupPrecision& lookupPrec,
1869 const tcu::LodPrecision& lodPrec,
1870 qpWatchDog* watchDog)
1872 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1873 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1875 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1876 const tcu::Texture1DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
1878 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1879 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1881 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1882 const float dstW = float(dstSize.x());
1883 const float dstH = float(dstSize.y());
1884 const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored.
1886 // Coordinates and lod per triangle.
1887 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1888 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1889 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1891 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1895 const tcu::Vec2 lodOffsets[] =
1903 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1905 for (int py = 0; py < result.getHeight(); py++)
1907 // Ugly hack, validation can take way too long at the moment.
1909 qpWatchDog_touch(watchDog);
1911 for (int px = 0; px < result.getWidth(); px++)
1913 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1914 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1916 // Try comparison to ideal reference first, and if that fails use slower verificator.
1917 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1919 const float wx = (float)px + 0.5f;
1920 const float wy = (float)py + 0.5f;
1921 const float nx = wx / dstW;
1922 const float ny = wy / dstH;
1924 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1925 const float triWx = triNdx ? dstW - wx : wx;
1926 const float triWy = triNdx ? dstH - wy : wy;
1927 const float triNx = triNdx ? 1.0f - nx : nx;
1928 const float triNy = triNdx ? 1.0f - ny : ny;
1930 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1931 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1932 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
1933 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
1935 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1937 // Compute lod bounds across lodOffsets range.
1938 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1940 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1941 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1942 const float nxo = wxo/dstW;
1943 const float nyo = wyo/dstH;
1945 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
1946 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
1947 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1949 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1950 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1953 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1954 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1958 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1968 //! Verifies texture lookup results and returns number of failed pixels.
1969 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1970 const tcu::ConstPixelBufferAccess& reference,
1971 const tcu::PixelBufferAccess& errorMask,
1972 const tcu::Texture2DArrayView& baseView,
1973 const float* texCoord,
1974 const ReferenceParams& sampleParams,
1975 const tcu::LookupPrecision& lookupPrec,
1976 const tcu::LodPrecision& lodPrec,
1977 qpWatchDog* watchDog)
1979 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1980 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1982 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1983 const tcu::Texture2DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
1985 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1986 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1987 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1989 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1990 const float dstW = float(dstSize.x());
1991 const float dstH = float(dstSize.y());
1992 const tcu::Vec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
1994 // Coordinates and lod per triangle.
1995 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1996 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1997 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1998 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2000 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2004 const tcu::Vec2 lodOffsets[] =
2012 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2014 for (int py = 0; py < result.getHeight(); py++)
2016 // Ugly hack, validation can take way too long at the moment.
2018 qpWatchDog_touch(watchDog);
2020 for (int px = 0; px < result.getWidth(); px++)
2022 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2023 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2025 // Try comparison to ideal reference first, and if that fails use slower verificator.
2026 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2028 const float wx = (float)px + 0.5f;
2029 const float wy = (float)py + 0.5f;
2030 const float nx = wx / dstW;
2031 const float ny = wy / dstH;
2033 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2034 const float triWx = triNdx ? dstW - wx : wx;
2035 const float triWy = triNdx ? dstH - wy : wy;
2036 const float triNx = triNdx ? 1.0f - nx : nx;
2037 const float triNy = triNdx ? 1.0f - ny : ny;
2039 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2040 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2041 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2042 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2043 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2044 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2045 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2047 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2049 // Compute lod bounds across lodOffsets range.
2050 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2052 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2053 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2054 const float nxo = wxo/dstW;
2055 const float nyo = wyo/dstH;
2057 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2058 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2059 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2060 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2061 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2063 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2064 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2067 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2068 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2072 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2082 bool verifyTextureResult (tcu::TestContext& testCtx,
2083 const tcu::ConstPixelBufferAccess& result,
2084 const tcu::Texture1DArrayView& src,
2085 const float* texCoord,
2086 const ReferenceParams& sampleParams,
2087 const tcu::LookupPrecision& lookupPrec,
2088 const tcu::LodPrecision& lodPrec,
2089 const tcu::PixelFormat& pixelFormat)
2091 tcu::TestLog& log = testCtx.getLog();
2092 tcu::Surface reference (result.getWidth(), result.getHeight());
2093 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2094 int numFailedPixels;
2096 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2098 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2099 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2101 if (numFailedPixels > 0)
2102 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2104 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2105 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2107 if (numFailedPixels > 0)
2109 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2110 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2113 log << tcu::TestLog::EndImageSet;
2115 return numFailedPixels == 0;
2118 bool verifyTextureResult (tcu::TestContext& testCtx,
2119 const tcu::ConstPixelBufferAccess& result,
2120 const tcu::Texture2DArrayView& src,
2121 const float* texCoord,
2122 const ReferenceParams& sampleParams,
2123 const tcu::LookupPrecision& lookupPrec,
2124 const tcu::LodPrecision& lodPrec,
2125 const tcu::PixelFormat& pixelFormat)
2127 tcu::TestLog& log = testCtx.getLog();
2128 tcu::Surface reference (result.getWidth(), result.getHeight());
2129 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2130 int numFailedPixels;
2132 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2134 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2135 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2137 if (numFailedPixels > 0)
2138 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2140 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2141 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2143 if (numFailedPixels > 0)
2145 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2146 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2149 log << tcu::TestLog::EndImageSet;
2151 return numFailedPixels == 0;
2154 //! Verifies texture lookup results and returns number of failed pixels.
2155 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2156 const tcu::ConstPixelBufferAccess& reference,
2157 const tcu::PixelBufferAccess& errorMask,
2158 const tcu::TextureCubeArrayView& baseView,
2159 const float* texCoord,
2160 const ReferenceParams& sampleParams,
2161 const tcu::LookupPrecision& lookupPrec,
2162 const tcu::IVec4& coordBits,
2163 const tcu::LodPrecision& lodPrec,
2164 qpWatchDog* watchDog)
2166 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2167 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2169 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2170 const tcu::TextureCubeArrayView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
2172 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2173 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2174 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2175 const tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2177 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2178 const float dstW = float(dstSize.x());
2179 const float dstH = float(dstSize.y());
2180 const int srcSize = src.getSize();
2182 // Coordinates per triangle.
2183 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2184 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2185 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2186 const tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2187 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2189 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2191 const float posEps = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2195 const tcu::Vec2 lodOffsets[] =
2202 // \note Not strictly allowed by spec, but implementations do this in practice.
2209 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2211 for (int py = 0; py < result.getHeight(); py++)
2213 // Ugly hack, validation can take way too long at the moment.
2215 qpWatchDog_touch(watchDog);
2217 for (int px = 0; px < result.getWidth(); px++)
2219 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2220 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2222 // Try comparison to ideal reference first, and if that fails use slower verificator.
2223 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2225 const float wx = (float)px + 0.5f;
2226 const float wy = (float)py + 0.5f;
2227 const float nx = wx / dstW;
2228 const float ny = wy / dstH;
2230 const bool tri0 = nx + ny - posEps <= 1.0f;
2231 const bool tri1 = nx + ny + posEps >= 1.0f;
2235 DE_ASSERT(tri0 || tri1);
2237 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2238 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2240 const float triWx = triNdx ? dstW - wx : wx;
2241 const float triWy = triNdx ? dstH - wy : wy;
2242 const float triNx = triNdx ? 1.0f - nx : nx;
2243 const float triNy = triNdx ? 1.0f - ny : ny;
2245 const tcu::Vec4 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2246 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2247 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2248 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2249 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2250 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2251 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2252 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2253 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2254 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2256 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2258 // Compute lod bounds across lodOffsets range.
2259 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2261 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2262 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2263 const float nxo = wxo/dstW;
2264 const float nyo = wyo/dstH;
2266 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2267 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2268 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2269 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2270 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2271 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2272 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2273 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2274 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2275 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2277 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2278 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2281 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2283 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2292 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2302 bool verifyTextureResult (tcu::TestContext& testCtx,
2303 const tcu::ConstPixelBufferAccess& result,
2304 const tcu::TextureCubeArrayView& src,
2305 const float* texCoord,
2306 const ReferenceParams& sampleParams,
2307 const tcu::LookupPrecision& lookupPrec,
2308 const tcu::IVec4& coordBits,
2309 const tcu::LodPrecision& lodPrec,
2310 const tcu::PixelFormat& pixelFormat)
2312 tcu::TestLog& log = testCtx.getLog();
2313 tcu::Surface reference (result.getWidth(), result.getHeight());
2314 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2315 int numFailedPixels;
2317 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2319 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2320 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2322 if (numFailedPixels > 0)
2323 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2325 log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2326 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2328 if (numFailedPixels > 0)
2330 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2331 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2334 log << tcu::TestLog::EndImageSet;
2336 return numFailedPixels == 0;
2339 // Shadow lookup verification
2341 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2342 const tcu::ConstPixelBufferAccess& reference,
2343 const tcu::PixelBufferAccess& errorMask,
2344 const tcu::Texture2DView& src,
2345 const float* texCoord,
2346 const ReferenceParams& sampleParams,
2347 const tcu::TexComparePrecision& comparePrec,
2348 const tcu::LodPrecision& lodPrec,
2349 const tcu::Vec3& nonShadowThreshold)
2351 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2352 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2354 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2355 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2357 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2358 const float dstW = float(dstSize.x());
2359 const float dstH = float(dstSize.y());
2360 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2362 // Coordinates and lod per triangle.
2363 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2364 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2365 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2367 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2371 const tcu::Vec2 lodOffsets[] =
2379 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2381 for (int py = 0; py < result.getHeight(); py++)
2383 for (int px = 0; px < result.getWidth(); px++)
2385 const tcu::Vec4 resPix = result.getPixel(px, py);
2386 const tcu::Vec4 refPix = reference.getPixel(px, py);
2388 // Other channels should trivially match to reference.
2389 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2391 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2396 // Reference result is known to be a valid result, we can
2397 // skip verification if thes results are equal
2398 if (resPix.x() != refPix.x())
2400 const float wx = (float)px + 0.5f;
2401 const float wy = (float)py + 0.5f;
2402 const float nx = wx / dstW;
2403 const float ny = wy / dstH;
2405 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2406 const float triWx = triNdx ? dstW - wx : wx;
2407 const float triWy = triNdx ? dstH - wy : wy;
2408 const float triNx = triNdx ? 1.0f - nx : nx;
2409 const float triNy = triNdx ? 1.0f - ny : ny;
2411 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2412 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2413 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2414 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2415 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2416 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2418 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2420 // Compute lod bounds across lodOffsets range.
2421 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2423 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2424 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2425 const float nxo = wxo/dstW;
2426 const float nyo = wyo/dstH;
2428 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2429 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2430 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2431 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2432 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2434 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2435 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2438 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2439 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2443 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2453 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2454 const tcu::ConstPixelBufferAccess& reference,
2455 const tcu::PixelBufferAccess& errorMask,
2456 const tcu::TextureCubeView& src,
2457 const float* texCoord,
2458 const ReferenceParams& sampleParams,
2459 const tcu::TexComparePrecision& comparePrec,
2460 const tcu::LodPrecision& lodPrec,
2461 const tcu::Vec3& nonShadowThreshold)
2463 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2464 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2466 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2467 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2468 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2470 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2471 const float dstW = float(dstSize.x());
2472 const float dstH = float(dstSize.y());
2473 const int srcSize = src.getSize();
2475 // Coordinates per triangle.
2476 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2477 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2478 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2479 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2481 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2485 const tcu::Vec2 lodOffsets[] =
2493 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2495 for (int py = 0; py < result.getHeight(); py++)
2497 for (int px = 0; px < result.getWidth(); px++)
2499 const tcu::Vec4 resPix = result.getPixel(px, py);
2500 const tcu::Vec4 refPix = reference.getPixel(px, py);
2502 // Other channels should trivially match to reference.
2503 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2505 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2510 // Reference result is known to be a valid result, we can
2511 // skip verification if thes results are equal
2512 if (resPix.x() != refPix.x())
2514 const float wx = (float)px + 0.5f;
2515 const float wy = (float)py + 0.5f;
2516 const float nx = wx / dstW;
2517 const float ny = wy / dstH;
2519 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2520 const float triWx = triNdx ? dstW - wx : wx;
2521 const float triWy = triNdx ? dstH - wy : wy;
2522 const float triNx = triNdx ? 1.0f - nx : nx;
2523 const float triNy = triNdx ? 1.0f - ny : ny;
2525 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2526 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2527 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2528 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2529 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2530 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2531 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2532 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2533 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2535 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2537 // Compute lod bounds across lodOffsets range.
2538 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2540 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2541 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2542 const float nxo = wxo/dstW;
2543 const float nyo = wyo/dstH;
2545 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2546 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2547 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2548 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2549 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2550 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2551 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2552 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2553 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2554 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2556 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2557 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2560 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2561 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2565 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2575 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2576 const tcu::ConstPixelBufferAccess& reference,
2577 const tcu::PixelBufferAccess& errorMask,
2578 const tcu::Texture2DArrayView& src,
2579 const float* texCoord,
2580 const ReferenceParams& sampleParams,
2581 const tcu::TexComparePrecision& comparePrec,
2582 const tcu::LodPrecision& lodPrec,
2583 const tcu::Vec3& nonShadowThreshold)
2585 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2586 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2588 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2589 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2590 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2592 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2593 const float dstW = float(dstSize.x());
2594 const float dstH = float(dstSize.y());
2595 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2597 // Coordinates and lod per triangle.
2598 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2599 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2600 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2601 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2603 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2607 const tcu::Vec2 lodOffsets[] =
2615 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2617 for (int py = 0; py < result.getHeight(); py++)
2619 for (int px = 0; px < result.getWidth(); px++)
2621 const tcu::Vec4 resPix = result.getPixel(px, py);
2622 const tcu::Vec4 refPix = reference.getPixel(px, py);
2624 // Other channels should trivially match to reference.
2625 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2627 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2632 // Reference result is known to be a valid result, we can
2633 // skip verification if thes results are equal
2634 if (resPix.x() != refPix.x())
2636 const float wx = (float)px + 0.5f;
2637 const float wy = (float)py + 0.5f;
2638 const float nx = wx / dstW;
2639 const float ny = wy / dstH;
2641 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2642 const float triWx = triNdx ? dstW - wx : wx;
2643 const float triWy = triNdx ? dstH - wy : wy;
2644 const float triNx = triNdx ? 1.0f - nx : nx;
2645 const float triNy = triNdx ? 1.0f - ny : ny;
2647 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2648 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2649 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2650 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2651 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2652 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2653 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2655 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2657 // Compute lod bounds across lodOffsets range.
2658 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2660 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2661 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2662 const float nxo = wxo/dstW;
2663 const float nyo = wyo/dstH;
2665 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2666 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2667 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2668 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2669 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2671 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2672 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2675 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2676 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2680 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2690 // Mipmap generation comparison.
2692 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2694 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2696 const float dstW = float(dst.getWidth());
2697 const float dstH = float(dst.getHeight());
2698 const float srcW = float(src.getWidth());
2699 const float srcH = float(src.getHeight());
2702 // Translation to lookup verification parameters.
2703 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
2704 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
2705 tcu::LookupPrecision lookupPrec;
2707 lookupPrec.colorThreshold = precision.colorThreshold;
2708 lookupPrec.colorMask = precision.colorMask;
2709 lookupPrec.coordBits = tcu::IVec3(22);
2710 lookupPrec.uvwBits = precision.filterBits;
2712 for (int y = 0; y < dst.getHeight(); y++)
2713 for (int x = 0; x < dst.getWidth(); x++)
2715 const tcu::Vec4 result = dst.getPixel(x, y);
2716 const float cx = (float(x)+0.5f) / dstW * srcW;
2717 const float cy = (float(y)+0.5f) / dstH * srcH;
2718 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
2720 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2728 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2730 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2732 const float dstW = float(dst.getWidth());
2733 const float dstH = float(dst.getHeight());
2734 const float srcW = float(src.getWidth());
2735 const float srcH = float(src.getHeight());
2738 // Translation to lookup verification parameters.
2739 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
2740 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
2741 tcu::LookupPrecision lookupPrec;
2743 lookupPrec.colorThreshold = precision.colorThreshold;
2744 lookupPrec.colorMask = precision.colorMask;
2745 lookupPrec.coordBits = tcu::IVec3(22);
2746 lookupPrec.uvwBits = precision.filterBits;
2748 for (int y = 0; y < dst.getHeight(); y++)
2749 for (int x = 0; x < dst.getWidth(); x++)
2751 const tcu::Vec4 result = dst.getPixel(x, y);
2752 const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
2753 const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
2754 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
2756 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2764 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2766 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2767 DE_UNREF(precision);
2769 const float dstW = float(dst.getWidth());
2770 const float dstH = float(dst.getHeight());
2771 const float srcW = float(src.getWidth());
2772 const float srcH = float(src.getHeight());
2775 for (int y = 0; y < dst.getHeight(); y++)
2776 for (int x = 0; x < dst.getWidth(); x++)
2778 const tcu::Vec4 result = dst.getPixel(x, y);
2779 const int minX = deFloorFloatToInt32(((float)x-0.5f) / dstW * srcW);
2780 const int minY = deFloorFloatToInt32(((float)y-0.5f) / dstH * srcH);
2781 const int maxX = deCeilFloatToInt32(((float)x+1.5f) / dstW * srcW);
2782 const int maxY = deCeilFloatToInt32(((float)y+1.5f) / dstH * srcH);
2783 tcu::Vec4 minVal, maxVal;
2786 DE_ASSERT(minX < maxX && minY < maxY);
2788 for (int ky = minY; ky <= maxY; ky++)
2790 for (int kx = minX; kx <= maxX; kx++)
2792 const int sx = de::clamp(kx, 0, src.getWidth()-1);
2793 const int sy = de::clamp(ky, 0, src.getHeight()-1);
2794 const tcu::Vec4 sample = src.getPixel(sx, sy);
2796 if (ky == minY && kx == minX)
2803 minVal = min(sample, minVal);
2804 maxVal = max(sample, maxVal);
2809 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
2811 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2819 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
2821 qpTestResult result = QP_TEST_RESULT_PASS;
2823 // Special comparison for level 0.
2825 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
2826 const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
2830 log << tcu::TestLog::Message << "ERROR: Level 0 comparison failed!" << tcu::TestLog::EndMessage;
2831 result = QP_TEST_RESULT_FAIL;
2835 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
2837 const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx-1);
2838 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx);
2839 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
2840 bool levelOk = false;
2842 // Try different comparisons in quality order.
2846 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
2850 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2855 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
2859 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2862 // At this point all high-quality methods have been used.
2863 if (!levelOk && result == QP_TEST_RESULT_PASS)
2864 result = QP_TEST_RESULT_QUALITY_WARNING;
2868 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
2872 log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
2876 result = QP_TEST_RESULT_FAIL;
2878 log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
2879 << tcu::TestLog::Image("Result", "Result", dst);
2882 log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2884 log << tcu::TestLog::EndImageSet;
2890 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
2892 qpTestResult result = QP_TEST_RESULT_PASS;
2894 static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
2895 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
2897 // Special comparison for level 0.
2898 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
2900 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
2901 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
2902 const bool level0Ok = tcu::floatThresholdCompare(log,
2903 ("Level0Face" + de::toString(faceNdx)).c_str(),
2904 (string("Level 0, face ") + s_faceNames[face]).c_str(),
2905 level0Reference.getLevelFace(0, face),
2906 resultTexture.getLevelFace(0, face),
2907 threshold, tcu::COMPARE_LOG_RESULT);
2911 log << tcu::TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << tcu::TestLog::EndMessage;
2912 result = QP_TEST_RESULT_FAIL;
2916 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
2918 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
2920 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
2921 const char* faceName = s_faceNames[face];
2922 const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx-1, face);
2923 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face);
2924 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
2925 bool levelOk = false;
2927 // Try different comparisons in quality order.
2931 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
2935 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2940 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
2944 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2947 // At this point all high-quality methods have been used.
2948 if (!levelOk && result == QP_TEST_RESULT_PASS)
2949 result = QP_TEST_RESULT_QUALITY_WARNING;
2953 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
2957 log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
2961 result = QP_TEST_RESULT_FAIL;
2963 log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
2964 << tcu::TestLog::Image("Result", "Result", dst);
2967 log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2969 log << tcu::TestLog::EndImageSet;
2976 // Logging utilities.
2978 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
2980 return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
2981 << "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
2982 << "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
2983 << "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
2986 } // TextureTestUtil