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 inline 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 inline 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 inline 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& src, const tcu::Vec4& sq, const ReferenceParams& params)
431 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
433 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
434 int srcSize = src.getWidth();
436 // Coordinates and lod per triangle.
437 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
438 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod),
439 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) };
441 for (int y = 0; y < dst.getHeight(); y++)
443 for (int x = 0; x < dst.getWidth(); x++)
445 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
446 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
448 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
449 float triX = triNdx ? 1.0f-xf : xf;
450 float triY = triNdx ? 1.0f-yf : yf;
452 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
453 float lod = triLod[triNdx];
455 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
460 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
462 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
464 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
465 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
467 // Coordinates and lod per triangle.
468 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
469 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
470 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
471 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
473 for (int y = 0; y < dst.getHeight(); y++)
475 for (int x = 0; x < dst.getWidth(); x++)
477 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
478 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
480 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
481 float triX = triNdx ? 1.0f-xf : xf;
482 float triY = triNdx ? 1.0f-yf : yf;
484 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
485 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
486 float lod = triLod[triNdx];
488 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
493 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture1DView& src, const tcu::Vec4& sq, const ReferenceParams& params)
495 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
496 float dstW = (float)dst.getWidth();
497 float dstH = (float)dst.getHeight();
499 tcu::Vec4 uq = sq * (float)src.getWidth();
501 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
502 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
503 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
505 for (int py = 0; py < dst.getHeight(); py++)
507 for (int px = 0; px < dst.getWidth(); px++)
509 float wx = (float)px + 0.5f;
510 float wy = (float)py + 0.5f;
511 float nx = wx / dstW;
512 float ny = wy / dstH;
514 int triNdx = nx + ny >= 1.0f ? 1 : 0;
515 float triWx = triNdx ? dstW - wx : wx;
516 float triWy = triNdx ? dstH - wy : wy;
517 float triNx = triNdx ? 1.0f - nx : nx;
518 float triNy = triNdx ? 1.0f - ny : ny;
520 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
521 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
524 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
529 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture2DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
531 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
532 float dstW = (float)dst.getWidth();
533 float dstH = (float)dst.getHeight();
535 tcu::Vec4 uq = sq * (float)src.getWidth();
536 tcu::Vec4 vq = tq * (float)src.getHeight();
538 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
539 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
540 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
541 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
542 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
544 for (int py = 0; py < dst.getHeight(); py++)
546 for (int px = 0; px < dst.getWidth(); px++)
548 float wx = (float)px + 0.5f;
549 float wy = (float)py + 0.5f;
550 float nx = wx / dstW;
551 float ny = wy / dstH;
553 int triNdx = nx + ny >= 1.0f ? 1 : 0;
554 float triWx = triNdx ? dstW - wx : wx;
555 float triWy = triNdx ? dstH - wy : wy;
556 float triNx = triNdx ? 1.0f - nx : nx;
557 float triNy = triNdx ? 1.0f - ny : ny;
559 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
560 float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
561 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
564 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
569 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
571 const tcu::Texture2DView view = getSubView(src, params.baseLevel, params.maxLevel);
572 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
573 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
575 if (params.flags & ReferenceParams::PROJECTED)
576 sampleTextureProjected(dst, view, sq, tq, params);
578 sampleTextureNonProjected(dst, view, sq, tq, params);
581 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params)
583 const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel);
584 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
586 if (params.flags & ReferenceParams::PROJECTED)
587 sampleTextureProjected(dst, view, sq, params);
589 sampleTextureNonProjected(dst, view, sq, params);
592 static float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize)
594 const tcu::CubeFace face = tcu::selectCubeFace(coord);
599 // \note Derivate signs don't matter when computing lod
602 case tcu::CUBEFACE_NEGATIVE_X:
603 case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
604 case tcu::CUBEFACE_NEGATIVE_Y:
605 case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
606 case tcu::CUBEFACE_NEGATIVE_Z:
607 case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
613 const float sc = coord[sNdx];
614 const float tc = coord[tNdx];
615 const float ma = de::abs(coord[maNdx]);
616 const float scdx = coordDx[sNdx];
617 const float tcdx = coordDx[tNdx];
618 const float madx = de::abs(coordDx[maNdx]);
619 const float scdy = coordDy[sNdx];
620 const float tcdy = coordDy[tNdx];
621 const float mady = de::abs(coordDy[maNdx]);
622 const float dudx = float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma);
623 const float dvdx = float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma);
624 const float dudy = float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma);
625 const float dvdy = float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma);
627 return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
631 static void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
633 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
634 const float dstW = float(dstSize.x());
635 const float dstH = float(dstSize.y());
636 const int srcSize = src.getSize();
638 // Coordinates per triangle.
639 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
640 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
641 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
642 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
644 const float lodBias ((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
646 for (int py = 0; py < dst.getHeight(); py++)
648 for (int px = 0; px < dst.getWidth(); px++)
650 const float wx = (float)px + 0.5f;
651 const float wy = (float)py + 0.5f;
652 const float nx = wx / dstW;
653 const float ny = wy / dstH;
655 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
656 const float triNx = triNdx ? 1.0f - nx : nx;
657 const float triNy = triNdx ? 1.0f - ny : ny;
659 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
660 triangleInterpolate(triT[triNdx], triNx, triNy),
661 triangleInterpolate(triR[triNdx], triNx, triNy));
662 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
663 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
664 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
665 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
666 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
667 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
669 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod);
671 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py);
676 void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
678 const tcu::TextureCubeView view = getSubView(src, params.baseLevel, params.maxLevel);
679 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
680 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
681 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
683 return sampleTexture(dst, view, sq, tq, rq, params);
686 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
688 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
690 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
691 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
693 // Coordinates and lod per triangle.
694 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
695 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
696 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
697 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias,
698 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias};
700 for (int y = 0; y < dst.getHeight(); y++)
702 for (int x = 0; x < dst.getWidth(); x++)
704 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
705 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
707 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
708 float triX = triNdx ? 1.0f-xf : xf;
709 float triY = triNdx ? 1.0f-yf : yf;
711 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
712 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
713 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
714 float lod = triLod[triNdx];
716 dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
721 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params)
723 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
724 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
725 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
727 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
728 sampleTextureNonProjected(dst, src, sq, tq, rq, params);
731 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
733 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
735 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
736 deInt32 srcSize = src.getWidth();
738 // Coordinates and lod per triangle.
739 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
740 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
741 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
742 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
744 for (int y = 0; y < dst.getHeight(); y++)
746 for (int x = 0; x < dst.getWidth(); x++)
748 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
749 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
751 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
752 float triX = triNdx ? 1.0f-xf : xf;
753 float triY = triNdx ? 1.0f-yf : yf;
755 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
756 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
757 float lod = triLod[triNdx];
759 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
764 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params)
766 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
767 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
769 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
770 sampleTextureNonProjected(dst, src, sq, tq, params);
773 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture3DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
775 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
777 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
778 tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
780 // Coordinates and lod per triangle.
781 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
782 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
783 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
784 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod),
785 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) };
787 for (int y = 0; y < dst.getHeight(); y++)
789 for (int x = 0; x < dst.getWidth(); x++)
791 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
792 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
794 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
795 float triX = triNdx ? 1.0f-xf : xf;
796 float triY = triNdx ? 1.0f-yf : yf;
798 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
799 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
800 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
801 float lod = triLod[triNdx];
803 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
808 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture3DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
810 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
811 float dstW = (float)dst.getWidth();
812 float dstH = (float)dst.getHeight();
814 tcu::Vec4 uq = sq * (float)src.getWidth();
815 tcu::Vec4 vq = tq * (float)src.getHeight();
816 tcu::Vec4 wq = rq * (float)src.getDepth();
818 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
819 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
820 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
821 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
822 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
823 tcu::Vec3 triW[2] = { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) };
824 tcu::Vec3 triP[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
826 for (int py = 0; py < dst.getHeight(); py++)
828 for (int px = 0; px < dst.getWidth(); px++)
830 float wx = (float)px + 0.5f;
831 float wy = (float)py + 0.5f;
832 float nx = wx / dstW;
833 float ny = wy / dstH;
835 int triNdx = nx + ny >= 1.0f ? 1 : 0;
836 float triWx = triNdx ? dstW - wx : wx;
837 float triWy = triNdx ? dstH - wy : wy;
838 float triNx = triNdx ? 1.0f - nx : nx;
839 float triNy = triNdx ? 1.0f - ny : ny;
841 float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
842 float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
843 float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
844 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
847 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
852 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params)
854 const tcu::Texture3DView view = getSubView(src, params.baseLevel, params.maxLevel);
855 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
856 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
857 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
859 if (params.flags & ReferenceParams::PROJECTED)
860 sampleTextureProjected(dst, view, sq, tq, rq, params);
862 sampleTextureNonProjected(dst, view, sq, tq, rq, params);
865 static void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const tcu::Vec4& qq, const ReferenceParams& params)
867 const float dstW = (float)dst.getWidth();
868 const float dstH = (float)dst.getHeight();
870 // Coordinates per triangle.
871 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
872 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
873 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
874 tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
875 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
877 const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
879 for (int py = 0; py < dst.getHeight(); py++)
881 for (int px = 0; px < dst.getWidth(); px++)
883 const float wx = (float)px + 0.5f;
884 const float wy = (float)py + 0.5f;
885 const float nx = wx / dstW;
886 const float ny = wy / dstH;
888 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
889 const float triNx = triNdx ? 1.0f - nx : nx;
890 const float triNy = triNdx ? 1.0f - ny : ny;
892 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
893 triangleInterpolate(triT[triNdx], triNx, triNy),
894 triangleInterpolate(triR[triNdx], triNx, triNy));
896 const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy);
898 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
899 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
900 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
901 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
902 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
903 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
905 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
907 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
912 void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params)
914 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
915 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
916 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
917 tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
919 sampleTexture(dst, src, sq, tq, rq, qq, params);
922 void fetchTexture (const SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias)
924 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
925 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
927 for (int y = 0; y < dst.getHeight(); y++)
929 for (int x = 0; x < dst.getWidth(); x++)
931 const float yf = ((float)y + 0.5f) / (float)dst.getHeight();
932 const float xf = ((float)x + 0.5f) / (float)dst.getWidth();
934 const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
935 const float triX = triNdx ? 1.0f-xf : xf;
936 const float triY = triNdx ? 1.0f-yf : yf;
938 const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
940 dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
945 void clear (const SurfaceAccess& dst, const tcu::Vec4& color)
947 for (int y = 0; y < dst.getHeight(); y++)
948 for (int x = 0; x < dst.getWidth(); x++)
949 dst.setPixel(color, x, y);
952 bool compareImages (TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
954 return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
957 bool compareImages (TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
959 return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
962 int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
964 return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
967 inline int rangeDiff (int x, int a, int b)
977 inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
979 int rMin = de::min(a.getRed(), b.getRed());
980 int rMax = de::max(a.getRed(), b.getRed());
981 int gMin = de::min(a.getGreen(), b.getGreen());
982 int gMax = de::max(a.getGreen(), b.getGreen());
983 int bMin = de::min(a.getBlue(), b.getBlue());
984 int bMax = de::max(a.getBlue(), b.getBlue());
985 int aMin = de::min(a.getAlpha(), b.getAlpha());
986 int aMax = de::max(a.getAlpha(), b.getAlpha());
988 return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax),
989 rangeDiff(p.getGreen(), gMin, gMax),
990 rangeDiff(p.getBlue(), bMin, bMax),
991 rangeDiff(p.getAlpha(), aMin, aMax));
994 inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
996 tcu::RGBA diff = rangeDiff(p, a, b);
997 return diff.getRed() <= threshold.getRed() &&
998 diff.getGreen() <= threshold.getGreen() &&
999 diff.getBlue() <= threshold.getBlue() &&
1000 diff.getAlpha() <= threshold.getAlpha();
1003 RandomViewport::RandomViewport (const tcu::RenderTarget& renderTarget, int preferredWidth, int preferredHeight, deUint32 seed)
1006 , width (deMin32(preferredWidth, renderTarget.getWidth()))
1007 , height (deMin32(preferredHeight, renderTarget.getHeight()))
1009 de::Random rnd(seed);
1010 x = rnd.getInt(0, renderTarget.getWidth() - width);
1011 y = rnd.getInt(0, renderTarget.getHeight() - height);
1014 ProgramLibrary::ProgramLibrary (const glu::RenderContext& context, tcu::TestLog& log, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1015 : m_context (context)
1017 , m_glslVersion (glslVersion)
1018 , m_texCoordPrecision (texCoordPrecision)
1022 ProgramLibrary::~ProgramLibrary (void)
1027 void ProgramLibrary::clear (void)
1029 for (map<Program, glu::ShaderProgram*>::iterator i = m_programs.begin(); i != m_programs.end(); i++)
1032 i->second = DE_NULL;
1037 glu::ShaderProgram* ProgramLibrary::getProgram (Program program)
1039 if (m_programs.find(program) != m_programs.end())
1040 return m_programs[program]; // Return from cache.
1042 static const char* vertShaderTemplate =
1044 "${VTX_IN} highp vec4 a_position;\n"
1045 "${VTX_IN} ${PRECISION} ${TEXCOORD_TYPE} a_texCoord;\n"
1046 "${VTX_OUT} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1048 "void main (void)\n"
1050 " gl_Position = a_position;\n"
1051 " v_texCoord = a_texCoord;\n"
1053 static const char* fragShaderTemplate =
1055 "${FRAG_IN} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1056 "uniform ${PRECISION} float u_bias;\n"
1057 "uniform ${PRECISION} float u_ref;\n"
1058 "uniform ${PRECISION} vec4 u_colorScale;\n"
1059 "uniform ${PRECISION} vec4 u_colorBias;\n"
1060 "uniform ${PRECISION} ${SAMPLER_TYPE} u_sampler;\n"
1062 "void main (void)\n"
1064 " ${FRAG_COLOR} = ${LOOKUP} * u_colorScale + u_colorBias;\n"
1067 map<string, string> params;
1069 bool isCube = de::inRange<int>(program, PROGRAM_CUBE_FLOAT, PROGRAM_CUBE_SHADOW_BIAS);
1070 bool isArray = de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW)
1071 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW);
1073 bool is1D = de::inRange<int>(program, PROGRAM_1D_FLOAT, PROGRAM_1D_UINT_BIAS)
1074 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW)
1075 || de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1077 bool is2D = de::inRange<int>(program, PROGRAM_2D_FLOAT, PROGRAM_2D_UINT_BIAS)
1078 || de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW);
1080 bool is3D = de::inRange<int>(program, PROGRAM_3D_FLOAT, PROGRAM_3D_UINT_BIAS);
1081 bool isCubeArray = de::inRange<int>(program, PROGRAM_CUBE_ARRAY_FLOAT, PROGRAM_CUBE_ARRAY_SHADOW);
1082 bool isBuffer = de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1084 if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1086 params["FRAG_HEADER"] = "";
1087 params["VTX_HEADER"] = "";
1088 params["VTX_IN"] = "attribute";
1089 params["VTX_OUT"] = "varying";
1090 params["FRAG_IN"] = "varying";
1091 params["FRAG_COLOR"] = "gl_FragColor";
1093 else if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1095 const string version = glu::getGLSLVersionDeclaration(m_glslVersion);
1096 const char* ext = DE_NULL;
1098 if (isCubeArray && glu::glslVersionIsES(m_glslVersion))
1099 ext = "GL_EXT_texture_cube_map_array";
1100 else if (isBuffer && glu::glslVersionIsES(m_glslVersion))
1101 ext = "GL_EXT_texture_buffer";
1103 params["FRAG_HEADER"] = version + (ext ? string("\n#extension ") + ext + " : require" : string()) + "\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1104 params["VTX_HEADER"] = version + "\n";
1105 params["VTX_IN"] = "in";
1106 params["VTX_OUT"] = "out";
1107 params["FRAG_IN"] = "in";
1108 params["FRAG_COLOR"] = "dEQP_FragColor";
1111 DE_ASSERT(!"Unsupported version");
1113 params["PRECISION"] = glu::getPrecisionName(m_texCoordPrecision);
1116 params["TEXCOORD_TYPE"] = "vec4";
1117 else if (isCube || (is2D && isArray) || is3D)
1118 params["TEXCOORD_TYPE"] = "vec3";
1119 else if ((is1D && isArray) || is2D)
1120 params["TEXCOORD_TYPE"] = "vec2";
1122 params["TEXCOORD_TYPE"] = "float";
1124 DE_ASSERT(DE_FALSE);
1126 const char* sampler = DE_NULL;
1127 const char* lookup = DE_NULL;
1129 if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1133 case PROGRAM_2D_FLOAT: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1134 case PROGRAM_2D_INT: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1135 case PROGRAM_2D_UINT: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1136 case PROGRAM_2D_SHADOW: sampler = "sampler2DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1137 case PROGRAM_2D_FLOAT_BIAS: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1138 case PROGRAM_2D_INT_BIAS: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1139 case PROGRAM_2D_UINT_BIAS: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1140 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;
1141 case PROGRAM_1D_FLOAT: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1142 case PROGRAM_1D_INT: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1143 case PROGRAM_1D_UINT: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1144 case PROGRAM_1D_SHADOW: sampler = "sampler1DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1145 case PROGRAM_1D_FLOAT_BIAS: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1146 case PROGRAM_1D_INT_BIAS: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1147 case PROGRAM_1D_UINT_BIAS: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1148 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;
1149 case PROGRAM_CUBE_FLOAT: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord)"; break;
1150 case PROGRAM_CUBE_INT: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1151 case PROGRAM_CUBE_UINT: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1152 case PROGRAM_CUBE_SHADOW: sampler = "samplerCubeShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1153 case PROGRAM_CUBE_FLOAT_BIAS: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1154 case PROGRAM_CUBE_INT_BIAS: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1155 case PROGRAM_CUBE_UINT_BIAS: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1156 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;
1157 case PROGRAM_2D_ARRAY_FLOAT: sampler = "sampler2DArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1158 case PROGRAM_2D_ARRAY_INT: sampler = "isampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1159 case PROGRAM_2D_ARRAY_UINT: sampler = "usampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1160 case PROGRAM_2D_ARRAY_SHADOW: sampler = "sampler2DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1161 case PROGRAM_3D_FLOAT: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1162 case PROGRAM_3D_INT: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1163 case PROGRAM_3D_UINT: sampler = "usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1164 case PROGRAM_3D_FLOAT_BIAS: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1165 case PROGRAM_3D_INT_BIAS: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1166 case PROGRAM_3D_UINT_BIAS: sampler = "usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1167 case PROGRAM_CUBE_ARRAY_FLOAT: sampler = "samplerCubeArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1168 case PROGRAM_CUBE_ARRAY_INT: sampler = "isamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1169 case PROGRAM_CUBE_ARRAY_UINT: sampler = "usamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1170 case PROGRAM_CUBE_ARRAY_SHADOW: sampler = "samplerCubeArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1171 case PROGRAM_1D_ARRAY_FLOAT: sampler = "sampler1DArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1172 case PROGRAM_1D_ARRAY_INT: sampler = "isampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1173 case PROGRAM_1D_ARRAY_UINT: sampler = "usampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1174 case PROGRAM_1D_ARRAY_SHADOW: sampler = "sampler1DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1175 case PROGRAM_BUFFER_FLOAT: sampler = "samplerBuffer"; lookup = "texelFetch(u_sampler, int(v_texCoord))"; break;
1176 case PROGRAM_BUFFER_INT: sampler = "isamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break;
1177 case PROGRAM_BUFFER_UINT: sampler = "usamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break;
1182 else if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1184 sampler = isCube ? "samplerCube" : "sampler2D";
1188 case PROGRAM_2D_FLOAT: lookup = "texture2D(u_sampler, v_texCoord)"; break;
1189 case PROGRAM_2D_FLOAT_BIAS: lookup = "texture2D(u_sampler, v_texCoord, u_bias)"; break;
1190 case PROGRAM_CUBE_FLOAT: lookup = "textureCube(u_sampler, v_texCoord)"; break;
1191 case PROGRAM_CUBE_FLOAT_BIAS: lookup = "textureCube(u_sampler, v_texCoord, u_bias)"; break;
1197 DE_ASSERT(!"Unsupported version");
1199 params["SAMPLER_TYPE"] = sampler;
1200 params["LOOKUP"] = lookup;
1202 std::string vertSrc = tcu::StringTemplate(vertShaderTemplate).specialize(params);
1203 std::string fragSrc = tcu::StringTemplate(fragShaderTemplate).specialize(params);
1205 glu::ShaderProgram* progObj = new glu::ShaderProgram(m_context, glu::makeVtxFragSources(vertSrc, fragSrc));
1206 if (!progObj->isOk())
1210 TCU_FAIL("Failed to compile shader program");
1215 m_programs[program] = progObj;
1226 TextureRenderer::TextureRenderer (const glu::RenderContext& context, tcu::TestLog& log, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1227 : m_renderCtx (context)
1229 , m_programLibrary (context, log, glslVersion, texCoordPrecision)
1233 TextureRenderer::~TextureRenderer (void)
1238 void TextureRenderer::clear (void)
1240 m_programLibrary.clear();
1243 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, TextureType texType)
1245 renderQuad(texUnit, texCoord, RenderParams(texType));
1248 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, const RenderParams& params)
1250 const glw::Functions& gl = m_renderCtx.getFunctions();
1251 tcu::Vec4 wCoord = params.flags & RenderParams::PROJECTED ? params.w : tcu::Vec4(1.0f);
1252 bool useBias = !!(params.flags & RenderParams::USE_BIAS);
1253 bool logUniforms = !!(params.flags & RenderParams::LOG_UNIFORMS);
1255 // Render quad with texture.
1258 -1.0f*wCoord.x(), -1.0f*wCoord.x(), 0.0f, wCoord.x(),
1259 -1.0f*wCoord.y(), +1.0f*wCoord.y(), 0.0f, wCoord.y(),
1260 +1.0f*wCoord.z(), -1.0f*wCoord.z(), 0.0f, wCoord.z(),
1261 +1.0f*wCoord.w(), +1.0f*wCoord.w(), 0.0f, wCoord.w()
1263 static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
1265 Program progSpec = PROGRAM_LAST;
1267 if (params.texType == TEXTURETYPE_2D)
1271 switch (params.samplerType)
1273 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_2D_FLOAT_BIAS : PROGRAM_2D_FLOAT; break;
1274 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_2D_INT_BIAS : PROGRAM_2D_INT; break;
1275 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_2D_UINT_BIAS : PROGRAM_2D_UINT; break;
1276 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_2D_SHADOW_BIAS : PROGRAM_2D_SHADOW; break;
1277 default: DE_ASSERT(false);
1280 else if (params.texType == TEXTURETYPE_1D)
1284 switch (params.samplerType)
1286 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_1D_FLOAT_BIAS : PROGRAM_1D_FLOAT; break;
1287 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_1D_INT_BIAS : PROGRAM_1D_INT; break;
1288 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_1D_UINT_BIAS : PROGRAM_1D_UINT; break;
1289 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_1D_SHADOW_BIAS : PROGRAM_1D_SHADOW; break;
1290 default: DE_ASSERT(false);
1293 else if (params.texType == TEXTURETYPE_CUBE)
1297 switch (params.samplerType)
1299 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_CUBE_FLOAT_BIAS : PROGRAM_CUBE_FLOAT; break;
1300 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_CUBE_INT_BIAS : PROGRAM_CUBE_INT; break;
1301 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_CUBE_UINT_BIAS : PROGRAM_CUBE_UINT; break;
1302 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_CUBE_SHADOW_BIAS : PROGRAM_CUBE_SHADOW; break;
1303 default: DE_ASSERT(false);
1306 else if (params.texType == TEXTURETYPE_3D)
1310 switch (params.samplerType)
1312 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_3D_FLOAT_BIAS : PROGRAM_3D_FLOAT; break;
1313 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_3D_INT_BIAS : PROGRAM_3D_INT; break;
1314 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_3D_UINT_BIAS : PROGRAM_3D_UINT; break;
1315 default: DE_ASSERT(false);
1318 else if (params.texType == TEXTURETYPE_2D_ARRAY)
1320 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1324 switch (params.samplerType)
1326 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_2D_ARRAY_FLOAT; break;
1327 case SAMPLERTYPE_INT: progSpec = PROGRAM_2D_ARRAY_INT; break;
1328 case SAMPLERTYPE_UINT: progSpec = PROGRAM_2D_ARRAY_UINT; break;
1329 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_2D_ARRAY_SHADOW; break;
1330 default: DE_ASSERT(false);
1333 else if (params.texType == TEXTURETYPE_CUBE_ARRAY)
1335 DE_ASSERT(!useBias);
1339 switch (params.samplerType)
1341 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_CUBE_ARRAY_FLOAT; break;
1342 case SAMPLERTYPE_INT: progSpec = PROGRAM_CUBE_ARRAY_INT; break;
1343 case SAMPLERTYPE_UINT: progSpec = PROGRAM_CUBE_ARRAY_UINT; break;
1344 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_CUBE_ARRAY_SHADOW; break;
1345 default: DE_ASSERT(false);
1348 else if (params.texType == TEXTURETYPE_1D_ARRAY)
1350 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1354 switch (params.samplerType)
1356 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_1D_ARRAY_FLOAT; break;
1357 case SAMPLERTYPE_INT: progSpec = PROGRAM_1D_ARRAY_INT; break;
1358 case SAMPLERTYPE_UINT: progSpec = PROGRAM_1D_ARRAY_UINT; break;
1359 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_1D_ARRAY_SHADOW; break;
1360 default: DE_ASSERT(false);
1363 else if (params.texType == TEXTURETYPE_BUFFER)
1367 switch (params.samplerType)
1369 case SAMPLERTYPE_FETCH_FLOAT: progSpec = PROGRAM_BUFFER_FLOAT; break;
1370 case SAMPLERTYPE_FETCH_INT: progSpec = PROGRAM_BUFFER_INT; break;
1371 case SAMPLERTYPE_FETCH_UINT: progSpec = PROGRAM_BUFFER_UINT; break;
1372 default: DE_ASSERT(false);
1376 DE_ASSERT(DE_FALSE);
1378 glu::ShaderProgram* program = m_programLibrary.getProgram(progSpec);
1380 // \todo [2012-09-26 pyry] Move to ProgramLibrary and log unique programs only(?)
1381 if (params.flags & RenderParams::LOG_PROGRAMS)
1384 GLU_EXPECT_NO_ERROR(gl.getError(), "Set vertex attributes");
1386 // Program and uniforms.
1387 deUint32 prog = program->getProgram();
1388 gl.useProgram(prog);
1390 gl.uniform1i(gl.getUniformLocation(prog, "u_sampler"), texUnit);
1392 m_log << TestLog::Message << "u_sampler = " << texUnit << TestLog::EndMessage;
1396 gl.uniform1f(gl.getUniformLocation(prog, "u_bias"), params.bias);
1398 m_log << TestLog::Message << "u_bias = " << params.bias << TestLog::EndMessage;
1401 if (params.samplerType == SAMPLERTYPE_SHADOW)
1403 gl.uniform1f(gl.getUniformLocation(prog, "u_ref"), params.ref);
1405 m_log << TestLog::Message << "u_ref = " << params.ref << TestLog::EndMessage;
1408 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorScale"), 1, params.colorScale.getPtr());
1409 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorBias"), 1, params.colorBias.getPtr());
1413 m_log << TestLog::Message << "u_colorScale = " << params.colorScale << TestLog::EndMessage;
1414 m_log << TestLog::Message << "u_colorBias = " << params.colorBias << TestLog::EndMessage;
1417 GLU_EXPECT_NO_ERROR(gl.getError(), "Set program state");
1420 const glu::VertexArrayBinding vertexArrays[] =
1422 glu::va::Float("a_position", 4, 4, 0, &position[0]),
1423 glu::va::Float("a_texCoord", numComps, 4, 0, texCoord)
1425 glu::draw(m_renderCtx, prog, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
1426 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1430 void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
1440 void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
1444 dst[0] = left; dst[1] = (float)layerNdx;
1445 dst[2] = left; dst[3] = (float)layerNdx;
1446 dst[4] = right; dst[5] = (float)layerNdx;
1447 dst[6] = right; dst[7] = (float)layerNdx;
1450 void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1454 dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y();
1455 dst[2] = bottomLeft.x(); dst[3] = topRight.y();
1456 dst[4] = topRight.x(); dst[5] = bottomLeft.y();
1457 dst[6] = topRight.x(); dst[7] = topRight.y();
1460 void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1464 dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx;
1465 dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx;
1466 dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx;
1467 dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx;
1470 void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
1472 tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1473 tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1474 tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1475 tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1477 tcu::Vec3 v0 = p0 + (p1-p0)*f0;
1478 tcu::Vec3 v1 = p0 + (p1-p0)*f1;
1479 tcu::Vec3 v2 = p0 + (p1-p0)*f2;
1480 tcu::Vec3 v3 = p0 + (p1-p0)*f3;
1484 dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
1485 dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
1486 dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
1487 dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
1490 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
1492 static const float texCoordNegX[] =
1495 -1.0f, -1.0f, -1.0f,
1499 static const float texCoordPosX[] =
1506 static const float texCoordNegY[] =
1509 -1.0f, -1.0f, -1.0f,
1513 static const float texCoordPosY[] =
1515 -1.0f, +1.0f, -1.0f,
1520 static const float texCoordNegZ[] =
1527 static const float texCoordPosZ[] =
1530 -1.0f, -1.0f, +1.0f,
1535 const float* texCoord = DE_NULL;
1536 int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX);
1540 case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
1541 case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
1542 case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
1543 case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
1544 case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
1545 case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
1547 DE_ASSERT(DE_FALSE);
1551 dst.resize(texCoordSize);
1552 std::copy(texCoord, texCoord+texCoordSize, dst.begin());
1555 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1566 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1567 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1568 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1569 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1570 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1571 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1573 DE_ASSERT(DE_FALSE);
1579 dst[0+mRow] = mSign;
1580 dst[3+mRow] = mSign;
1581 dst[6+mRow] = mSign;
1582 dst[9+mRow] = mSign;
1584 dst[0+sRow] = sSign * bottomLeft.x();
1585 dst[3+sRow] = sSign * bottomLeft.x();
1586 dst[6+sRow] = sSign * topRight.x();
1587 dst[9+sRow] = sSign * topRight.x();
1589 dst[0+tRow] = tSign * bottomLeft.y();
1590 dst[3+tRow] = tSign * topRight.y();
1591 dst[6+tRow] = tSign * bottomLeft.y();
1592 dst[9+tRow] = tSign * topRight.y();
1595 void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
1604 const float l0 = layerRange.x();
1605 const float l1 = layerRange.y();
1609 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1610 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1611 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1612 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1613 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1614 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1616 DE_ASSERT(DE_FALSE);
1622 dst[ 0+mRow] = mSign;
1623 dst[ 4+mRow] = mSign;
1624 dst[ 8+mRow] = mSign;
1625 dst[12+mRow] = mSign;
1627 dst[ 0+sRow] = sSign * bottomLeft.x();
1628 dst[ 4+sRow] = sSign * bottomLeft.x();
1629 dst[ 8+sRow] = sSign * topRight.x();
1630 dst[12+sRow] = sSign * topRight.x();
1632 dst[ 0+tRow] = tSign * bottomLeft.y();
1633 dst[ 4+tRow] = tSign * topRight.y();
1634 dst[ 8+tRow] = tSign * bottomLeft.y();
1635 dst[12+tRow] = tSign * topRight.y();
1640 dst[ 4+qRow] = l0*0.5f + l1*0.5f;
1641 dst[ 8+qRow] = l0*0.5f + l1*0.5f;
1653 // Texture result verification
1655 //! Verifies texture lookup results and returns number of failed pixels.
1656 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1657 const tcu::ConstPixelBufferAccess& reference,
1658 const tcu::PixelBufferAccess& errorMask,
1659 const tcu::Texture1DView& baseView,
1660 const float* texCoord,
1661 const ReferenceParams& sampleParams,
1662 const tcu::LookupPrecision& lookupPrec,
1663 const tcu::LodPrecision& lodPrec,
1664 qpWatchDog* watchDog)
1666 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1667 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1669 const tcu::Texture1DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1671 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1673 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1674 const float dstW = float(dstSize.x());
1675 const float dstH = float(dstSize.y());
1676 const int srcSize = src.getWidth();
1678 // Coordinates and lod per triangle.
1679 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1680 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1682 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1686 const tcu::Vec2 lodOffsets[] =
1694 tcu::clear(errorMask, tcu::RGBA::green.toVec());
1696 for (int py = 0; py < result.getHeight(); py++)
1698 // Ugly hack, validation can take way too long at the moment.
1700 qpWatchDog_touch(watchDog);
1702 for (int px = 0; px < result.getWidth(); px++)
1704 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1705 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1707 // Try comparison to ideal reference first, and if that fails use slower verificator.
1708 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1710 const float wx = (float)px + 0.5f;
1711 const float wy = (float)py + 0.5f;
1712 const float nx = wx / dstW;
1713 const float ny = wy / dstH;
1715 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1716 const float triWx = triNdx ? dstW - wx : wx;
1717 const float triWy = triNdx ? dstH - wy : wy;
1718 const float triNx = triNdx ? 1.0f - nx : nx;
1719 const float triNy = triNdx ? 1.0f - ny : ny;
1721 const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1722 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1723 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1725 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1727 // Compute lod bounds across lodOffsets range.
1728 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1730 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1731 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1732 const float nxo = wxo/dstW;
1733 const float nyo = wyo/dstH;
1735 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1736 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1737 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1739 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1740 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1743 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1744 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1748 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
1758 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1759 const tcu::ConstPixelBufferAccess& reference,
1760 const tcu::PixelBufferAccess& errorMask,
1761 const tcu::Texture2DView& baseView,
1762 const float* texCoord,
1763 const ReferenceParams& sampleParams,
1764 const tcu::LookupPrecision& lookupPrec,
1765 const tcu::LodPrecision& lodPrec,
1766 qpWatchDog* watchDog)
1768 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1769 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1771 const tcu::Texture2DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1773 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1774 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1776 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1777 const float dstW = float(dstSize.x());
1778 const float dstH = float(dstSize.y());
1779 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
1781 // Coordinates and lod per triangle.
1782 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1783 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1784 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1786 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1790 const tcu::Vec2 lodOffsets[] =
1798 tcu::clear(errorMask, tcu::RGBA::green.toVec());
1800 for (int py = 0; py < result.getHeight(); py++)
1802 // Ugly hack, validation can take way too long at the moment.
1804 qpWatchDog_touch(watchDog);
1806 for (int px = 0; px < result.getWidth(); px++)
1808 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1809 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1811 // Try comparison to ideal reference first, and if that fails use slower verificator.
1812 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1814 const float wx = (float)px + 0.5f;
1815 const float wy = (float)py + 0.5f;
1816 const float nx = wx / dstW;
1817 const float ny = wy / dstH;
1819 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1820 const float triWx = triNdx ? dstW - wx : wx;
1821 const float triWy = triNdx ? dstH - wy : wy;
1822 const float triNx = triNdx ? 1.0f - nx : nx;
1823 const float triNy = triNdx ? 1.0f - ny : ny;
1825 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1826 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1827 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1828 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1829 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1830 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1832 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1834 // Compute lod bounds across lodOffsets range.
1835 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1837 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1838 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1839 const float nxo = wxo/dstW;
1840 const float nyo = wyo/dstH;
1842 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1843 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1844 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1845 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1846 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1848 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1849 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1852 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1853 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1857 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
1867 bool verifyTextureResult (tcu::TestContext& testCtx,
1868 const tcu::ConstPixelBufferAccess& result,
1869 const tcu::Texture1DView& src,
1870 const float* texCoord,
1871 const ReferenceParams& sampleParams,
1872 const tcu::LookupPrecision& lookupPrec,
1873 const tcu::LodPrecision& lodPrec,
1874 const tcu::PixelFormat& pixelFormat)
1876 tcu::TestLog& log = testCtx.getLog();
1877 tcu::Surface reference (result.getWidth(), result.getHeight());
1878 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1879 int numFailedPixels;
1881 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1883 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1884 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1886 if (numFailedPixels > 0)
1887 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1889 log << TestLog::ImageSet("VerifyResult", "Verification result")
1890 << TestLog::Image("Rendered", "Rendered image", result);
1892 if (numFailedPixels > 0)
1894 log << TestLog::Image("Reference", "Ideal reference image", reference)
1895 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1898 log << TestLog::EndImageSet;
1900 return numFailedPixels == 0;
1903 bool verifyTextureResult (tcu::TestContext& testCtx,
1904 const tcu::ConstPixelBufferAccess& result,
1905 const tcu::Texture2DView& src,
1906 const float* texCoord,
1907 const ReferenceParams& sampleParams,
1908 const tcu::LookupPrecision& lookupPrec,
1909 const tcu::LodPrecision& lodPrec,
1910 const tcu::PixelFormat& pixelFormat)
1912 tcu::TestLog& log = testCtx.getLog();
1913 tcu::Surface reference (result.getWidth(), result.getHeight());
1914 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1915 int numFailedPixels;
1917 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1919 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1920 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1922 if (numFailedPixels > 0)
1923 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1925 log << TestLog::ImageSet("VerifyResult", "Verification result")
1926 << TestLog::Image("Rendered", "Rendered image", result);
1928 if (numFailedPixels > 0)
1930 log << TestLog::Image("Reference", "Ideal reference image", reference)
1931 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1934 log << TestLog::EndImageSet;
1936 return numFailedPixels == 0;
1939 //! Verifies texture lookup results and returns number of failed pixels.
1940 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1941 const tcu::ConstPixelBufferAccess& reference,
1942 const tcu::PixelBufferAccess& errorMask,
1943 const tcu::TextureCubeView& baseView,
1944 const float* texCoord,
1945 const ReferenceParams& sampleParams,
1946 const tcu::LookupPrecision& lookupPrec,
1947 const tcu::LodPrecision& lodPrec,
1948 qpWatchDog* watchDog)
1950 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1951 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1953 const tcu::TextureCubeView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1955 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1956 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1957 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1959 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1960 const float dstW = float(dstSize.x());
1961 const float dstH = float(dstSize.y());
1962 const int srcSize = src.getSize();
1964 // Coordinates per triangle.
1965 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1966 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1967 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1968 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1970 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1972 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1976 const tcu::Vec2 lodOffsets[] =
1983 // \note Not strictly allowed by spec, but implementations do this in practice.
1990 tcu::clear(errorMask, tcu::RGBA::green.toVec());
1992 for (int py = 0; py < result.getHeight(); py++)
1994 // Ugly hack, validation can take way too long at the moment.
1996 qpWatchDog_touch(watchDog);
1998 for (int px = 0; px < result.getWidth(); px++)
2000 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2001 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2003 // Try comparison to ideal reference first, and if that fails use slower verificator.
2004 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2006 const float wx = (float)px + 0.5f;
2007 const float wy = (float)py + 0.5f;
2008 const float nx = wx / dstW;
2009 const float ny = wy / dstH;
2011 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
2012 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
2016 DE_ASSERT(tri0 || tri1);
2018 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2019 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2021 const float triWx = triNdx ? dstW - wx : wx;
2022 const float triWy = triNdx ? dstH - wy : wy;
2023 const float triNx = triNdx ? 1.0f - nx : nx;
2024 const float triNy = triNdx ? 1.0f - ny : ny;
2026 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2027 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2028 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2029 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2030 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2031 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2032 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2033 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2034 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2036 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2038 // Compute lod bounds across lodOffsets range.
2039 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2041 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2042 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2043 const float nxo = wxo/dstW;
2044 const float nyo = wyo/dstH;
2046 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2047 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2048 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2049 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2050 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2051 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2052 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2053 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2054 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2055 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2057 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2058 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2061 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2063 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2072 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2082 bool verifyTextureResult (tcu::TestContext& testCtx,
2083 const tcu::ConstPixelBufferAccess& result,
2084 const tcu::TextureCubeView& src,
2085 const float* texCoord,
2086 const ReferenceParams& sampleParams,
2087 const tcu::LookupPrecision& lookupPrec,
2088 const tcu::LodPrecision& lodPrec,
2089 const tcu::PixelFormat& pixelFormat)
2091 tcu::TestLog& log = testCtx.getLog();
2092 tcu::Surface reference (result.getWidth(), result.getHeight());
2093 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2094 int numFailedPixels;
2096 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2098 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2099 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2101 if (numFailedPixels > 0)
2102 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2104 log << TestLog::ImageSet("VerifyResult", "Verification result")
2105 << TestLog::Image("Rendered", "Rendered image", result);
2107 if (numFailedPixels > 0)
2109 log << TestLog::Image("Reference", "Ideal reference image", reference)
2110 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2113 log << TestLog::EndImageSet;
2115 return numFailedPixels == 0;
2118 //! Verifies texture lookup results and returns number of failed pixels.
2119 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2120 const tcu::ConstPixelBufferAccess& reference,
2121 const tcu::PixelBufferAccess& errorMask,
2122 const tcu::Texture3DView& baseView,
2123 const float* texCoord,
2124 const ReferenceParams& sampleParams,
2125 const tcu::LookupPrecision& lookupPrec,
2126 const tcu::LodPrecision& lodPrec,
2127 qpWatchDog* watchDog)
2129 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2130 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2132 const tcu::Texture3DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
2134 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2135 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2136 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2138 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2139 const float dstW = float(dstSize.x());
2140 const float dstH = float(dstSize.y());
2141 const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
2143 // Coordinates and lod per triangle.
2144 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2145 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2146 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2147 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2149 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2151 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
2155 const tcu::Vec2 lodOffsets[] =
2163 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2165 for (int py = 0; py < result.getHeight(); py++)
2167 // Ugly hack, validation can take way too long at the moment.
2169 qpWatchDog_touch(watchDog);
2171 for (int px = 0; px < result.getWidth(); px++)
2173 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2174 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2176 // Try comparison to ideal reference first, and if that fails use slower verificator.
2177 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2179 const float wx = (float)px + 0.5f;
2180 const float wy = (float)py + 0.5f;
2181 const float nx = wx / dstW;
2182 const float ny = wy / dstH;
2184 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
2185 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
2189 DE_ASSERT(tri0 || tri1);
2191 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2192 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2194 const float triWx = triNdx ? dstW - wx : wx;
2195 const float triWy = triNdx ? dstH - wy : wy;
2196 const float triNx = triNdx ? 1.0f - nx : nx;
2197 const float triNy = triNdx ? 1.0f - ny : ny;
2199 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2200 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2201 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2202 const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2203 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2204 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2205 const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2206 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2207 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2209 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
2211 // Compute lod bounds across lodOffsets range.
2212 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2214 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2215 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2216 const float nxo = wxo/dstW;
2217 const float nyo = wyo/dstH;
2219 const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2220 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2221 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2222 const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2223 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2224 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2225 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
2227 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2228 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2231 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2233 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2242 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2252 bool verifyTextureResult (tcu::TestContext& testCtx,
2253 const tcu::ConstPixelBufferAccess& result,
2254 const tcu::Texture3DView& src,
2255 const float* texCoord,
2256 const ReferenceParams& sampleParams,
2257 const tcu::LookupPrecision& lookupPrec,
2258 const tcu::LodPrecision& lodPrec,
2259 const tcu::PixelFormat& pixelFormat)
2261 tcu::TestLog& log = testCtx.getLog();
2262 tcu::Surface reference (result.getWidth(), result.getHeight());
2263 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2264 int numFailedPixels;
2266 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2268 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2269 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2271 if (numFailedPixels > 0)
2272 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2274 log << TestLog::ImageSet("VerifyResult", "Verification result")
2275 << TestLog::Image("Rendered", "Rendered image", result);
2277 if (numFailedPixels > 0)
2279 log << TestLog::Image("Reference", "Ideal reference image", reference)
2280 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2283 log << TestLog::EndImageSet;
2285 return numFailedPixels == 0;
2288 //! Verifies texture lookup results and returns number of failed pixels.
2289 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2290 const tcu::ConstPixelBufferAccess& reference,
2291 const tcu::PixelBufferAccess& errorMask,
2292 const tcu::Texture1DArrayView& src,
2293 const float* texCoord,
2294 const ReferenceParams& sampleParams,
2295 const tcu::LookupPrecision& lookupPrec,
2296 const tcu::LodPrecision& lodPrec,
2297 qpWatchDog* watchDog)
2299 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2300 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2302 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2303 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2305 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2306 const float dstW = float(dstSize.x());
2307 const float dstH = float(dstSize.y());
2308 const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored.
2310 // Coordinates and lod per triangle.
2311 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2312 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2313 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2315 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2319 const tcu::Vec2 lodOffsets[] =
2327 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2329 for (int py = 0; py < result.getHeight(); py++)
2331 // Ugly hack, validation can take way too long at the moment.
2333 qpWatchDog_touch(watchDog);
2335 for (int px = 0; px < result.getWidth(); px++)
2337 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2338 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2340 // Try comparison to ideal reference first, and if that fails use slower verificator.
2341 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2343 const float wx = (float)px + 0.5f;
2344 const float wy = (float)py + 0.5f;
2345 const float nx = wx / dstW;
2346 const float ny = wy / dstH;
2348 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2349 const float triWx = triNdx ? dstW - wx : wx;
2350 const float triWy = triNdx ? dstH - wy : wy;
2351 const float triNx = triNdx ? 1.0f - nx : nx;
2352 const float triNy = triNdx ? 1.0f - ny : ny;
2354 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2355 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2356 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
2357 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
2359 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
2361 // Compute lod bounds across lodOffsets range.
2362 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2364 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2365 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2366 const float nxo = wxo/dstW;
2367 const float nyo = wyo/dstH;
2369 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
2370 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
2371 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
2373 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2374 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2377 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2378 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2382 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2392 //! Verifies texture lookup results and returns number of failed pixels.
2393 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2394 const tcu::ConstPixelBufferAccess& reference,
2395 const tcu::PixelBufferAccess& errorMask,
2396 const tcu::Texture2DArrayView& src,
2397 const float* texCoord,
2398 const ReferenceParams& sampleParams,
2399 const tcu::LookupPrecision& lookupPrec,
2400 const tcu::LodPrecision& lodPrec,
2401 qpWatchDog* watchDog)
2403 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2404 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2406 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2407 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2408 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2410 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2411 const float dstW = float(dstSize.x());
2412 const float dstH = float(dstSize.y());
2413 const tcu::Vec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2415 // Coordinates and lod per triangle.
2416 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2417 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2418 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2419 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2421 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2425 const tcu::Vec2 lodOffsets[] =
2433 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2435 for (int py = 0; py < result.getHeight(); py++)
2437 // Ugly hack, validation can take way too long at the moment.
2439 qpWatchDog_touch(watchDog);
2441 for (int px = 0; px < result.getWidth(); px++)
2443 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2444 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2446 // Try comparison to ideal reference first, and if that fails use slower verificator.
2447 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2449 const float wx = (float)px + 0.5f;
2450 const float wy = (float)py + 0.5f;
2451 const float nx = wx / dstW;
2452 const float ny = wy / dstH;
2454 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2455 const float triWx = triNdx ? dstW - wx : wx;
2456 const float triWy = triNdx ? dstH - wy : wy;
2457 const float triNx = triNdx ? 1.0f - nx : nx;
2458 const float triNy = triNdx ? 1.0f - ny : ny;
2460 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2461 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2462 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2463 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2464 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2465 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2466 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2468 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2470 // Compute lod bounds across lodOffsets range.
2471 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2473 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2474 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2475 const float nxo = wxo/dstW;
2476 const float nyo = wyo/dstH;
2478 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2479 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2480 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2481 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2482 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2484 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2485 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2488 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2489 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2493 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2503 bool verifyTextureResult (tcu::TestContext& testCtx,
2504 const tcu::ConstPixelBufferAccess& result,
2505 const tcu::Texture1DArrayView& src,
2506 const float* texCoord,
2507 const ReferenceParams& sampleParams,
2508 const tcu::LookupPrecision& lookupPrec,
2509 const tcu::LodPrecision& lodPrec,
2510 const tcu::PixelFormat& pixelFormat)
2512 tcu::TestLog& log = testCtx.getLog();
2513 tcu::Surface reference (result.getWidth(), result.getHeight());
2514 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2515 int numFailedPixels;
2517 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2519 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2520 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2522 if (numFailedPixels > 0)
2523 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2525 log << TestLog::ImageSet("VerifyResult", "Verification result")
2526 << TestLog::Image("Rendered", "Rendered image", result);
2528 if (numFailedPixels > 0)
2530 log << TestLog::Image("Reference", "Ideal reference image", reference)
2531 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2534 log << TestLog::EndImageSet;
2536 return numFailedPixels == 0;
2539 bool verifyTextureResult (tcu::TestContext& testCtx,
2540 const tcu::ConstPixelBufferAccess& result,
2541 const tcu::Texture2DArrayView& src,
2542 const float* texCoord,
2543 const ReferenceParams& sampleParams,
2544 const tcu::LookupPrecision& lookupPrec,
2545 const tcu::LodPrecision& lodPrec,
2546 const tcu::PixelFormat& pixelFormat)
2548 tcu::TestLog& log = testCtx.getLog();
2549 tcu::Surface reference (result.getWidth(), result.getHeight());
2550 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2551 int numFailedPixels;
2553 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2555 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2556 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2558 if (numFailedPixels > 0)
2559 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2561 log << TestLog::ImageSet("VerifyResult", "Verification result")
2562 << TestLog::Image("Rendered", "Rendered image", result);
2564 if (numFailedPixels > 0)
2566 log << TestLog::Image("Reference", "Ideal reference image", reference)
2567 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2570 log << TestLog::EndImageSet;
2572 return numFailedPixels == 0;
2575 //! Verifies texture lookup results and returns number of failed pixels.
2576 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2577 const tcu::ConstPixelBufferAccess& reference,
2578 const tcu::PixelBufferAccess& errorMask,
2579 const tcu::TextureCubeArrayView& baseView,
2580 const float* texCoord,
2581 const ReferenceParams& sampleParams,
2582 const tcu::LookupPrecision& lookupPrec,
2583 const tcu::IVec4& coordBits,
2584 const tcu::LodPrecision& lodPrec,
2585 qpWatchDog* watchDog)
2587 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2588 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2590 const tcu::TextureCubeArrayView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
2592 // What is the 'q' in all these names? Also a two char name for something that is in scope for ~120 lines and only used twice each seems excessive
2593 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2594 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2595 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2596 const tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2598 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2599 const float dstW = float(dstSize.x());
2600 const float dstH = float(dstSize.y());
2601 const int srcSize = src.getSize();
2603 // Coordinates per triangle.
2604 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2605 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2606 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2607 const tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2608 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2610 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2612 const float posEps = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2616 const tcu::Vec2 lodOffsets[] =
2623 // \note Not strictly allowed by spec, but implementations do this in practice.
2630 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2632 for (int py = 0; py < result.getHeight(); py++)
2634 // Ugly hack, validation can take way too long at the moment.
2636 qpWatchDog_touch(watchDog);
2638 for (int px = 0; px < result.getWidth(); px++)
2640 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2641 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2643 // Try comparison to ideal reference first, and if that fails use slower verificator.
2644 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2646 const float wx = (float)px + 0.5f;
2647 const float wy = (float)py + 0.5f;
2648 const float nx = wx / dstW;
2649 const float ny = wy / dstH;
2651 const bool tri0 = nx + ny - posEps <= 1.0f;
2652 const bool tri1 = nx + ny + posEps >= 1.0f;
2656 DE_ASSERT(tri0 || tri1);
2658 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2659 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2661 const float triWx = triNdx ? dstW - wx : wx;
2662 const float triWy = triNdx ? dstH - wy : wy;
2663 const float triNx = triNdx ? 1.0f - nx : nx;
2664 const float triNy = triNdx ? 1.0f - ny : ny;
2666 const tcu::Vec4 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2667 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2668 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2669 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2670 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2671 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2672 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2673 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2674 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2675 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2677 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2679 // Compute lod bounds across lodOffsets range.
2680 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2682 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2683 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2684 const float nxo = wxo/dstW;
2685 const float nyo = wyo/dstH;
2687 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2688 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2689 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2690 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2691 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2692 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2693 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2694 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2695 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2696 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2698 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2699 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2702 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2704 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2713 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2723 bool verifyTextureResult (tcu::TestContext& testCtx,
2724 const tcu::ConstPixelBufferAccess& result,
2725 const tcu::TextureCubeArrayView& src,
2726 const float* texCoord,
2727 const ReferenceParams& sampleParams,
2728 const tcu::LookupPrecision& lookupPrec,
2729 const tcu::IVec4& coordBits,
2730 const tcu::LodPrecision& lodPrec,
2731 const tcu::PixelFormat& pixelFormat)
2733 tcu::TestLog& log = testCtx.getLog();
2734 tcu::Surface reference (result.getWidth(), result.getHeight());
2735 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2736 int numFailedPixels;
2738 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2740 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2741 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2743 if (numFailedPixels > 0)
2744 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2746 log << TestLog::ImageSet("VerifyResult", "Verification result")
2747 << TestLog::Image("Rendered", "Rendered image", result);
2749 if (numFailedPixels > 0)
2751 log << TestLog::Image("Reference", "Ideal reference image", reference)
2752 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2755 log << TestLog::EndImageSet;
2757 return numFailedPixels == 0;
2760 // Shadow lookup verification
2762 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2763 const tcu::ConstPixelBufferAccess& reference,
2764 const tcu::PixelBufferAccess& errorMask,
2765 const tcu::Texture2DView& src,
2766 const float* texCoord,
2767 const ReferenceParams& sampleParams,
2768 const tcu::TexComparePrecision& comparePrec,
2769 const tcu::LodPrecision& lodPrec,
2770 const tcu::Vec3& nonShadowThreshold)
2772 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2773 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2775 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2776 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2778 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2779 const float dstW = float(dstSize.x());
2780 const float dstH = float(dstSize.y());
2781 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2783 // Coordinates and lod per triangle.
2784 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2785 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2786 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2788 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2792 const tcu::Vec2 lodOffsets[] =
2800 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2802 for (int py = 0; py < result.getHeight(); py++)
2804 for (int px = 0; px < result.getWidth(); px++)
2806 const tcu::Vec4 resPix = result.getPixel(px, py);
2807 const tcu::Vec4 refPix = reference.getPixel(px, py);
2809 // Other channels should trivially match to reference.
2810 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2812 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2818 const float wx = (float)px + 0.5f;
2819 const float wy = (float)py + 0.5f;
2820 const float nx = wx / dstW;
2821 const float ny = wy / dstH;
2823 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2824 const float triWx = triNdx ? dstW - wx : wx;
2825 const float triWy = triNdx ? dstH - wy : wy;
2826 const float triNx = triNdx ? 1.0f - nx : nx;
2827 const float triNy = triNdx ? 1.0f - ny : ny;
2829 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2830 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2831 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2832 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2833 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2834 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2836 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2838 // Compute lod bounds across lodOffsets range.
2839 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2841 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2842 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2843 const float nxo = wxo/dstW;
2844 const float nyo = wyo/dstH;
2846 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2847 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2848 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2849 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2850 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2852 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2853 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2856 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2857 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2861 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2871 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2872 const tcu::ConstPixelBufferAccess& reference,
2873 const tcu::PixelBufferAccess& errorMask,
2874 const tcu::TextureCubeView& src,
2875 const float* texCoord,
2876 const ReferenceParams& sampleParams,
2877 const tcu::TexComparePrecision& comparePrec,
2878 const tcu::LodPrecision& lodPrec,
2879 const tcu::Vec3& nonShadowThreshold)
2881 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2882 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2884 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2885 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2886 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2888 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2889 const float dstW = float(dstSize.x());
2890 const float dstH = float(dstSize.y());
2891 const int srcSize = src.getSize();
2893 // Coordinates per triangle.
2894 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2895 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2896 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2897 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2899 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2903 const tcu::Vec2 lodOffsets[] =
2911 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2913 for (int py = 0; py < result.getHeight(); py++)
2915 for (int px = 0; px < result.getWidth(); px++)
2917 const tcu::Vec4 resPix = result.getPixel(px, py);
2918 const tcu::Vec4 refPix = reference.getPixel(px, py);
2920 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2922 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2928 const float wx = (float)px + 0.5f;
2929 const float wy = (float)py + 0.5f;
2930 const float nx = wx / dstW;
2931 const float ny = wy / dstH;
2933 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2934 const float triWx = triNdx ? dstW - wx : wx;
2935 const float triWy = triNdx ? dstH - wy : wy;
2936 const float triNx = triNdx ? 1.0f - nx : nx;
2937 const float triNy = triNdx ? 1.0f - ny : ny;
2939 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2940 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2941 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2942 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2943 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2944 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2945 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2946 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2947 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2949 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2951 // Compute lod bounds across lodOffsets range.
2952 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2954 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2955 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2956 const float nxo = wxo/dstW;
2957 const float nyo = wyo/dstH;
2959 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2960 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2961 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2962 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2963 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2964 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2965 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2966 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2967 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2968 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2970 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2971 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2974 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2975 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2979 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2989 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2990 const tcu::ConstPixelBufferAccess& reference,
2991 const tcu::PixelBufferAccess& errorMask,
2992 const tcu::Texture2DArrayView& src,
2993 const float* texCoord,
2994 const ReferenceParams& sampleParams,
2995 const tcu::TexComparePrecision& comparePrec,
2996 const tcu::LodPrecision& lodPrec,
2997 const tcu::Vec3& nonShadowThreshold)
2999 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3000 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3002 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
3003 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
3004 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
3006 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
3007 const float dstW = float(dstSize.x());
3008 const float dstH = float(dstSize.y());
3009 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
3011 // Coordinates and lod per triangle.
3012 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
3013 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
3014 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
3015 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
3017 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3021 const tcu::Vec2 lodOffsets[] =
3029 tcu::clear(errorMask, tcu::RGBA::green.toVec());
3031 for (int py = 0; py < result.getHeight(); py++)
3033 for (int px = 0; px < result.getWidth(); px++)
3035 const tcu::Vec4 resPix = result.getPixel(px, py);
3036 const tcu::Vec4 refPix = reference.getPixel(px, py);
3038 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
3040 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3046 const float wx = (float)px + 0.5f;
3047 const float wy = (float)py + 0.5f;
3048 const float nx = wx / dstW;
3049 const float ny = wy / dstH;
3051 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
3052 const float triWx = triNdx ? dstW - wx : wx;
3053 const float triWy = triNdx ? dstH - wy : wy;
3054 const float triNx = triNdx ? 1.0f - nx : nx;
3055 const float triNy = triNdx ? 1.0f - ny : ny;
3057 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3058 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
3059 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
3060 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
3061 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
3062 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
3063 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
3065 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
3067 // Compute lod bounds across lodOffsets range.
3068 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3070 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
3071 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
3072 const float nxo = wxo/dstW;
3073 const float nyo = wyo/dstH;
3075 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
3076 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
3077 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
3078 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
3079 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
3081 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3082 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3085 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3086 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3090 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3100 // Mipmap generation comparison.
3102 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3104 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3106 const float dstW = float(dst.getWidth());
3107 const float dstH = float(dst.getHeight());
3108 const float srcW = float(src.getWidth());
3109 const float srcH = float(src.getHeight());
3112 // Translation to lookup verification parameters.
3113 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3114 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3115 tcu::LookupPrecision lookupPrec;
3117 lookupPrec.colorThreshold = precision.colorThreshold;
3118 lookupPrec.colorMask = precision.colorMask;
3119 lookupPrec.coordBits = tcu::IVec3(22);
3120 lookupPrec.uvwBits = precision.filterBits;
3122 for (int y = 0; y < dst.getHeight(); y++)
3123 for (int x = 0; x < dst.getWidth(); x++)
3125 const tcu::Vec4 result = dst.getPixel(x, y);
3126 const float cx = (float(x)+0.5f) / dstW * srcW;
3127 const float cy = (float(y)+0.5f) / dstH * srcH;
3128 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3130 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3138 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3140 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3142 const float dstW = float(dst.getWidth());
3143 const float dstH = float(dst.getHeight());
3144 const float srcW = float(src.getWidth());
3145 const float srcH = float(src.getHeight());
3148 // Translation to lookup verification parameters.
3149 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3150 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3151 tcu::LookupPrecision lookupPrec;
3153 lookupPrec.colorThreshold = precision.colorThreshold;
3154 lookupPrec.colorMask = precision.colorMask;
3155 lookupPrec.coordBits = tcu::IVec3(22);
3156 lookupPrec.uvwBits = precision.filterBits;
3158 for (int y = 0; y < dst.getHeight(); y++)
3159 for (int x = 0; x < dst.getWidth(); x++)
3161 const tcu::Vec4 result = dst.getPixel(x, y);
3162 const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
3163 const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
3164 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3166 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3174 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3176 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3177 DE_UNREF(precision);
3179 const float dstW = float(dst.getWidth());
3180 const float dstH = float(dst.getHeight());
3181 const float srcW = float(src.getWidth());
3182 const float srcH = float(src.getHeight());
3185 for (int y = 0; y < dst.getHeight(); y++)
3186 for (int x = 0; x < dst.getWidth(); x++)
3188 const tcu::Vec4 result = dst.getPixel(x, y);
3189 const int minX = deFloorFloatToInt32(float(x-0.5f) / dstW * srcW);
3190 const int minY = deFloorFloatToInt32(float(y-0.5f) / dstH * srcH);
3191 const int maxX = deCeilFloatToInt32(float(x+1.5f) / dstW * srcW);
3192 const int maxY = deCeilFloatToInt32(float(y+1.5f) / dstH * srcH);
3193 tcu::Vec4 minVal, maxVal;
3196 DE_ASSERT(minX < maxX && minY < maxY);
3198 for (int ky = minY; ky <= maxY; ky++)
3200 for (int kx = minX; kx <= maxX; kx++)
3202 const int sx = de::clamp(kx, 0, src.getWidth()-1);
3203 const int sy = de::clamp(ky, 0, src.getHeight()-1);
3204 const tcu::Vec4 sample = src.getPixel(sx, sy);
3206 if (ky == minY && kx == minX)
3213 minVal = min(sample, minVal);
3214 maxVal = max(sample, maxVal);
3219 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
3221 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3229 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
3231 qpTestResult result = QP_TEST_RESULT_PASS;
3233 // Special comparison for level 0.
3235 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3236 const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
3240 log << TestLog::Message << "ERROR: Level 0 comparison failed!" << TestLog::EndMessage;
3241 result = QP_TEST_RESULT_FAIL;
3245 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3247 const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx-1);
3248 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx);
3249 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
3250 bool levelOk = false;
3252 // Try different comparisons in quality order.
3256 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3260 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3265 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3269 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3272 // At this point all high-quality methods have been used.
3273 if (!levelOk && result == QP_TEST_RESULT_PASS)
3274 result = QP_TEST_RESULT_QUALITY_WARNING;
3278 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3282 log << TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3286 result = QP_TEST_RESULT_FAIL;
3288 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
3289 << TestLog::Image("Result", "Result", dst);
3292 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3294 log << TestLog::EndImageSet;
3300 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
3302 qpTestResult result = QP_TEST_RESULT_PASS;
3304 static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
3305 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
3307 // Special comparison for level 0.
3308 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3310 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3311 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3312 const bool level0Ok = tcu::floatThresholdCompare(log,
3313 ("Level0Face" + de::toString(faceNdx)).c_str(),
3314 (string("Level 0, face ") + s_faceNames[face]).c_str(),
3315 level0Reference.getLevelFace(0, face),
3316 resultTexture.getLevelFace(0, face),
3317 threshold, tcu::COMPARE_LOG_RESULT);
3321 log << TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << TestLog::EndMessage;
3322 result = QP_TEST_RESULT_FAIL;
3326 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3328 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3330 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3331 const char* faceName = s_faceNames[face];
3332 const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx-1, face);
3333 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face);
3334 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
3335 bool levelOk = false;
3337 // Try different comparisons in quality order.
3341 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3345 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3350 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3354 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3357 // At this point all high-quality methods have been used.
3358 if (!levelOk && result == QP_TEST_RESULT_PASS)
3359 result = QP_TEST_RESULT_QUALITY_WARNING;
3363 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3367 log << TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3371 result = QP_TEST_RESULT_FAIL;
3373 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
3374 << TestLog::Image("Result", "Result", dst);
3377 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3379 log << TestLog::EndImageSet;
3386 // Logging utilities.
3388 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
3390 return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
3391 << "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
3392 << "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
3393 << "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3396 } // TextureTestUtil