1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
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 Texture test utilities.
22 *//*--------------------------------------------------------------------*/
24 #include "glsTextureTestUtil.hpp"
25 #include "gluDefs.hpp"
26 #include "gluDrawUtil.hpp"
27 #include "gluRenderContext.hpp"
28 #include "deRandom.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuImageCompare.hpp"
33 #include "tcuStringTemplate.hpp"
34 #include "tcuTexLookupVerifier.hpp"
35 #include "tcuTexCompareVerifier.hpp"
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 #include "qpWatchDog.h"
39 #include "deStringUtil.hpp"
50 namespace TextureTestUtil
58 SamplerType getSamplerType (tcu::TextureFormat format)
60 using tcu::TextureFormat;
64 case TextureFormat::SIGNED_INT8:
65 case TextureFormat::SIGNED_INT16:
66 case TextureFormat::SIGNED_INT32:
67 return SAMPLERTYPE_INT;
69 case TextureFormat::UNSIGNED_INT8:
70 case TextureFormat::UNSIGNED_INT32:
71 case TextureFormat::UNSIGNED_INT_1010102_REV:
72 return SAMPLERTYPE_UINT;
74 // Texture formats used in depth/stencil textures.
75 case TextureFormat::UNSIGNED_INT16:
76 case TextureFormat::UNSIGNED_INT_24_8:
77 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FLOAT : SAMPLERTYPE_UINT;
80 return SAMPLERTYPE_FLOAT;
84 SamplerType getFetchSamplerType (tcu::TextureFormat format)
86 using tcu::TextureFormat;
90 case TextureFormat::SIGNED_INT8:
91 case TextureFormat::SIGNED_INT16:
92 case TextureFormat::SIGNED_INT32:
93 return SAMPLERTYPE_FETCH_INT;
95 case TextureFormat::UNSIGNED_INT8:
96 case TextureFormat::UNSIGNED_INT32:
97 case TextureFormat::UNSIGNED_INT_1010102_REV:
98 return SAMPLERTYPE_FETCH_UINT;
100 // Texture formats used in depth/stencil textures.
101 case TextureFormat::UNSIGNED_INT16:
102 case TextureFormat::UNSIGNED_INT_24_8:
103 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FETCH_FLOAT : SAMPLERTYPE_FETCH_UINT;
106 return SAMPLERTYPE_FETCH_FLOAT;
110 static tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLevel, int maxLevel)
112 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
113 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
114 const int numLevels = clampedMax-clampedBase+1;
115 return tcu::Texture1DView(numLevels, view.getLevels()+clampedBase);
118 static tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLevel, int maxLevel)
120 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
121 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
122 const int numLevels = clampedMax-clampedBase+1;
123 return tcu::Texture2DView(numLevels, view.getLevels()+clampedBase);
126 static tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int baseLevel, int maxLevel)
128 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
129 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
130 const int numLevels = clampedMax-clampedBase+1;
131 const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST];
133 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
134 levels[face] = view.getFaceLevels((tcu::CubeFace)face) + clampedBase;
136 return tcu::TextureCubeView(numLevels, levels);
139 static tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLevel, int maxLevel)
141 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
142 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
143 const int numLevels = clampedMax-clampedBase+1;
144 return tcu::Texture3DView(numLevels, view.getLevels()+clampedBase);
147 static tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel)
149 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
150 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
151 const int numLevels = clampedMax-clampedBase+1;
152 return tcu::TextureCubeArrayView(numLevels, view.getLevels()+clampedBase);
155 inline float linearInterpolate (float t, float minVal, float maxVal)
157 return minVal + (maxVal - minVal) * t;
160 inline tcu::Vec4 linearInterpolate (float t, const tcu::Vec4& a, const tcu::Vec4& b)
162 return a + (b - a) * t;
165 inline float bilinearInterpolate (float x, float y, const tcu::Vec4& quad)
167 float w00 = (1.0f-x)*(1.0f-y);
168 float w01 = (1.0f-x)*y;
169 float w10 = x*(1.0f-y);
171 return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
174 inline float triangleInterpolate (float v0, float v1, float v2, float x, float y)
176 return v0 + (v2-v0)*x + (v1-v0)*y;
179 inline float triangleInterpolate (const tcu::Vec3& v, float x, float y)
181 return triangleInterpolate(v.x(), v.y(), v.z(), x, y);
184 SurfaceAccess::SurfaceAccess (tcu::Surface& surface, const tcu::PixelFormat& colorFmt, int x, int y, int width, int height)
185 : m_surface (&surface)
186 , m_colorMask (getColorMask(colorFmt))
194 SurfaceAccess::SurfaceAccess (tcu::Surface& surface, const tcu::PixelFormat& colorFmt)
195 : m_surface (&surface)
196 , m_colorMask (getColorMask(colorFmt))
199 , m_width (surface.getWidth())
200 , m_height (surface.getHeight())
204 SurfaceAccess::SurfaceAccess (const SurfaceAccess& parent, int x, int y, int width, int height)
205 : m_surface (parent.m_surface)
206 , m_colorMask (parent.m_colorMask)
207 , m_x (parent.m_x + x)
208 , m_y (parent.m_y + y)
214 // 1D lookup LOD computation.
216 float computeLodFromDerivates (LodMode mode, float dudx, float dudy)
221 // \note [mika] Min and max bounds equal to exact with 1D textures
223 case LODMODE_MIN_BOUND:
224 case LODMODE_MAX_BOUND:
225 p = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
232 return deFloatLog2(p);
235 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, deInt32 srcSize, const tcu::Vec3& sq)
237 float dux = (sq.z() - sq.x()) * (float)srcSize;
238 float duy = (sq.y() - sq.x()) * (float)srcSize;
239 float dx = (float)dstSize.x();
240 float dy = (float)dstSize.y();
242 return computeLodFromDerivates(mode, dux/dx, duy/dy);
245 // 2D lookup LOD computation.
247 float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dudy, float dvdy)
253 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx), deFloatSqrt(dudy*dudy + dvdy*dvdy));
256 case LODMODE_MIN_BOUND:
257 case LODMODE_MAX_BOUND:
259 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
260 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
262 p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv;
270 return deFloatLog2(p);
273 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec2& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq)
275 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
276 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
277 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
278 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
279 float dx = (float)dstSize.x();
280 float dy = (float)dstSize.y();
282 return computeLodFromDerivates(mode, dux/dx, dvx/dx, duy/dy, dvy/dy);
285 // 3D lookup LOD computation.
287 float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy)
293 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx + dwdx*dwdx), deFloatSqrt(dudy*dudy + dvdy*dvdy + dwdy*dwdy));
296 case LODMODE_MIN_BOUND:
297 case LODMODE_MAX_BOUND:
299 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
300 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
301 float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy));
303 p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw);
311 return deFloatLog2(p);
314 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec3& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq, const tcu::Vec3& rq)
316 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
317 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
318 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
319 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
320 float dwx = (rq.z() - rq.x()) * (float)srcSize.z();
321 float dwy = (rq.y() - rq.x()) * (float)srcSize.z();
322 float dx = (float)dstSize.x();
323 float dy = (float)dstSize.y();
325 return computeLodFromDerivates(mode, dux/dx, dvx/dx, dwx/dx, duy/dy, dvy/dy, dwy/dy);
328 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
330 return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
333 static inline float triDerivateX (const tcu::Vec3& s, const tcu::Vec3& w, float wx, float width, float ny)
335 float d = w[1]*w[2]*(width*(ny - 1.0f) + wx) - w[0]*(w[2]*width*ny + w[1]*wx);
336 return (w[0]*w[1]*w[2]*width * (w[1]*(s[0] - s[2])*(ny - 1.0f) + ny*(w[2]*(s[1] - s[0]) + w[0]*(s[2] - s[1])))) / (d*d);
339 static inline float triDerivateY (const tcu::Vec3& s, const tcu::Vec3& w, float wy, float height, float nx)
341 float d = w[1]*w[2]*(height*(nx - 1.0f) + wy) - w[0]*(w[1]*height*nx + w[2]*wy);
342 return (w[0]*w[1]*w[2]*height * (w[2]*(s[0] - s[1])*(nx - 1.0f) + nx*(w[0]*(s[1] - s[2]) + w[1]*(s[2] - s[0])))) / (d*d);
346 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& projection, float wx, float wy, float width, float height)
348 // Exact derivatives.
349 float dudx = triDerivateX(u, projection, wx, width, wy/height);
350 float dudy = triDerivateY(u, projection, wy, height, wx/width);
352 return computeLodFromDerivates(mode, dudx, dudy);
356 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& projection, float wx, float wy, float width, float height)
358 // Exact derivatives.
359 float dudx = triDerivateX(u, projection, wx, width, wy/height);
360 float dvdx = triDerivateX(v, projection, wx, width, wy/height);
361 float dudy = triDerivateY(u, projection, wy, height, wx/width);
362 float dvdy = triDerivateY(v, projection, wy, height, wx/width);
364 return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy);
368 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& w, const tcu::Vec3& projection, float wx, float wy, float width, float height)
370 // Exact derivatives.
371 float dudx = triDerivateX(u, projection, wx, width, wy/height);
372 float dvdx = triDerivateX(v, projection, wx, width, wy/height);
373 float dwdx = triDerivateX(w, projection, wx, width, wy/height);
374 float dudy = triDerivateY(u, projection, wy, height, wx/width);
375 float dvdy = triDerivateY(v, projection, wy, height, wx/width);
376 float dwdy = triDerivateY(w, projection, wy, height, wx/width);
378 return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy);
381 static inline tcu::Vec4 execSample (const tcu::Texture1DView& src, const ReferenceParams& params, float s, float lod)
383 if (params.samplerType == SAMPLERTYPE_SHADOW)
384 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f);
386 return src.sample(params.sampler, s, lod);
389 static inline tcu::Vec4 execSample (const tcu::Texture2DView& src, const ReferenceParams& params, float s, float t, float lod)
391 if (params.samplerType == SAMPLERTYPE_SHADOW)
392 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
394 return src.sample(params.sampler, s, t, lod);
397 static inline tcu::Vec4 execSample (const tcu::TextureCubeView& src, const ReferenceParams& params, float s, float t, float r, float lod)
399 if (params.samplerType == SAMPLERTYPE_SHADOW)
400 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
402 return src.sample(params.sampler, s, t, r, lod);
405 static inline tcu::Vec4 execSample (const tcu::Texture2DArrayView& src, const ReferenceParams& params, float s, float t, float r, float lod)
407 if (params.samplerType == SAMPLERTYPE_SHADOW)
408 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
410 return src.sample(params.sampler, s, t, r, lod);
413 static inline tcu::Vec4 execSample (const tcu::TextureCubeArrayView& src, const ReferenceParams& params, float s, float t, float r, float q, float lod)
415 if (params.samplerType == SAMPLERTYPE_SHADOW)
416 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f);
418 return src.sample(params.sampler, s, t, r, q, lod);
421 static inline tcu::Vec4 execSample (const tcu::Texture1DArrayView& src, const ReferenceParams& params, float s, float t, float lod)
423 if (params.samplerType == SAMPLERTYPE_SHADOW)
424 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
426 return src.sample(params.sampler, s, t, lod);
429 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
431 // Separate combined DS formats
432 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
433 const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
435 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
437 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
438 int srcSize = src.getWidth();
440 // Coordinates and lod per triangle.
441 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
442 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod),
443 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) };
445 for (int y = 0; y < dst.getHeight(); y++)
447 for (int x = 0; x < dst.getWidth(); x++)
449 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
450 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
452 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
453 float triX = triNdx ? 1.0f-xf : xf;
454 float triY = triNdx ? 1.0f-yf : yf;
456 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
457 float lod = triLod[triNdx];
459 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
464 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
466 // Separate combined DS formats
467 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
468 const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
470 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
472 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
473 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
475 // Coordinates and lod per triangle.
476 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
477 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
478 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
479 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
481 for (int y = 0; y < dst.getHeight(); y++)
483 for (int x = 0; x < dst.getWidth(); x++)
485 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
486 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
488 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
489 float triX = triNdx ? 1.0f-xf : xf;
490 float triY = triNdx ? 1.0f-yf : yf;
492 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
493 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
494 float lod = triLod[triNdx];
496 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
501 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
503 // Separate combined DS formats
504 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
505 const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
507 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
508 float dstW = (float)dst.getWidth();
509 float dstH = (float)dst.getHeight();
511 tcu::Vec4 uq = sq * (float)src.getWidth();
513 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
514 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
515 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
517 for (int py = 0; py < dst.getHeight(); py++)
519 for (int px = 0; px < dst.getWidth(); px++)
521 float wx = (float)px + 0.5f;
522 float wy = (float)py + 0.5f;
523 float nx = wx / dstW;
524 float ny = wy / dstH;
526 int triNdx = nx + ny >= 1.0f ? 1 : 0;
527 float triWx = triNdx ? dstW - wx : wx;
528 float triWy = triNdx ? dstH - wy : wy;
529 float triNx = triNdx ? 1.0f - nx : nx;
530 float triNy = triNdx ? 1.0f - ny : ny;
532 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
533 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
536 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
541 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
543 // Separate combined DS formats
544 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
545 const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
547 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
548 float dstW = (float)dst.getWidth();
549 float dstH = (float)dst.getHeight();
551 tcu::Vec4 uq = sq * (float)src.getWidth();
552 tcu::Vec4 vq = tq * (float)src.getHeight();
554 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
555 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
556 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
557 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
558 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
560 for (int py = 0; py < dst.getHeight(); py++)
562 for (int px = 0; px < dst.getWidth(); px++)
564 float wx = (float)px + 0.5f;
565 float wy = (float)py + 0.5f;
566 float nx = wx / dstW;
567 float ny = wy / dstH;
569 int triNdx = nx + ny >= 1.0f ? 1 : 0;
570 float triWx = triNdx ? dstW - wx : wx;
571 float triWy = triNdx ? dstH - wy : wy;
572 float triNx = triNdx ? 1.0f - nx : nx;
573 float triNy = triNdx ? 1.0f - ny : ny;
575 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
576 float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
577 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
580 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
585 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
587 const tcu::Texture2DView view = getSubView(src, params.baseLevel, params.maxLevel);
588 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
589 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
591 if (params.flags & ReferenceParams::PROJECTED)
592 sampleTextureProjected(dst, view, sq, tq, params);
594 sampleTextureNonProjected(dst, view, sq, tq, params);
597 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params)
599 const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel);
600 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
602 if (params.flags & ReferenceParams::PROJECTED)
603 sampleTextureProjected(dst, view, sq, params);
605 sampleTextureNonProjected(dst, view, sq, params);
608 static float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize)
610 const tcu::CubeFace face = tcu::selectCubeFace(coord);
615 // \note Derivate signs don't matter when computing lod
618 case tcu::CUBEFACE_NEGATIVE_X:
619 case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
620 case tcu::CUBEFACE_NEGATIVE_Y:
621 case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
622 case tcu::CUBEFACE_NEGATIVE_Z:
623 case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
629 const float sc = coord[sNdx];
630 const float tc = coord[tNdx];
631 const float ma = de::abs(coord[maNdx]);
632 const float scdx = coordDx[sNdx];
633 const float tcdx = coordDx[tNdx];
634 const float madx = de::abs(coordDx[maNdx]);
635 const float scdy = coordDy[sNdx];
636 const float tcdy = coordDy[tNdx];
637 const float mady = de::abs(coordDy[maNdx]);
638 const float dudx = float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma);
639 const float dvdx = float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma);
640 const float dudy = float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma);
641 const float dvdy = float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma);
643 return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
647 static void sampleTextureCube (const SurfaceAccess& dst, const tcu::TextureCubeView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
649 // Separate combined DS formats
650 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
651 const tcu::TextureCubeView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
653 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
654 const float dstW = float(dstSize.x());
655 const float dstH = float(dstSize.y());
656 const int srcSize = src.getSize();
658 // Coordinates per triangle.
659 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
660 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
661 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
662 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
664 const float lodBias ((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
666 for (int py = 0; py < dst.getHeight(); py++)
668 for (int px = 0; px < dst.getWidth(); px++)
670 const float wx = (float)px + 0.5f;
671 const float wy = (float)py + 0.5f;
672 const float nx = wx / dstW;
673 const float ny = wy / dstH;
675 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
676 const float triNx = triNdx ? 1.0f - nx : nx;
677 const float triNy = triNdx ? 1.0f - ny : ny;
679 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
680 triangleInterpolate(triT[triNdx], triNx, triNy),
681 triangleInterpolate(triR[triNdx], triNx, triNy));
682 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
683 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
684 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
685 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
686 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
687 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
689 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod);
691 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py);
696 void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
698 const tcu::TextureCubeView view = getSubView(src, params.baseLevel, params.maxLevel);
699 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
700 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
701 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
703 return sampleTextureCube(dst, view, sq, tq, rq, params);
706 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
708 // Separate combined DS formats
709 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
710 const tcu::Texture2DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
712 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
714 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
715 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
717 // Coordinates and lod per triangle.
718 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
719 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
720 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
721 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
722 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
724 for (int y = 0; y < dst.getHeight(); y++)
726 for (int x = 0; x < dst.getWidth(); x++)
728 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
729 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
731 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
732 float triX = triNdx ? 1.0f-xf : xf;
733 float triY = triNdx ? 1.0f-yf : yf;
735 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
736 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
737 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
738 float lod = triLod[triNdx];
740 dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
745 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params)
747 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
748 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
749 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
751 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
752 sampleTextureNonProjected(dst, src, sq, tq, rq, params);
755 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
757 // Separate combined DS formats
758 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
759 const tcu::Texture1DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
761 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
763 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
764 deInt32 srcSize = src.getWidth();
766 // Coordinates and lod per triangle.
767 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
768 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
769 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
770 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
772 for (int y = 0; y < dst.getHeight(); y++)
774 for (int x = 0; x < dst.getWidth(); x++)
776 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
777 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
779 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
780 float triX = triNdx ? 1.0f-xf : xf;
781 float triY = triNdx ? 1.0f-yf : yf;
783 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
784 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
785 float lod = triLod[triNdx];
787 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
792 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params)
794 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
795 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
797 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
798 sampleTextureNonProjected(dst, src, sq, tq, params);
801 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
803 // Separate combined DS formats
804 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
805 const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
807 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
809 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
810 tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
812 // Coordinates and lod per triangle.
813 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
814 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
815 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
816 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod),
817 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) };
819 for (int y = 0; y < dst.getHeight(); y++)
821 for (int x = 0; x < dst.getWidth(); x++)
823 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
824 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
826 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
827 float triX = triNdx ? 1.0f-xf : xf;
828 float triY = triNdx ? 1.0f-yf : yf;
830 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
831 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
832 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
833 float lod = triLod[triNdx];
835 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
840 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
842 // Separate combined DS formats
843 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
844 const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
846 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
847 float dstW = (float)dst.getWidth();
848 float dstH = (float)dst.getHeight();
850 tcu::Vec4 uq = sq * (float)src.getWidth();
851 tcu::Vec4 vq = tq * (float)src.getHeight();
852 tcu::Vec4 wq = rq * (float)src.getDepth();
854 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
855 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
856 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
857 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
858 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
859 tcu::Vec3 triW[2] = { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) };
860 tcu::Vec3 triP[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
862 for (int py = 0; py < dst.getHeight(); py++)
864 for (int px = 0; px < dst.getWidth(); px++)
866 float wx = (float)px + 0.5f;
867 float wy = (float)py + 0.5f;
868 float nx = wx / dstW;
869 float ny = wy / dstH;
871 int triNdx = nx + ny >= 1.0f ? 1 : 0;
872 float triWx = triNdx ? dstW - wx : wx;
873 float triWy = triNdx ? dstH - wy : wy;
874 float triNx = triNdx ? 1.0f - nx : nx;
875 float triNy = triNdx ? 1.0f - ny : ny;
877 float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
878 float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
879 float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
880 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
883 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
888 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params)
890 const tcu::Texture3DView view = getSubView(src, params.baseLevel, params.maxLevel);
891 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
892 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
893 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
895 if (params.flags & ReferenceParams::PROJECTED)
896 sampleTextureProjected(dst, view, sq, tq, rq, params);
898 sampleTextureNonProjected(dst, view, sq, tq, rq, params);
901 static void sampleTextureCubeArray (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const tcu::Vec4& qq, const ReferenceParams& params)
903 // Separate combined DS formats
904 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
905 const tcu::TextureCubeArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
907 const float dstW = (float)dst.getWidth();
908 const float dstH = (float)dst.getHeight();
910 // Coordinates per triangle.
911 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
912 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
913 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
914 tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
915 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
917 const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
919 for (int py = 0; py < dst.getHeight(); py++)
921 for (int px = 0; px < dst.getWidth(); px++)
923 const float wx = (float)px + 0.5f;
924 const float wy = (float)py + 0.5f;
925 const float nx = wx / dstW;
926 const float ny = wy / dstH;
928 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
929 const float triNx = triNdx ? 1.0f - nx : nx;
930 const float triNy = triNdx ? 1.0f - ny : ny;
932 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
933 triangleInterpolate(triT[triNdx], triNx, triNy),
934 triangleInterpolate(triR[triNdx], triNx, triNy));
936 const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy);
938 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
939 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
940 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
941 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
942 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
943 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
945 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
947 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
952 void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params)
954 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
955 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
956 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
957 tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
959 sampleTextureCubeArray(dst, src, sq, tq, rq, qq, params);
962 void fetchTexture (const SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias)
964 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
965 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
967 for (int y = 0; y < dst.getHeight(); y++)
969 for (int x = 0; x < dst.getWidth(); x++)
971 const float yf = ((float)y + 0.5f) / (float)dst.getHeight();
972 const float xf = ((float)x + 0.5f) / (float)dst.getWidth();
974 const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
975 const float triX = triNdx ? 1.0f-xf : xf;
976 const float triY = triNdx ? 1.0f-yf : yf;
978 const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
980 dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
985 bool compareImages (TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
987 return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
990 bool compareImages (TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
992 return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
995 int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
997 return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
1000 inline int rangeDiff (int x, int a, int b)
1010 inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
1012 int rMin = de::min(a.getRed(), b.getRed());
1013 int rMax = de::max(a.getRed(), b.getRed());
1014 int gMin = de::min(a.getGreen(), b.getGreen());
1015 int gMax = de::max(a.getGreen(), b.getGreen());
1016 int bMin = de::min(a.getBlue(), b.getBlue());
1017 int bMax = de::max(a.getBlue(), b.getBlue());
1018 int aMin = de::min(a.getAlpha(), b.getAlpha());
1019 int aMax = de::max(a.getAlpha(), b.getAlpha());
1021 return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax),
1022 rangeDiff(p.getGreen(), gMin, gMax),
1023 rangeDiff(p.getBlue(), bMin, bMax),
1024 rangeDiff(p.getAlpha(), aMin, aMax));
1027 inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
1029 tcu::RGBA diff = rangeDiff(p, a, b);
1030 return diff.getRed() <= threshold.getRed() &&
1031 diff.getGreen() <= threshold.getGreen() &&
1032 diff.getBlue() <= threshold.getBlue() &&
1033 diff.getAlpha() <= threshold.getAlpha();
1036 RandomViewport::RandomViewport (const tcu::RenderTarget& renderTarget, int preferredWidth, int preferredHeight, deUint32 seed)
1039 , width (deMin32(preferredWidth, renderTarget.getWidth()))
1040 , height (deMin32(preferredHeight, renderTarget.getHeight()))
1042 de::Random rnd(seed);
1043 x = rnd.getInt(0, renderTarget.getWidth() - width);
1044 y = rnd.getInt(0, renderTarget.getHeight() - height);
1047 ProgramLibrary::ProgramLibrary (const glu::RenderContext& context, tcu::TestLog& log, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1048 : m_context (context)
1050 , m_glslVersion (glslVersion)
1051 , m_texCoordPrecision (texCoordPrecision)
1055 ProgramLibrary::~ProgramLibrary (void)
1060 void ProgramLibrary::clear (void)
1062 for (map<Program, glu::ShaderProgram*>::iterator i = m_programs.begin(); i != m_programs.end(); i++)
1065 i->second = DE_NULL;
1070 glu::ShaderProgram* ProgramLibrary::getProgram (Program program)
1072 if (m_programs.find(program) != m_programs.end())
1073 return m_programs[program]; // Return from cache.
1075 static const char* vertShaderTemplate =
1077 "${VTX_IN} highp vec4 a_position;\n"
1078 "${VTX_IN} ${PRECISION} ${TEXCOORD_TYPE} a_texCoord;\n"
1079 "${VTX_OUT} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1081 "void main (void)\n"
1083 " gl_Position = a_position;\n"
1084 " v_texCoord = a_texCoord;\n"
1086 static const char* fragShaderTemplate =
1088 "${FRAG_IN} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1089 "uniform ${PRECISION} float u_bias;\n"
1090 "uniform ${PRECISION} float u_ref;\n"
1091 "uniform ${PRECISION} vec4 u_colorScale;\n"
1092 "uniform ${PRECISION} vec4 u_colorBias;\n"
1093 "uniform ${PRECISION} ${SAMPLER_TYPE} u_sampler;\n"
1095 "void main (void)\n"
1097 " ${FRAG_COLOR} = ${LOOKUP} * u_colorScale + u_colorBias;\n"
1100 map<string, string> params;
1102 bool isCube = de::inRange<int>(program, PROGRAM_CUBE_FLOAT, PROGRAM_CUBE_SHADOW_BIAS);
1103 bool isArray = de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW)
1104 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW);
1106 bool is1D = de::inRange<int>(program, PROGRAM_1D_FLOAT, PROGRAM_1D_UINT_BIAS)
1107 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW)
1108 || de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1110 bool is2D = de::inRange<int>(program, PROGRAM_2D_FLOAT, PROGRAM_2D_UINT_BIAS)
1111 || de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW);
1113 bool is3D = de::inRange<int>(program, PROGRAM_3D_FLOAT, PROGRAM_3D_UINT_BIAS);
1114 bool isCubeArray = de::inRange<int>(program, PROGRAM_CUBE_ARRAY_FLOAT, PROGRAM_CUBE_ARRAY_SHADOW);
1115 bool isBuffer = de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1117 if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1119 params["FRAG_HEADER"] = "";
1120 params["VTX_HEADER"] = "";
1121 params["VTX_IN"] = "attribute";
1122 params["VTX_OUT"] = "varying";
1123 params["FRAG_IN"] = "varying";
1124 params["FRAG_COLOR"] = "gl_FragColor";
1126 else if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1128 const string version = glu::getGLSLVersionDeclaration(m_glslVersion);
1129 const char* ext = DE_NULL;
1131 if (isCubeArray && glu::glslVersionIsES(m_glslVersion))
1132 ext = "GL_EXT_texture_cube_map_array";
1133 else if (isBuffer && glu::glslVersionIsES(m_glslVersion))
1134 ext = "GL_EXT_texture_buffer";
1136 params["FRAG_HEADER"] = version + (ext ? string("\n#extension ") + ext + " : require" : string()) + "\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1137 params["VTX_HEADER"] = version + "\n";
1138 params["VTX_IN"] = "in";
1139 params["VTX_OUT"] = "out";
1140 params["FRAG_IN"] = "in";
1141 params["FRAG_COLOR"] = "dEQP_FragColor";
1144 DE_FATAL("Unsupported version");
1146 params["PRECISION"] = glu::getPrecisionName(m_texCoordPrecision);
1149 params["TEXCOORD_TYPE"] = "vec4";
1150 else if (isCube || (is2D && isArray) || is3D)
1151 params["TEXCOORD_TYPE"] = "vec3";
1152 else if ((is1D && isArray) || is2D)
1153 params["TEXCOORD_TYPE"] = "vec2";
1155 params["TEXCOORD_TYPE"] = "float";
1157 DE_ASSERT(DE_FALSE);
1159 const char* sampler = DE_NULL;
1160 const char* lookup = DE_NULL;
1162 if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1166 case PROGRAM_2D_FLOAT: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1167 case PROGRAM_2D_INT: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1168 case PROGRAM_2D_UINT: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1169 case PROGRAM_2D_SHADOW: sampler = "sampler2DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1170 case PROGRAM_2D_FLOAT_BIAS: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1171 case PROGRAM_2D_INT_BIAS: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1172 case PROGRAM_2D_UINT_BIAS: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1173 case PROGRAM_2D_SHADOW_BIAS: sampler = "sampler2DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break;
1174 case PROGRAM_1D_FLOAT: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1175 case PROGRAM_1D_INT: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1176 case PROGRAM_1D_UINT: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1177 case PROGRAM_1D_SHADOW: sampler = "sampler1DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1178 case PROGRAM_1D_FLOAT_BIAS: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1179 case PROGRAM_1D_INT_BIAS: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1180 case PROGRAM_1D_UINT_BIAS: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1181 case PROGRAM_1D_SHADOW_BIAS: sampler = "sampler1DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break;
1182 case PROGRAM_CUBE_FLOAT: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord)"; break;
1183 case PROGRAM_CUBE_INT: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1184 case PROGRAM_CUBE_UINT: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1185 case PROGRAM_CUBE_SHADOW: sampler = "samplerCubeShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1186 case PROGRAM_CUBE_FLOAT_BIAS: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1187 case PROGRAM_CUBE_INT_BIAS: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1188 case PROGRAM_CUBE_UINT_BIAS: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1189 case PROGRAM_CUBE_SHADOW_BIAS: sampler = "samplerCubeShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break;
1190 case PROGRAM_2D_ARRAY_FLOAT: sampler = "sampler2DArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1191 case PROGRAM_2D_ARRAY_INT: sampler = "isampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1192 case PROGRAM_2D_ARRAY_UINT: sampler = "usampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1193 case PROGRAM_2D_ARRAY_SHADOW: sampler = "sampler2DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1194 case PROGRAM_3D_FLOAT: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1195 case PROGRAM_3D_INT: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1196 case PROGRAM_3D_UINT: sampler = "usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1197 case PROGRAM_3D_FLOAT_BIAS: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1198 case PROGRAM_3D_INT_BIAS: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1199 case PROGRAM_3D_UINT_BIAS: sampler = "usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1200 case PROGRAM_CUBE_ARRAY_FLOAT: sampler = "samplerCubeArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1201 case PROGRAM_CUBE_ARRAY_INT: sampler = "isamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1202 case PROGRAM_CUBE_ARRAY_UINT: sampler = "usamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1203 case PROGRAM_CUBE_ARRAY_SHADOW: sampler = "samplerCubeArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1204 case PROGRAM_1D_ARRAY_FLOAT: sampler = "sampler1DArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1205 case PROGRAM_1D_ARRAY_INT: sampler = "isampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1206 case PROGRAM_1D_ARRAY_UINT: sampler = "usampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1207 case PROGRAM_1D_ARRAY_SHADOW: sampler = "sampler1DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1208 case PROGRAM_BUFFER_FLOAT: sampler = "samplerBuffer"; lookup = "texelFetch(u_sampler, int(v_texCoord))"; break;
1209 case PROGRAM_BUFFER_INT: sampler = "isamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break;
1210 case PROGRAM_BUFFER_UINT: sampler = "usamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break;
1215 else if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1217 sampler = isCube ? "samplerCube" : "sampler2D";
1221 case PROGRAM_2D_FLOAT: lookup = "texture2D(u_sampler, v_texCoord)"; break;
1222 case PROGRAM_2D_FLOAT_BIAS: lookup = "texture2D(u_sampler, v_texCoord, u_bias)"; break;
1223 case PROGRAM_CUBE_FLOAT: lookup = "textureCube(u_sampler, v_texCoord)"; break;
1224 case PROGRAM_CUBE_FLOAT_BIAS: lookup = "textureCube(u_sampler, v_texCoord, u_bias)"; break;
1230 DE_FATAL("Unsupported version");
1232 params["SAMPLER_TYPE"] = sampler;
1233 params["LOOKUP"] = lookup;
1235 std::string vertSrc = tcu::StringTemplate(vertShaderTemplate).specialize(params);
1236 std::string fragSrc = tcu::StringTemplate(fragShaderTemplate).specialize(params);
1238 glu::ShaderProgram* progObj = new glu::ShaderProgram(m_context, glu::makeVtxFragSources(vertSrc, fragSrc));
1239 if (!progObj->isOk())
1243 TCU_FAIL("Failed to compile shader program");
1248 m_programs[program] = progObj;
1259 TextureRenderer::TextureRenderer (const glu::RenderContext& context, tcu::TestLog& log, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1260 : m_renderCtx (context)
1262 , m_programLibrary (context, log, glslVersion, texCoordPrecision)
1266 TextureRenderer::~TextureRenderer (void)
1271 void TextureRenderer::clear (void)
1273 m_programLibrary.clear();
1276 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, TextureType texType)
1278 renderQuad(texUnit, texCoord, RenderParams(texType));
1281 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, const RenderParams& params)
1283 const glw::Functions& gl = m_renderCtx.getFunctions();
1284 tcu::Vec4 wCoord = params.flags & RenderParams::PROJECTED ? params.w : tcu::Vec4(1.0f);
1285 bool useBias = !!(params.flags & RenderParams::USE_BIAS);
1286 bool logUniforms = !!(params.flags & RenderParams::LOG_UNIFORMS);
1288 // Render quad with texture.
1291 -1.0f*wCoord.x(), -1.0f*wCoord.x(), 0.0f, wCoord.x(),
1292 -1.0f*wCoord.y(), +1.0f*wCoord.y(), 0.0f, wCoord.y(),
1293 +1.0f*wCoord.z(), -1.0f*wCoord.z(), 0.0f, wCoord.z(),
1294 +1.0f*wCoord.w(), +1.0f*wCoord.w(), 0.0f, wCoord.w()
1296 static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
1298 Program progSpec = PROGRAM_LAST;
1300 if (params.texType == TEXTURETYPE_2D)
1304 switch (params.samplerType)
1306 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_2D_FLOAT_BIAS : PROGRAM_2D_FLOAT; break;
1307 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_2D_INT_BIAS : PROGRAM_2D_INT; break;
1308 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_2D_UINT_BIAS : PROGRAM_2D_UINT; break;
1309 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_2D_SHADOW_BIAS : PROGRAM_2D_SHADOW; break;
1310 default: DE_ASSERT(false);
1313 else if (params.texType == TEXTURETYPE_1D)
1317 switch (params.samplerType)
1319 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_1D_FLOAT_BIAS : PROGRAM_1D_FLOAT; break;
1320 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_1D_INT_BIAS : PROGRAM_1D_INT; break;
1321 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_1D_UINT_BIAS : PROGRAM_1D_UINT; break;
1322 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_1D_SHADOW_BIAS : PROGRAM_1D_SHADOW; break;
1323 default: DE_ASSERT(false);
1326 else if (params.texType == TEXTURETYPE_CUBE)
1330 switch (params.samplerType)
1332 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_CUBE_FLOAT_BIAS : PROGRAM_CUBE_FLOAT; break;
1333 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_CUBE_INT_BIAS : PROGRAM_CUBE_INT; break;
1334 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_CUBE_UINT_BIAS : PROGRAM_CUBE_UINT; break;
1335 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_CUBE_SHADOW_BIAS : PROGRAM_CUBE_SHADOW; break;
1336 default: DE_ASSERT(false);
1339 else if (params.texType == TEXTURETYPE_3D)
1343 switch (params.samplerType)
1345 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_3D_FLOAT_BIAS : PROGRAM_3D_FLOAT; break;
1346 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_3D_INT_BIAS : PROGRAM_3D_INT; break;
1347 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_3D_UINT_BIAS : PROGRAM_3D_UINT; break;
1348 default: DE_ASSERT(false);
1351 else if (params.texType == TEXTURETYPE_2D_ARRAY)
1353 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1357 switch (params.samplerType)
1359 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_2D_ARRAY_FLOAT; break;
1360 case SAMPLERTYPE_INT: progSpec = PROGRAM_2D_ARRAY_INT; break;
1361 case SAMPLERTYPE_UINT: progSpec = PROGRAM_2D_ARRAY_UINT; break;
1362 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_2D_ARRAY_SHADOW; break;
1363 default: DE_ASSERT(false);
1366 else if (params.texType == TEXTURETYPE_CUBE_ARRAY)
1368 DE_ASSERT(!useBias);
1372 switch (params.samplerType)
1374 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_CUBE_ARRAY_FLOAT; break;
1375 case SAMPLERTYPE_INT: progSpec = PROGRAM_CUBE_ARRAY_INT; break;
1376 case SAMPLERTYPE_UINT: progSpec = PROGRAM_CUBE_ARRAY_UINT; break;
1377 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_CUBE_ARRAY_SHADOW; break;
1378 default: DE_ASSERT(false);
1381 else if (params.texType == TEXTURETYPE_1D_ARRAY)
1383 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1387 switch (params.samplerType)
1389 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_1D_ARRAY_FLOAT; break;
1390 case SAMPLERTYPE_INT: progSpec = PROGRAM_1D_ARRAY_INT; break;
1391 case SAMPLERTYPE_UINT: progSpec = PROGRAM_1D_ARRAY_UINT; break;
1392 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_1D_ARRAY_SHADOW; break;
1393 default: DE_ASSERT(false);
1396 else if (params.texType == TEXTURETYPE_BUFFER)
1400 switch (params.samplerType)
1402 case SAMPLERTYPE_FETCH_FLOAT: progSpec = PROGRAM_BUFFER_FLOAT; break;
1403 case SAMPLERTYPE_FETCH_INT: progSpec = PROGRAM_BUFFER_INT; break;
1404 case SAMPLERTYPE_FETCH_UINT: progSpec = PROGRAM_BUFFER_UINT; break;
1405 default: DE_ASSERT(false);
1409 DE_ASSERT(DE_FALSE);
1411 glu::ShaderProgram* program = m_programLibrary.getProgram(progSpec);
1413 // \todo [2012-09-26 pyry] Move to ProgramLibrary and log unique programs only(?)
1414 if (params.flags & RenderParams::LOG_PROGRAMS)
1417 GLU_EXPECT_NO_ERROR(gl.getError(), "Set vertex attributes");
1419 // Program and uniforms.
1420 deUint32 prog = program->getProgram();
1421 gl.useProgram(prog);
1423 gl.uniform1i(gl.getUniformLocation(prog, "u_sampler"), texUnit);
1425 m_log << TestLog::Message << "u_sampler = " << texUnit << TestLog::EndMessage;
1429 gl.uniform1f(gl.getUniformLocation(prog, "u_bias"), params.bias);
1431 m_log << TestLog::Message << "u_bias = " << params.bias << TestLog::EndMessage;
1434 if (params.samplerType == SAMPLERTYPE_SHADOW)
1436 gl.uniform1f(gl.getUniformLocation(prog, "u_ref"), params.ref);
1438 m_log << TestLog::Message << "u_ref = " << params.ref << TestLog::EndMessage;
1441 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorScale"), 1, params.colorScale.getPtr());
1442 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorBias"), 1, params.colorBias.getPtr());
1446 m_log << TestLog::Message << "u_colorScale = " << params.colorScale << TestLog::EndMessage;
1447 m_log << TestLog::Message << "u_colorBias = " << params.colorBias << TestLog::EndMessage;
1450 GLU_EXPECT_NO_ERROR(gl.getError(), "Set program state");
1453 const glu::VertexArrayBinding vertexArrays[] =
1455 glu::va::Float("a_position", 4, 4, 0, &position[0]),
1456 glu::va::Float("a_texCoord", numComps, 4, 0, texCoord)
1458 glu::draw(m_renderCtx, prog, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
1459 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1463 void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
1473 void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
1477 dst[0] = left; dst[1] = (float)layerNdx;
1478 dst[2] = left; dst[3] = (float)layerNdx;
1479 dst[4] = right; dst[5] = (float)layerNdx;
1480 dst[6] = right; dst[7] = (float)layerNdx;
1483 void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1487 dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y();
1488 dst[2] = bottomLeft.x(); dst[3] = topRight.y();
1489 dst[4] = topRight.x(); dst[5] = bottomLeft.y();
1490 dst[6] = topRight.x(); dst[7] = topRight.y();
1493 void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1497 dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx;
1498 dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx;
1499 dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx;
1500 dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx;
1503 void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
1505 tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1506 tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1507 tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1508 tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1510 tcu::Vec3 v0 = p0 + (p1-p0)*f0;
1511 tcu::Vec3 v1 = p0 + (p1-p0)*f1;
1512 tcu::Vec3 v2 = p0 + (p1-p0)*f2;
1513 tcu::Vec3 v3 = p0 + (p1-p0)*f3;
1517 dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
1518 dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
1519 dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
1520 dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
1523 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
1525 static const float texCoordNegX[] =
1528 -1.0f, -1.0f, -1.0f,
1532 static const float texCoordPosX[] =
1539 static const float texCoordNegY[] =
1542 -1.0f, -1.0f, -1.0f,
1546 static const float texCoordPosY[] =
1548 -1.0f, +1.0f, -1.0f,
1553 static const float texCoordNegZ[] =
1560 static const float texCoordPosZ[] =
1563 -1.0f, -1.0f, +1.0f,
1568 const float* texCoord = DE_NULL;
1569 int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX);
1573 case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
1574 case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
1575 case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
1576 case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
1577 case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
1578 case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
1580 DE_ASSERT(DE_FALSE);
1584 dst.resize(texCoordSize);
1585 std::copy(texCoord, texCoord+texCoordSize, dst.begin());
1588 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1599 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1600 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1601 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1602 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1603 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1604 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1606 DE_ASSERT(DE_FALSE);
1612 dst[0+mRow] = mSign;
1613 dst[3+mRow] = mSign;
1614 dst[6+mRow] = mSign;
1615 dst[9+mRow] = mSign;
1617 dst[0+sRow] = sSign * bottomLeft.x();
1618 dst[3+sRow] = sSign * bottomLeft.x();
1619 dst[6+sRow] = sSign * topRight.x();
1620 dst[9+sRow] = sSign * topRight.x();
1622 dst[0+tRow] = tSign * bottomLeft.y();
1623 dst[3+tRow] = tSign * topRight.y();
1624 dst[6+tRow] = tSign * bottomLeft.y();
1625 dst[9+tRow] = tSign * topRight.y();
1628 void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
1637 const float l0 = layerRange.x();
1638 const float l1 = layerRange.y();
1642 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1643 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1644 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1645 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1646 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1647 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1649 DE_ASSERT(DE_FALSE);
1655 dst[ 0+mRow] = mSign;
1656 dst[ 4+mRow] = mSign;
1657 dst[ 8+mRow] = mSign;
1658 dst[12+mRow] = mSign;
1660 dst[ 0+sRow] = sSign * bottomLeft.x();
1661 dst[ 4+sRow] = sSign * bottomLeft.x();
1662 dst[ 8+sRow] = sSign * topRight.x();
1663 dst[12+sRow] = sSign * topRight.x();
1665 dst[ 0+tRow] = tSign * bottomLeft.y();
1666 dst[ 4+tRow] = tSign * topRight.y();
1667 dst[ 8+tRow] = tSign * bottomLeft.y();
1668 dst[12+tRow] = tSign * topRight.y();
1673 dst[ 4+qRow] = l0*0.5f + l1*0.5f;
1674 dst[ 8+qRow] = l0*0.5f + l1*0.5f;
1686 // Texture result verification
1688 //! Verifies texture lookup results and returns number of failed pixels.
1689 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1690 const tcu::ConstPixelBufferAccess& reference,
1691 const tcu::PixelBufferAccess& errorMask,
1692 const tcu::Texture1DView& baseView,
1693 const float* texCoord,
1694 const ReferenceParams& sampleParams,
1695 const tcu::LookupPrecision& lookupPrec,
1696 const tcu::LodPrecision& lodPrec,
1697 qpWatchDog* watchDog)
1699 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1700 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1702 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1703 const tcu::Texture1DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1705 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1707 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1708 const float dstW = float(dstSize.x());
1709 const float dstH = float(dstSize.y());
1710 const int srcSize = src.getWidth();
1712 // Coordinates and lod per triangle.
1713 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1714 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1716 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1720 const tcu::Vec2 lodOffsets[] =
1728 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1730 for (int py = 0; py < result.getHeight(); py++)
1732 // Ugly hack, validation can take way too long at the moment.
1734 qpWatchDog_touch(watchDog);
1736 for (int px = 0; px < result.getWidth(); px++)
1738 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1739 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1741 // Try comparison to ideal reference first, and if that fails use slower verificator.
1742 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1744 const float wx = (float)px + 0.5f;
1745 const float wy = (float)py + 0.5f;
1746 const float nx = wx / dstW;
1747 const float ny = wy / dstH;
1749 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1750 const float triWx = triNdx ? dstW - wx : wx;
1751 const float triWy = triNdx ? dstH - wy : wy;
1752 const float triNx = triNdx ? 1.0f - nx : nx;
1753 const float triNy = triNdx ? 1.0f - ny : ny;
1755 const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1756 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1757 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1759 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1761 // Compute lod bounds across lodOffsets range.
1762 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1764 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1765 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1766 const float nxo = wxo/dstW;
1767 const float nyo = wyo/dstH;
1769 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1770 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1771 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1773 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1774 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1777 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1778 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1782 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1792 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1793 const tcu::ConstPixelBufferAccess& reference,
1794 const tcu::PixelBufferAccess& errorMask,
1795 const tcu::Texture2DView& baseView,
1796 const float* texCoord,
1797 const ReferenceParams& sampleParams,
1798 const tcu::LookupPrecision& lookupPrec,
1799 const tcu::LodPrecision& lodPrec,
1800 qpWatchDog* watchDog)
1802 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1803 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1805 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1806 const tcu::Texture2DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1808 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1809 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1811 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1812 const float dstW = float(dstSize.x());
1813 const float dstH = float(dstSize.y());
1814 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
1816 // Coordinates and lod per triangle.
1817 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1818 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1819 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1821 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1825 const tcu::Vec2 lodOffsets[] =
1833 tcu::clear(errorMask, tcu::RGBA::green().toVec());
1835 for (int py = 0; py < result.getHeight(); py++)
1837 // Ugly hack, validation can take way too long at the moment.
1839 qpWatchDog_touch(watchDog);
1841 for (int px = 0; px < result.getWidth(); px++)
1843 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1844 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1846 // Try comparison to ideal reference first, and if that fails use slower verificator.
1847 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1849 const float wx = (float)px + 0.5f;
1850 const float wy = (float)py + 0.5f;
1851 const float nx = wx / dstW;
1852 const float ny = wy / dstH;
1854 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1855 const float triWx = triNdx ? dstW - wx : wx;
1856 const float triWy = triNdx ? dstH - wy : wy;
1857 const float triNx = triNdx ? 1.0f - nx : nx;
1858 const float triNy = triNdx ? 1.0f - ny : ny;
1860 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1861 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1862 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1863 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1864 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1865 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1867 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1869 // Compute lod bounds across lodOffsets range.
1870 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1872 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1873 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1874 const float nxo = wxo/dstW;
1875 const float nyo = wyo/dstH;
1877 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1878 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1879 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1880 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1881 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1883 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1884 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1887 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1888 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1892 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1902 bool verifyTextureResult (tcu::TestContext& testCtx,
1903 const tcu::ConstPixelBufferAccess& result,
1904 const tcu::Texture1DView& src,
1905 const float* texCoord,
1906 const ReferenceParams& sampleParams,
1907 const tcu::LookupPrecision& lookupPrec,
1908 const tcu::LodPrecision& lodPrec,
1909 const tcu::PixelFormat& pixelFormat)
1911 tcu::TestLog& log = testCtx.getLog();
1912 tcu::Surface reference (result.getWidth(), result.getHeight());
1913 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1914 int numFailedPixels;
1916 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1918 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1919 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1921 if (numFailedPixels > 0)
1922 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1924 log << TestLog::ImageSet("VerifyResult", "Verification result")
1925 << TestLog::Image("Rendered", "Rendered image", result);
1927 if (numFailedPixels > 0)
1929 log << TestLog::Image("Reference", "Ideal reference image", reference)
1930 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1933 log << TestLog::EndImageSet;
1935 return numFailedPixels == 0;
1938 bool verifyTextureResult (tcu::TestContext& testCtx,
1939 const tcu::ConstPixelBufferAccess& result,
1940 const tcu::Texture2DView& src,
1941 const float* texCoord,
1942 const ReferenceParams& sampleParams,
1943 const tcu::LookupPrecision& lookupPrec,
1944 const tcu::LodPrecision& lodPrec,
1945 const tcu::PixelFormat& pixelFormat)
1947 tcu::TestLog& log = testCtx.getLog();
1948 tcu::Surface reference (result.getWidth(), result.getHeight());
1949 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1950 int numFailedPixels;
1952 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1954 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1955 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1957 if (numFailedPixels > 0)
1958 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1960 log << TestLog::ImageSet("VerifyResult", "Verification result")
1961 << TestLog::Image("Rendered", "Rendered image", result);
1963 if (numFailedPixels > 0)
1965 log << TestLog::Image("Reference", "Ideal reference image", reference)
1966 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1969 log << TestLog::EndImageSet;
1971 return numFailedPixels == 0;
1974 //! Verifies texture lookup results and returns number of failed pixels.
1975 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1976 const tcu::ConstPixelBufferAccess& reference,
1977 const tcu::PixelBufferAccess& errorMask,
1978 const tcu::TextureCubeView& baseView,
1979 const float* texCoord,
1980 const ReferenceParams& sampleParams,
1981 const tcu::LookupPrecision& lookupPrec,
1982 const tcu::LodPrecision& lodPrec,
1983 qpWatchDog* watchDog)
1985 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1986 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1988 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
1989 const tcu::TextureCubeView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1991 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1992 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1993 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1995 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1996 const float dstW = float(dstSize.x());
1997 const float dstH = float(dstSize.y());
1998 const int srcSize = src.getSize();
2000 // Coordinates per triangle.
2001 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2002 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2003 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2004 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2006 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2008 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
2012 const tcu::Vec2 lodOffsets[] =
2019 // \note Not strictly allowed by spec, but implementations do this in practice.
2026 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2028 for (int py = 0; py < result.getHeight(); py++)
2030 // Ugly hack, validation can take way too long at the moment.
2032 qpWatchDog_touch(watchDog);
2034 for (int px = 0; px < result.getWidth(); px++)
2036 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2037 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2039 // Try comparison to ideal reference first, and if that fails use slower verificator.
2040 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2042 const float wx = (float)px + 0.5f;
2043 const float wy = (float)py + 0.5f;
2044 const float nx = wx / dstW;
2045 const float ny = wy / dstH;
2047 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
2048 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
2052 DE_ASSERT(tri0 || tri1);
2054 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2055 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2057 const float triWx = triNdx ? dstW - wx : wx;
2058 const float triWy = triNdx ? dstH - wy : wy;
2059 const float triNx = triNdx ? 1.0f - nx : nx;
2060 const float triNy = triNdx ? 1.0f - ny : ny;
2062 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2063 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2064 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2065 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2066 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2067 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2068 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2069 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2070 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2072 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2074 // Compute lod bounds across lodOffsets range.
2075 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2077 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2078 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2079 const float nxo = wxo/dstW;
2080 const float nyo = wyo/dstH;
2082 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2083 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2084 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2085 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2086 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2087 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2088 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2089 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2090 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2091 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2093 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2094 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2097 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2099 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2108 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2118 bool verifyTextureResult (tcu::TestContext& testCtx,
2119 const tcu::ConstPixelBufferAccess& result,
2120 const tcu::TextureCubeView& 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(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 << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2140 log << TestLog::ImageSet("VerifyResult", "Verification result")
2141 << TestLog::Image("Rendered", "Rendered image", result);
2143 if (numFailedPixels > 0)
2145 log << TestLog::Image("Reference", "Ideal reference image", reference)
2146 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2149 log << 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::Texture3DView& baseView,
2159 const float* texCoord,
2160 const ReferenceParams& sampleParams,
2161 const tcu::LookupPrecision& lookupPrec,
2162 const tcu::LodPrecision& lodPrec,
2163 qpWatchDog* watchDog)
2165 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2166 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2168 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2169 const tcu::Texture3DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
2171 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2172 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2173 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2175 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2176 const float dstW = float(dstSize.x());
2177 const float dstH = float(dstSize.y());
2178 const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
2180 // Coordinates and lod per triangle.
2181 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2182 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2183 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2184 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2186 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2188 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
2192 const tcu::Vec2 lodOffsets[] =
2200 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2202 for (int py = 0; py < result.getHeight(); py++)
2204 // Ugly hack, validation can take way too long at the moment.
2206 qpWatchDog_touch(watchDog);
2208 for (int px = 0; px < result.getWidth(); px++)
2210 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2211 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2213 // Try comparison to ideal reference first, and if that fails use slower verificator.
2214 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2216 const float wx = (float)px + 0.5f;
2217 const float wy = (float)py + 0.5f;
2218 const float nx = wx / dstW;
2219 const float ny = wy / dstH;
2221 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
2222 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
2226 DE_ASSERT(tri0 || tri1);
2228 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2229 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2231 const float triWx = triNdx ? dstW - wx : wx;
2232 const float triWy = triNdx ? dstH - wy : wy;
2233 const float triNx = triNdx ? 1.0f - nx : nx;
2234 const float triNy = triNdx ? 1.0f - ny : ny;
2236 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2237 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2238 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2239 const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2240 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2241 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2242 const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2243 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2244 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2246 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
2248 // Compute lod bounds across lodOffsets range.
2249 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2251 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2252 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2253 const float nxo = wxo/dstW;
2254 const float nyo = wyo/dstH;
2256 const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2257 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2258 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2259 const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2260 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2261 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2262 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
2264 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2265 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2268 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2270 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2279 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2289 bool verifyTextureResult (tcu::TestContext& testCtx,
2290 const tcu::ConstPixelBufferAccess& result,
2291 const tcu::Texture3DView& src,
2292 const float* texCoord,
2293 const ReferenceParams& sampleParams,
2294 const tcu::LookupPrecision& lookupPrec,
2295 const tcu::LodPrecision& lodPrec,
2296 const tcu::PixelFormat& pixelFormat)
2298 tcu::TestLog& log = testCtx.getLog();
2299 tcu::Surface reference (result.getWidth(), result.getHeight());
2300 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2301 int numFailedPixels;
2303 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2305 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2306 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2308 if (numFailedPixels > 0)
2309 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2311 log << TestLog::ImageSet("VerifyResult", "Verification result")
2312 << TestLog::Image("Rendered", "Rendered image", result);
2314 if (numFailedPixels > 0)
2316 log << TestLog::Image("Reference", "Ideal reference image", reference)
2317 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2320 log << TestLog::EndImageSet;
2322 return numFailedPixels == 0;
2325 //! Verifies texture lookup results and returns number of failed pixels.
2326 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2327 const tcu::ConstPixelBufferAccess& reference,
2328 const tcu::PixelBufferAccess& errorMask,
2329 const tcu::Texture1DArrayView& baseView,
2330 const float* texCoord,
2331 const ReferenceParams& sampleParams,
2332 const tcu::LookupPrecision& lookupPrec,
2333 const tcu::LodPrecision& lodPrec,
2334 qpWatchDog* watchDog)
2336 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2337 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2339 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2340 const tcu::Texture1DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
2342 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2343 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2345 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2346 const float dstW = float(dstSize.x());
2347 const float dstH = float(dstSize.y());
2348 const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored.
2350 // Coordinates and lod per triangle.
2351 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2352 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2353 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2355 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2359 const tcu::Vec2 lodOffsets[] =
2367 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2369 for (int py = 0; py < result.getHeight(); py++)
2371 // Ugly hack, validation can take way too long at the moment.
2373 qpWatchDog_touch(watchDog);
2375 for (int px = 0; px < result.getWidth(); px++)
2377 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2378 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2380 // Try comparison to ideal reference first, and if that fails use slower verificator.
2381 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2383 const float wx = (float)px + 0.5f;
2384 const float wy = (float)py + 0.5f;
2385 const float nx = wx / dstW;
2386 const float ny = wy / dstH;
2388 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2389 const float triWx = triNdx ? dstW - wx : wx;
2390 const float triWy = triNdx ? dstH - wy : wy;
2391 const float triNx = triNdx ? 1.0f - nx : nx;
2392 const float triNy = triNdx ? 1.0f - ny : ny;
2394 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2395 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2396 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
2397 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
2399 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
2401 // Compute lod bounds across lodOffsets range.
2402 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2404 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2405 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2406 const float nxo = wxo/dstW;
2407 const float nyo = wyo/dstH;
2409 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
2410 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
2411 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
2413 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2414 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2417 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2418 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2422 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2432 //! Verifies texture lookup results and returns number of failed pixels.
2433 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2434 const tcu::ConstPixelBufferAccess& reference,
2435 const tcu::PixelBufferAccess& errorMask,
2436 const tcu::Texture2DArrayView& baseView,
2437 const float* texCoord,
2438 const ReferenceParams& sampleParams,
2439 const tcu::LookupPrecision& lookupPrec,
2440 const tcu::LodPrecision& lodPrec,
2441 qpWatchDog* watchDog)
2443 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2444 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2446 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2447 const tcu::Texture2DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
2449 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2450 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2451 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2453 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2454 const float dstW = float(dstSize.x());
2455 const float dstH = float(dstSize.y());
2456 const tcu::Vec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2458 // Coordinates and lod per triangle.
2459 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2460 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2461 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2462 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2464 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2468 const tcu::Vec2 lodOffsets[] =
2476 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2478 for (int py = 0; py < result.getHeight(); py++)
2480 // Ugly hack, validation can take way too long at the moment.
2482 qpWatchDog_touch(watchDog);
2484 for (int px = 0; px < result.getWidth(); px++)
2486 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2487 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2489 // Try comparison to ideal reference first, and if that fails use slower verificator.
2490 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2492 const float wx = (float)px + 0.5f;
2493 const float wy = (float)py + 0.5f;
2494 const float nx = wx / dstW;
2495 const float ny = wy / dstH;
2497 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2498 const float triWx = triNdx ? dstW - wx : wx;
2499 const float triWy = triNdx ? dstH - wy : wy;
2500 const float triNx = triNdx ? 1.0f - nx : nx;
2501 const float triNy = triNdx ? 1.0f - ny : ny;
2503 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2504 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2505 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2506 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2507 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2508 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2509 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2511 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2513 // Compute lod bounds across lodOffsets range.
2514 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2516 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2517 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2518 const float nxo = wxo/dstW;
2519 const float nyo = wyo/dstH;
2521 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2522 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2523 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2524 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2525 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2527 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2528 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2531 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2532 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2536 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2546 bool verifyTextureResult (tcu::TestContext& testCtx,
2547 const tcu::ConstPixelBufferAccess& result,
2548 const tcu::Texture1DArrayView& src,
2549 const float* texCoord,
2550 const ReferenceParams& sampleParams,
2551 const tcu::LookupPrecision& lookupPrec,
2552 const tcu::LodPrecision& lodPrec,
2553 const tcu::PixelFormat& pixelFormat)
2555 tcu::TestLog& log = testCtx.getLog();
2556 tcu::Surface reference (result.getWidth(), result.getHeight());
2557 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2558 int numFailedPixels;
2560 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2562 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2563 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2565 if (numFailedPixels > 0)
2566 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2568 log << TestLog::ImageSet("VerifyResult", "Verification result")
2569 << TestLog::Image("Rendered", "Rendered image", result);
2571 if (numFailedPixels > 0)
2573 log << TestLog::Image("Reference", "Ideal reference image", reference)
2574 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2577 log << TestLog::EndImageSet;
2579 return numFailedPixels == 0;
2582 bool verifyTextureResult (tcu::TestContext& testCtx,
2583 const tcu::ConstPixelBufferAccess& result,
2584 const tcu::Texture2DArrayView& src,
2585 const float* texCoord,
2586 const ReferenceParams& sampleParams,
2587 const tcu::LookupPrecision& lookupPrec,
2588 const tcu::LodPrecision& lodPrec,
2589 const tcu::PixelFormat& pixelFormat)
2591 tcu::TestLog& log = testCtx.getLog();
2592 tcu::Surface reference (result.getWidth(), result.getHeight());
2593 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2594 int numFailedPixels;
2596 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2598 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2599 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2601 if (numFailedPixels > 0)
2602 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2604 log << TestLog::ImageSet("VerifyResult", "Verification result")
2605 << TestLog::Image("Rendered", "Rendered image", result);
2607 if (numFailedPixels > 0)
2609 log << TestLog::Image("Reference", "Ideal reference image", reference)
2610 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2613 log << TestLog::EndImageSet;
2615 return numFailedPixels == 0;
2618 //! Verifies texture lookup results and returns number of failed pixels.
2619 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2620 const tcu::ConstPixelBufferAccess& reference,
2621 const tcu::PixelBufferAccess& errorMask,
2622 const tcu::TextureCubeArrayView& baseView,
2623 const float* texCoord,
2624 const ReferenceParams& sampleParams,
2625 const tcu::LookupPrecision& lookupPrec,
2626 const tcu::IVec4& coordBits,
2627 const tcu::LodPrecision& lodPrec,
2628 qpWatchDog* watchDog)
2630 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2631 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2633 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
2634 const tcu::TextureCubeArrayView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
2636 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2637 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2638 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2639 const tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2641 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2642 const float dstW = float(dstSize.x());
2643 const float dstH = float(dstSize.y());
2644 const int srcSize = src.getSize();
2646 // Coordinates per triangle.
2647 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2648 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2649 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2650 const tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2651 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2653 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2655 const float posEps = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2659 const tcu::Vec2 lodOffsets[] =
2666 // \note Not strictly allowed by spec, but implementations do this in practice.
2673 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2675 for (int py = 0; py < result.getHeight(); py++)
2677 // Ugly hack, validation can take way too long at the moment.
2679 qpWatchDog_touch(watchDog);
2681 for (int px = 0; px < result.getWidth(); px++)
2683 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2684 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2686 // Try comparison to ideal reference first, and if that fails use slower verificator.
2687 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2689 const float wx = (float)px + 0.5f;
2690 const float wy = (float)py + 0.5f;
2691 const float nx = wx / dstW;
2692 const float ny = wy / dstH;
2694 const bool tri0 = nx + ny - posEps <= 1.0f;
2695 const bool tri1 = nx + ny + posEps >= 1.0f;
2699 DE_ASSERT(tri0 || tri1);
2701 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2702 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2704 const float triWx = triNdx ? dstW - wx : wx;
2705 const float triWy = triNdx ? dstH - wy : wy;
2706 const float triNx = triNdx ? 1.0f - nx : nx;
2707 const float triNy = triNdx ? 1.0f - ny : ny;
2709 const tcu::Vec4 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2710 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2711 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2712 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2713 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2714 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2715 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2716 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2717 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2718 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2720 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2722 // Compute lod bounds across lodOffsets range.
2723 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2725 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2726 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2727 const float nxo = wxo/dstW;
2728 const float nyo = wyo/dstH;
2730 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2731 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2732 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2733 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2734 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2735 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2736 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2737 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2738 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2739 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2741 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2742 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2745 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2747 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2756 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2766 bool verifyTextureResult (tcu::TestContext& testCtx,
2767 const tcu::ConstPixelBufferAccess& result,
2768 const tcu::TextureCubeArrayView& src,
2769 const float* texCoord,
2770 const ReferenceParams& sampleParams,
2771 const tcu::LookupPrecision& lookupPrec,
2772 const tcu::IVec4& coordBits,
2773 const tcu::LodPrecision& lodPrec,
2774 const tcu::PixelFormat& pixelFormat)
2776 tcu::TestLog& log = testCtx.getLog();
2777 tcu::Surface reference (result.getWidth(), result.getHeight());
2778 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2779 int numFailedPixels;
2781 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2783 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2784 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2786 if (numFailedPixels > 0)
2787 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2789 log << TestLog::ImageSet("VerifyResult", "Verification result")
2790 << TestLog::Image("Rendered", "Rendered image", result);
2792 if (numFailedPixels > 0)
2794 log << TestLog::Image("Reference", "Ideal reference image", reference)
2795 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2798 log << TestLog::EndImageSet;
2800 return numFailedPixels == 0;
2803 // Shadow lookup verification
2805 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2806 const tcu::ConstPixelBufferAccess& reference,
2807 const tcu::PixelBufferAccess& errorMask,
2808 const tcu::Texture2DView& src,
2809 const float* texCoord,
2810 const ReferenceParams& sampleParams,
2811 const tcu::TexComparePrecision& comparePrec,
2812 const tcu::LodPrecision& lodPrec,
2813 const tcu::Vec3& nonShadowThreshold)
2815 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2816 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2818 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2819 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2821 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2822 const float dstW = float(dstSize.x());
2823 const float dstH = float(dstSize.y());
2824 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2826 // Coordinates and lod per triangle.
2827 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2828 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2829 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2831 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2835 const tcu::Vec2 lodOffsets[] =
2843 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2845 for (int py = 0; py < result.getHeight(); py++)
2847 for (int px = 0; px < result.getWidth(); px++)
2849 const tcu::Vec4 resPix = result.getPixel(px, py);
2850 const tcu::Vec4 refPix = reference.getPixel(px, py);
2852 // Other channels should trivially match to reference.
2853 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2855 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2860 // Reference result is known to be a valid result, we can
2861 // skip verification if thes results are equal
2862 if (resPix.x() != refPix.x())
2864 const float wx = (float)px + 0.5f;
2865 const float wy = (float)py + 0.5f;
2866 const float nx = wx / dstW;
2867 const float ny = wy / dstH;
2869 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2870 const float triWx = triNdx ? dstW - wx : wx;
2871 const float triWy = triNdx ? dstH - wy : wy;
2872 const float triNx = triNdx ? 1.0f - nx : nx;
2873 const float triNy = triNdx ? 1.0f - ny : ny;
2875 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2876 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2877 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2878 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2879 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2880 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2882 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2884 // Compute lod bounds across lodOffsets range.
2885 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2887 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2888 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2889 const float nxo = wxo/dstW;
2890 const float nyo = wyo/dstH;
2892 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2893 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2894 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2895 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2896 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2898 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2899 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2902 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2903 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2907 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2917 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2918 const tcu::ConstPixelBufferAccess& reference,
2919 const tcu::PixelBufferAccess& errorMask,
2920 const tcu::TextureCubeView& src,
2921 const float* texCoord,
2922 const ReferenceParams& sampleParams,
2923 const tcu::TexComparePrecision& comparePrec,
2924 const tcu::LodPrecision& lodPrec,
2925 const tcu::Vec3& nonShadowThreshold)
2927 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2928 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2930 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2931 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2932 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2934 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2935 const float dstW = float(dstSize.x());
2936 const float dstH = float(dstSize.y());
2937 const int srcSize = src.getSize();
2939 // Coordinates per triangle.
2940 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2941 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2942 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2943 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2945 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2949 const tcu::Vec2 lodOffsets[] =
2957 tcu::clear(errorMask, tcu::RGBA::green().toVec());
2959 for (int py = 0; py < result.getHeight(); py++)
2961 for (int px = 0; px < result.getWidth(); px++)
2963 const tcu::Vec4 resPix = result.getPixel(px, py);
2964 const tcu::Vec4 refPix = reference.getPixel(px, py);
2966 // Other channels should trivially match to reference.
2967 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2969 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2974 // Reference result is known to be a valid result, we can
2975 // skip verification if thes results are equal
2976 if (resPix.x() != refPix.x())
2978 const float wx = (float)px + 0.5f;
2979 const float wy = (float)py + 0.5f;
2980 const float nx = wx / dstW;
2981 const float ny = wy / dstH;
2983 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2984 const float triWx = triNdx ? dstW - wx : wx;
2985 const float triWy = triNdx ? dstH - wy : wy;
2986 const float triNx = triNdx ? 1.0f - nx : nx;
2987 const float triNy = triNdx ? 1.0f - ny : ny;
2989 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2990 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2991 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2992 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2993 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2994 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2995 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2996 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2997 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2999 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
3001 // Compute lod bounds across lodOffsets range.
3002 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3004 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
3005 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
3006 const float nxo = wxo/dstW;
3007 const float nyo = wyo/dstH;
3009 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
3010 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
3011 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
3012 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
3013 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
3014 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
3015 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
3016 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
3017 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
3018 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
3020 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3021 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3024 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3025 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3029 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3039 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
3040 const tcu::ConstPixelBufferAccess& reference,
3041 const tcu::PixelBufferAccess& errorMask,
3042 const tcu::Texture2DArrayView& src,
3043 const float* texCoord,
3044 const ReferenceParams& sampleParams,
3045 const tcu::TexComparePrecision& comparePrec,
3046 const tcu::LodPrecision& lodPrec,
3047 const tcu::Vec3& nonShadowThreshold)
3049 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3050 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3052 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
3053 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
3054 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
3056 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
3057 const float dstW = float(dstSize.x());
3058 const float dstH = float(dstSize.y());
3059 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
3061 // Coordinates and lod per triangle.
3062 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
3063 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
3064 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
3065 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
3067 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3071 const tcu::Vec2 lodOffsets[] =
3079 tcu::clear(errorMask, tcu::RGBA::green().toVec());
3081 for (int py = 0; py < result.getHeight(); py++)
3083 for (int px = 0; px < result.getWidth(); px++)
3085 const tcu::Vec4 resPix = result.getPixel(px, py);
3086 const tcu::Vec4 refPix = reference.getPixel(px, py);
3088 // Other channels should trivially match to reference.
3089 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
3091 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3096 // Reference result is known to be a valid result, we can
3097 // skip verification if thes results are equal
3098 if (resPix.x() != refPix.x())
3100 const float wx = (float)px + 0.5f;
3101 const float wy = (float)py + 0.5f;
3102 const float nx = wx / dstW;
3103 const float ny = wy / dstH;
3105 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
3106 const float triWx = triNdx ? dstW - wx : wx;
3107 const float triWy = triNdx ? dstH - wy : wy;
3108 const float triNx = triNdx ? 1.0f - nx : nx;
3109 const float triNy = triNdx ? 1.0f - ny : ny;
3111 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3112 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
3113 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
3114 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
3115 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
3116 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
3117 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
3119 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
3121 // Compute lod bounds across lodOffsets range.
3122 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3124 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
3125 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
3126 const float nxo = wxo/dstW;
3127 const float nyo = wyo/dstH;
3129 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
3130 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
3131 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
3132 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
3133 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
3135 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3136 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3139 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3140 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3144 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
3154 // Mipmap generation comparison.
3156 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3158 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3160 const float dstW = float(dst.getWidth());
3161 const float dstH = float(dst.getHeight());
3162 const float srcW = float(src.getWidth());
3163 const float srcH = float(src.getHeight());
3166 // Translation to lookup verification parameters.
3167 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3168 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3169 tcu::LookupPrecision lookupPrec;
3171 lookupPrec.colorThreshold = precision.colorThreshold;
3172 lookupPrec.colorMask = precision.colorMask;
3173 lookupPrec.coordBits = tcu::IVec3(22);
3174 lookupPrec.uvwBits = precision.filterBits;
3176 for (int y = 0; y < dst.getHeight(); y++)
3177 for (int x = 0; x < dst.getWidth(); x++)
3179 const tcu::Vec4 result = dst.getPixel(x, y);
3180 const float cx = (float(x)+0.5f) / dstW * srcW;
3181 const float cy = (float(y)+0.5f) / dstH * srcH;
3182 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3184 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3192 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3194 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3196 const float dstW = float(dst.getWidth());
3197 const float dstH = float(dst.getHeight());
3198 const float srcW = float(src.getWidth());
3199 const float srcH = float(src.getHeight());
3202 // Translation to lookup verification parameters.
3203 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3204 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3205 tcu::LookupPrecision lookupPrec;
3207 lookupPrec.colorThreshold = precision.colorThreshold;
3208 lookupPrec.colorMask = precision.colorMask;
3209 lookupPrec.coordBits = tcu::IVec3(22);
3210 lookupPrec.uvwBits = precision.filterBits;
3212 for (int y = 0; y < dst.getHeight(); y++)
3213 for (int x = 0; x < dst.getWidth(); x++)
3215 const tcu::Vec4 result = dst.getPixel(x, y);
3216 const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
3217 const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
3218 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3220 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3228 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3230 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3231 DE_UNREF(precision);
3233 const float dstW = float(dst.getWidth());
3234 const float dstH = float(dst.getHeight());
3235 const float srcW = float(src.getWidth());
3236 const float srcH = float(src.getHeight());
3239 for (int y = 0; y < dst.getHeight(); y++)
3240 for (int x = 0; x < dst.getWidth(); x++)
3242 const tcu::Vec4 result = dst.getPixel(x, y);
3243 const int minX = deFloorFloatToInt32(((float)x-0.5f) / dstW * srcW);
3244 const int minY = deFloorFloatToInt32(((float)y-0.5f) / dstH * srcH);
3245 const int maxX = deCeilFloatToInt32(((float)x+1.5f) / dstW * srcW);
3246 const int maxY = deCeilFloatToInt32(((float)y+1.5f) / dstH * srcH);
3247 tcu::Vec4 minVal, maxVal;
3250 DE_ASSERT(minX < maxX && minY < maxY);
3252 for (int ky = minY; ky <= maxY; ky++)
3254 for (int kx = minX; kx <= maxX; kx++)
3256 const int sx = de::clamp(kx, 0, src.getWidth()-1);
3257 const int sy = de::clamp(ky, 0, src.getHeight()-1);
3258 const tcu::Vec4 sample = src.getPixel(sx, sy);
3260 if (ky == minY && kx == minX)
3267 minVal = min(sample, minVal);
3268 maxVal = max(sample, maxVal);
3273 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
3275 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
3283 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
3285 qpTestResult result = QP_TEST_RESULT_PASS;
3287 // Special comparison for level 0.
3289 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3290 const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
3294 log << TestLog::Message << "ERROR: Level 0 comparison failed!" << TestLog::EndMessage;
3295 result = QP_TEST_RESULT_FAIL;
3299 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3301 const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx-1);
3302 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx);
3303 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
3304 bool levelOk = false;
3306 // Try different comparisons in quality order.
3310 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3314 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3319 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3323 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3326 // At this point all high-quality methods have been used.
3327 if (!levelOk && result == QP_TEST_RESULT_PASS)
3328 result = QP_TEST_RESULT_QUALITY_WARNING;
3332 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3336 log << TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3340 result = QP_TEST_RESULT_FAIL;
3342 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
3343 << TestLog::Image("Result", "Result", dst);
3346 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3348 log << TestLog::EndImageSet;
3354 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
3356 qpTestResult result = QP_TEST_RESULT_PASS;
3358 static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
3359 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
3361 // Special comparison for level 0.
3362 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3364 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3365 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3366 const bool level0Ok = tcu::floatThresholdCompare(log,
3367 ("Level0Face" + de::toString(faceNdx)).c_str(),
3368 (string("Level 0, face ") + s_faceNames[face]).c_str(),
3369 level0Reference.getLevelFace(0, face),
3370 resultTexture.getLevelFace(0, face),
3371 threshold, tcu::COMPARE_LOG_RESULT);
3375 log << TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << TestLog::EndMessage;
3376 result = QP_TEST_RESULT_FAIL;
3380 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3382 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3384 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3385 const char* faceName = s_faceNames[face];
3386 const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx-1, face);
3387 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face);
3388 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
3389 bool levelOk = false;
3391 // Try different comparisons in quality order.
3395 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3399 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3404 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3408 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3411 // At this point all high-quality methods have been used.
3412 if (!levelOk && result == QP_TEST_RESULT_PASS)
3413 result = QP_TEST_RESULT_QUALITY_WARNING;
3417 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3421 log << TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3425 result = QP_TEST_RESULT_FAIL;
3427 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
3428 << TestLog::Image("Result", "Result", dst);
3431 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3433 log << TestLog::EndImageSet;
3440 // Logging utilities.
3442 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
3444 return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
3445 << "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
3446 << "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
3447 << "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3450 } // TextureTestUtil