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 inline float triQuadInterpolate (float x, float y, const tcu::Vec4& quad)
186 // \note Top left fill rule.
188 return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y);
190 return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
193 SurfaceAccess::SurfaceAccess (tcu::Surface& surface, const tcu::PixelFormat& colorFmt, int x, int y, int width, int height)
194 : m_surface (&surface)
195 , m_colorMask (getColorMask(colorFmt))
203 SurfaceAccess::SurfaceAccess (tcu::Surface& surface, const tcu::PixelFormat& colorFmt)
204 : m_surface (&surface)
205 , m_colorMask (getColorMask(colorFmt))
208 , m_width (surface.getWidth())
209 , m_height (surface.getHeight())
213 SurfaceAccess::SurfaceAccess (const SurfaceAccess& parent, int x, int y, int width, int height)
214 : m_surface (parent.m_surface)
215 , m_colorMask (parent.m_colorMask)
216 , m_x (parent.m_x + x)
217 , m_y (parent.m_y + y)
223 // 1D lookup LOD computation.
225 inline float computeLodFromDerivates (LodMode mode, float dudx, float dudy)
230 // \note [mika] Min and max bounds equal to exact with 1D textures
232 case LODMODE_MIN_BOUND:
233 case LODMODE_MAX_BOUND:
234 p = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
241 return deFloatLog2(p);
244 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, deInt32 srcSize, const tcu::Vec3& sq)
246 float dux = (sq.z() - sq.x()) * (float)srcSize;
247 float duy = (sq.y() - sq.x()) * (float)srcSize;
248 float dx = (float)dstSize.x();
249 float dy = (float)dstSize.y();
251 return computeLodFromDerivates(mode, dux/dx, duy/dy);
254 // 2D lookup LOD computation.
256 inline float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dudy, float dvdy)
262 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx), deFloatSqrt(dudy*dudy + dvdy*dvdy));
265 case LODMODE_MIN_BOUND:
266 case LODMODE_MAX_BOUND:
268 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
269 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
271 p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv;
279 return deFloatLog2(p);
282 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec2& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq)
284 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
285 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
286 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
287 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
288 float dx = (float)dstSize.x();
289 float dy = (float)dstSize.y();
291 return computeLodFromDerivates(mode, dux/dx, dvx/dx, duy/dy, dvy/dy);
294 // 3D lookup LOD computation.
296 inline float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy)
302 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx + dwdx*dwdx), deFloatSqrt(dudy*dudy + dvdy*dvdy + dwdy*dwdy));
305 case LODMODE_MIN_BOUND:
306 case LODMODE_MAX_BOUND:
308 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
309 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
310 float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy));
312 p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw);
320 return deFloatLog2(p);
323 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)
325 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
326 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
327 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
328 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
329 float dwx = (rq.z() - rq.x()) * (float)srcSize.z();
330 float dwy = (rq.y() - rq.x()) * (float)srcSize.z();
331 float dx = (float)dstSize.x();
332 float dy = (float)dstSize.y();
334 return computeLodFromDerivates(mode, dux/dx, dvx/dx, dwx/dx, duy/dy, dvy/dy, dwy/dy);
337 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
339 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]);
342 static inline float triDerivateX (const tcu::Vec3& s, const tcu::Vec3& w, float wx, float width, float ny)
344 float d = w[1]*w[2]*(width*(ny - 1.0f) + wx) - w[0]*(w[2]*width*ny + w[1]*wx);
345 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);
348 static inline float triDerivateY (const tcu::Vec3& s, const tcu::Vec3& w, float wy, float height, float nx)
350 float d = w[1]*w[2]*(height*(nx - 1.0f) + wy) - w[0]*(w[1]*height*nx + w[2]*wy);
351 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);
355 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& projection, float wx, float wy, float width, float height)
357 // Exact derivatives.
358 float dudx = triDerivateX(u, projection, wx, width, wy/height);
359 float dudy = triDerivateY(u, projection, wy, height, wx/width);
361 return computeLodFromDerivates(mode, dudx, dudy);
365 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)
367 // Exact derivatives.
368 float dudx = triDerivateX(u, projection, wx, width, wy/height);
369 float dvdx = triDerivateX(v, projection, wx, width, wy/height);
370 float dudy = triDerivateY(u, projection, wy, height, wx/width);
371 float dvdy = triDerivateY(v, projection, wy, height, wx/width);
373 return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy);
377 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)
379 // Exact derivatives.
380 float dudx = triDerivateX(u, projection, wx, width, wy/height);
381 float dvdx = triDerivateX(v, projection, wx, width, wy/height);
382 float dwdx = triDerivateX(w, projection, wx, width, wy/height);
383 float dudy = triDerivateY(u, projection, wy, height, wx/width);
384 float dvdy = triDerivateY(v, projection, wy, height, wx/width);
385 float dwdy = triDerivateY(w, projection, wy, height, wx/width);
387 return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy);
390 static inline tcu::Vec4 execSample (const tcu::Texture1DView& src, const ReferenceParams& params, float s, float lod)
392 if (params.samplerType == SAMPLERTYPE_SHADOW)
393 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f);
395 return src.sample(params.sampler, s, lod);
398 static inline tcu::Vec4 execSample (const tcu::Texture2DView& src, const ReferenceParams& params, float s, float t, float lod)
400 if (params.samplerType == SAMPLERTYPE_SHADOW)
401 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
403 return src.sample(params.sampler, s, t, lod);
406 static inline tcu::Vec4 execSample (const tcu::TextureCubeView& src, const ReferenceParams& params, float s, float t, float r, float lod)
408 if (params.samplerType == SAMPLERTYPE_SHADOW)
409 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
411 return src.sample(params.sampler, s, t, r, lod);
414 static inline tcu::Vec4 execSample (const tcu::Texture2DArrayView& src, const ReferenceParams& params, float s, float t, float r, float lod)
416 if (params.samplerType == SAMPLERTYPE_SHADOW)
417 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
419 return src.sample(params.sampler, s, t, r, lod);
422 static inline tcu::Vec4 execSample (const tcu::TextureCubeArrayView& src, const ReferenceParams& params, float s, float t, float r, float q, float lod)
424 if (params.samplerType == SAMPLERTYPE_SHADOW)
425 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f);
427 return src.sample(params.sampler, s, t, r, q, lod);
430 static inline tcu::Vec4 execSample (const tcu::Texture1DArrayView& src, const ReferenceParams& params, float s, float t, float lod)
432 if (params.samplerType == SAMPLERTYPE_SHADOW)
433 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
435 return src.sample(params.sampler, s, t, lod);
438 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DView& src, const tcu::Vec4& sq, const ReferenceParams& params)
440 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
442 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
443 int srcSize = src.getWidth();
445 // Coordinates and lod per triangle.
446 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
447 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod),
448 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) };
450 for (int y = 0; y < dst.getHeight(); y++)
452 for (int x = 0; x < dst.getWidth(); x++)
454 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
455 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
457 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
458 float triX = triNdx ? 1.0f-xf : xf;
459 float triY = triNdx ? 1.0f-yf : yf;
461 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
462 float lod = triLod[triNdx];
464 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
469 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
471 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
473 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
474 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
476 // Coordinates and lod per triangle.
477 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
478 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
479 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
480 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
482 for (int y = 0; y < dst.getHeight(); y++)
484 for (int x = 0; x < dst.getWidth(); x++)
486 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
487 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
489 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
490 float triX = triNdx ? 1.0f-xf : xf;
491 float triY = triNdx ? 1.0f-yf : yf;
493 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
494 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
495 float lod = triLod[triNdx];
497 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
502 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture1DView& src, const tcu::Vec4& sq, const ReferenceParams& params)
504 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
505 float dstW = (float)dst.getWidth();
506 float dstH = (float)dst.getHeight();
508 tcu::Vec4 uq = sq * (float)src.getWidth();
510 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
511 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
512 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
514 for (int py = 0; py < dst.getHeight(); py++)
516 for (int px = 0; px < dst.getWidth(); px++)
518 float wx = (float)px + 0.5f;
519 float wy = (float)py + 0.5f;
520 float nx = wx / dstW;
521 float ny = wy / dstH;
523 int triNdx = nx + ny >= 1.0f ? 1 : 0;
524 float triWx = triNdx ? dstW - wx : wx;
525 float triWy = triNdx ? dstH - wy : wy;
526 float triNx = triNdx ? 1.0f - nx : nx;
527 float triNy = triNdx ? 1.0f - ny : ny;
529 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
530 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
533 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
538 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture2DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
540 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
541 float dstW = (float)dst.getWidth();
542 float dstH = (float)dst.getHeight();
544 tcu::Vec4 uq = sq * (float)src.getWidth();
545 tcu::Vec4 vq = tq * (float)src.getHeight();
547 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
548 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
549 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
550 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
551 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
553 for (int py = 0; py < dst.getHeight(); py++)
555 for (int px = 0; px < dst.getWidth(); px++)
557 float wx = (float)px + 0.5f;
558 float wy = (float)py + 0.5f;
559 float nx = wx / dstW;
560 float ny = wy / dstH;
562 int triNdx = nx + ny >= 1.0f ? 1 : 0;
563 float triWx = triNdx ? dstW - wx : wx;
564 float triWy = triNdx ? dstH - wy : wy;
565 float triNx = triNdx ? 1.0f - nx : nx;
566 float triNy = triNdx ? 1.0f - ny : ny;
568 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
569 float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
570 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
573 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
578 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
580 const tcu::Texture2DView view = getSubView(src, params.baseLevel, params.maxLevel);
581 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
582 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
584 if (params.flags & ReferenceParams::PROJECTED)
585 sampleTextureProjected(dst, view, sq, tq, params);
587 sampleTextureNonProjected(dst, view, sq, tq, params);
590 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params)
592 const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel);
593 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
595 if (params.flags & ReferenceParams::PROJECTED)
596 sampleTextureProjected(dst, view, sq, params);
598 sampleTextureNonProjected(dst, view, sq, params);
601 static float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize)
603 const tcu::CubeFace face = tcu::selectCubeFace(coord);
608 // \note Derivate signs don't matter when computing lod
611 case tcu::CUBEFACE_NEGATIVE_X:
612 case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
613 case tcu::CUBEFACE_NEGATIVE_Y:
614 case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
615 case tcu::CUBEFACE_NEGATIVE_Z:
616 case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
622 const float sc = coord[sNdx];
623 const float tc = coord[tNdx];
624 const float ma = de::abs(coord[maNdx]);
625 const float scdx = coordDx[sNdx];
626 const float tcdx = coordDx[tNdx];
627 const float madx = de::abs(coordDx[maNdx]);
628 const float scdy = coordDy[sNdx];
629 const float tcdy = coordDy[tNdx];
630 const float mady = de::abs(coordDy[maNdx]);
631 const float dudx = float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma);
632 const float dvdx = float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma);
633 const float dudy = float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma);
634 const float dvdy = float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma);
636 return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
640 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)
642 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
643 const float dstW = float(dstSize.x());
644 const float dstH = float(dstSize.y());
645 const int srcSize = src.getSize();
647 // Coordinates per triangle.
648 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
649 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
650 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
651 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
653 const float lodBias ((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
655 for (int py = 0; py < dst.getHeight(); py++)
657 for (int px = 0; px < dst.getWidth(); px++)
659 const float wx = (float)px + 0.5f;
660 const float wy = (float)py + 0.5f;
661 const float nx = wx / dstW;
662 const float ny = wy / dstH;
664 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
665 const float triNx = triNdx ? 1.0f - nx : nx;
666 const float triNy = triNdx ? 1.0f - ny : ny;
668 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
669 triangleInterpolate(triT[triNdx], triNx, triNy),
670 triangleInterpolate(triR[triNdx], triNx, triNy));
671 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
672 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
673 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
674 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
675 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
676 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
678 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod);
680 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py);
685 void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
687 const tcu::TextureCubeView view = getSubView(src, params.baseLevel, params.maxLevel);
688 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
689 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
690 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
692 return sampleTexture(dst, view, sq, tq, rq, params);
695 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)
697 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
699 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
700 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
702 // Coordinates and lod per triangle.
703 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
704 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
705 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
706 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias,
707 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias};
709 for (int y = 0; y < dst.getHeight(); y++)
711 for (int x = 0; x < dst.getWidth(); x++)
713 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
714 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
716 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
717 float triX = triNdx ? 1.0f-xf : xf;
718 float triY = triNdx ? 1.0f-yf : yf;
720 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
721 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
722 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
723 float lod = triLod[triNdx];
725 dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
730 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params)
732 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
733 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
734 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
736 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
737 sampleTextureNonProjected(dst, src, sq, tq, rq, params);
740 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
742 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
744 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
745 deInt32 srcSize = src.getWidth();
747 // Coordinates and lod per triangle.
748 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
749 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
750 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
751 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
753 for (int y = 0; y < dst.getHeight(); y++)
755 for (int x = 0; x < dst.getWidth(); x++)
757 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
758 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
760 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
761 float triX = triNdx ? 1.0f-xf : xf;
762 float triY = triNdx ? 1.0f-yf : yf;
764 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
765 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
766 float lod = triLod[triNdx];
768 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
773 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params)
775 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
776 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
778 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
779 sampleTextureNonProjected(dst, src, sq, tq, params);
782 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)
784 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
786 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
787 tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
789 // Coordinates and lod per triangle.
790 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
791 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
792 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
793 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod),
794 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) };
796 for (int y = 0; y < dst.getHeight(); y++)
798 for (int x = 0; x < dst.getWidth(); x++)
800 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
801 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
803 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
804 float triX = triNdx ? 1.0f-xf : xf;
805 float triY = triNdx ? 1.0f-yf : yf;
807 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
808 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
809 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
810 float lod = triLod[triNdx];
812 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
817 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)
819 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
820 float dstW = (float)dst.getWidth();
821 float dstH = (float)dst.getHeight();
823 tcu::Vec4 uq = sq * (float)src.getWidth();
824 tcu::Vec4 vq = tq * (float)src.getHeight();
825 tcu::Vec4 wq = rq * (float)src.getDepth();
827 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
828 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
829 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
830 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
831 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
832 tcu::Vec3 triW[2] = { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) };
833 tcu::Vec3 triP[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
835 for (int py = 0; py < dst.getHeight(); py++)
837 for (int px = 0; px < dst.getWidth(); px++)
839 float wx = (float)px + 0.5f;
840 float wy = (float)py + 0.5f;
841 float nx = wx / dstW;
842 float ny = wy / dstH;
844 int triNdx = nx + ny >= 1.0f ? 1 : 0;
845 float triWx = triNdx ? dstW - wx : wx;
846 float triWy = triNdx ? dstH - wy : wy;
847 float triNx = triNdx ? 1.0f - nx : nx;
848 float triNy = triNdx ? 1.0f - ny : ny;
850 float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
851 float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
852 float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
853 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
856 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
861 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params)
863 const tcu::Texture3DView view = getSubView(src, params.baseLevel, params.maxLevel);
864 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
865 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
866 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
868 if (params.flags & ReferenceParams::PROJECTED)
869 sampleTextureProjected(dst, view, sq, tq, rq, params);
871 sampleTextureNonProjected(dst, view, sq, tq, rq, params);
874 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)
876 const float dstW = (float)dst.getWidth();
877 const float dstH = (float)dst.getHeight();
879 // Coordinates per triangle.
880 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
881 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
882 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
883 tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
884 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
886 const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
888 for (int py = 0; py < dst.getHeight(); py++)
890 for (int px = 0; px < dst.getWidth(); px++)
892 const float wx = (float)px + 0.5f;
893 const float wy = (float)py + 0.5f;
894 const float nx = wx / dstW;
895 const float ny = wy / dstH;
897 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
898 const float triNx = triNdx ? 1.0f - nx : nx;
899 const float triNy = triNdx ? 1.0f - ny : ny;
901 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
902 triangleInterpolate(triT[triNdx], triNx, triNy),
903 triangleInterpolate(triR[triNdx], triNx, triNy));
905 const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy);
907 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
908 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
909 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
910 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
911 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
912 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
914 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
916 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
921 void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params)
923 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
924 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
925 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
926 tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
928 sampleTexture(dst, src, sq, tq, rq, qq, params);
931 void fetchTexture (const SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias)
933 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
934 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
936 for (int y = 0; y < dst.getHeight(); y++)
938 for (int x = 0; x < dst.getWidth(); x++)
940 const float yf = ((float)y + 0.5f) / (float)dst.getHeight();
941 const float xf = ((float)x + 0.5f) / (float)dst.getWidth();
943 const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
944 const float triX = triNdx ? 1.0f-xf : xf;
945 const float triY = triNdx ? 1.0f-yf : yf;
947 const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
949 dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
954 void clear (const SurfaceAccess& dst, const tcu::Vec4& color)
956 for (int y = 0; y < dst.getHeight(); y++)
957 for (int x = 0; x < dst.getWidth(); x++)
958 dst.setPixel(color, x, y);
961 bool compareImages (TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
963 return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
966 bool compareImages (TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
968 return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
971 int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
973 return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
976 inline int rangeDiff (int x, int a, int b)
986 inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
988 int rMin = de::min(a.getRed(), b.getRed());
989 int rMax = de::max(a.getRed(), b.getRed());
990 int gMin = de::min(a.getGreen(), b.getGreen());
991 int gMax = de::max(a.getGreen(), b.getGreen());
992 int bMin = de::min(a.getBlue(), b.getBlue());
993 int bMax = de::max(a.getBlue(), b.getBlue());
994 int aMin = de::min(a.getAlpha(), b.getAlpha());
995 int aMax = de::max(a.getAlpha(), b.getAlpha());
997 return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax),
998 rangeDiff(p.getGreen(), gMin, gMax),
999 rangeDiff(p.getBlue(), bMin, bMax),
1000 rangeDiff(p.getAlpha(), aMin, aMax));
1003 inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
1005 tcu::RGBA diff = rangeDiff(p, a, b);
1006 return diff.getRed() <= threshold.getRed() &&
1007 diff.getGreen() <= threshold.getGreen() &&
1008 diff.getBlue() <= threshold.getBlue() &&
1009 diff.getAlpha() <= threshold.getAlpha();
1012 RandomViewport::RandomViewport (const tcu::RenderTarget& renderTarget, int preferredWidth, int preferredHeight, deUint32 seed)
1015 , width (deMin32(preferredWidth, renderTarget.getWidth()))
1016 , height (deMin32(preferredHeight, renderTarget.getHeight()))
1018 de::Random rnd(seed);
1019 x = rnd.getInt(0, renderTarget.getWidth() - width);
1020 y = rnd.getInt(0, renderTarget.getHeight() - height);
1023 ProgramLibrary::ProgramLibrary (const glu::RenderContext& context, tcu::TestLog& log, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1024 : m_context (context)
1026 , m_glslVersion (glslVersion)
1027 , m_texCoordPrecision (texCoordPrecision)
1031 ProgramLibrary::~ProgramLibrary (void)
1036 void ProgramLibrary::clear (void)
1038 for (map<Program, glu::ShaderProgram*>::iterator i = m_programs.begin(); i != m_programs.end(); i++)
1041 i->second = DE_NULL;
1046 glu::ShaderProgram* ProgramLibrary::getProgram (Program program)
1048 if (m_programs.find(program) != m_programs.end())
1049 return m_programs[program]; // Return from cache.
1051 static const char* vertShaderTemplate =
1053 "${VTX_IN} highp vec4 a_position;\n"
1054 "${VTX_IN} ${PRECISION} ${TEXCOORD_TYPE} a_texCoord;\n"
1055 "${VTX_OUT} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1057 "void main (void)\n"
1059 " gl_Position = a_position;\n"
1060 " v_texCoord = a_texCoord;\n"
1062 static const char* fragShaderTemplate =
1064 "${FRAG_IN} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1065 "uniform ${PRECISION} float u_bias;\n"
1066 "uniform ${PRECISION} float u_ref;\n"
1067 "uniform ${PRECISION} vec4 u_colorScale;\n"
1068 "uniform ${PRECISION} vec4 u_colorBias;\n"
1069 "uniform ${PRECISION} ${SAMPLER_TYPE} u_sampler;\n"
1071 "void main (void)\n"
1073 " ${FRAG_COLOR} = ${LOOKUP} * u_colorScale + u_colorBias;\n"
1076 map<string, string> params;
1078 bool isCube = de::inRange<int>(program, PROGRAM_CUBE_FLOAT, PROGRAM_CUBE_SHADOW_BIAS);
1079 bool isArray = de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW)
1080 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW);
1082 bool is1D = de::inRange<int>(program, PROGRAM_1D_FLOAT, PROGRAM_1D_UINT_BIAS)
1083 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW)
1084 || de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1086 bool is2D = de::inRange<int>(program, PROGRAM_2D_FLOAT, PROGRAM_2D_UINT_BIAS)
1087 || de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW);
1089 bool is3D = de::inRange<int>(program, PROGRAM_3D_FLOAT, PROGRAM_3D_UINT_BIAS);
1090 bool isCubeArray = de::inRange<int>(program, PROGRAM_CUBE_ARRAY_FLOAT, PROGRAM_CUBE_ARRAY_SHADOW);
1091 bool isBuffer = de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1093 if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1095 params["FRAG_HEADER"] = "";
1096 params["VTX_HEADER"] = "";
1097 params["VTX_IN"] = "attribute";
1098 params["VTX_OUT"] = "varying";
1099 params["FRAG_IN"] = "varying";
1100 params["FRAG_COLOR"] = "gl_FragColor";
1102 else if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1104 const string version = glu::getGLSLVersionDeclaration(m_glslVersion);
1105 const char* ext = DE_NULL;
1107 if (isCubeArray && glu::glslVersionIsES(m_glslVersion))
1108 ext = "GL_EXT_texture_cube_map_array";
1109 else if (isBuffer && glu::glslVersionIsES(m_glslVersion))
1110 ext = "GL_EXT_texture_buffer";
1112 params["FRAG_HEADER"] = version + (ext ? string("\n#extension ") + ext + " : require" : string()) + "\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1113 params["VTX_HEADER"] = version + "\n";
1114 params["VTX_IN"] = "in";
1115 params["VTX_OUT"] = "out";
1116 params["FRAG_IN"] = "in";
1117 params["FRAG_COLOR"] = "dEQP_FragColor";
1120 DE_ASSERT(!"Unsupported version");
1122 params["PRECISION"] = glu::getPrecisionName(m_texCoordPrecision);
1125 params["TEXCOORD_TYPE"] = "vec4";
1126 else if (isCube || (is2D && isArray) || is3D)
1127 params["TEXCOORD_TYPE"] = "vec3";
1128 else if ((is1D && isArray) || is2D)
1129 params["TEXCOORD_TYPE"] = "vec2";
1131 params["TEXCOORD_TYPE"] = "float";
1133 DE_ASSERT(DE_FALSE);
1135 const char* sampler = DE_NULL;
1136 const char* lookup = DE_NULL;
1138 if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1142 case PROGRAM_2D_FLOAT: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1143 case PROGRAM_2D_INT: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1144 case PROGRAM_2D_UINT: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1145 case PROGRAM_2D_SHADOW: sampler = "sampler2DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1146 case PROGRAM_2D_FLOAT_BIAS: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1147 case PROGRAM_2D_INT_BIAS: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1148 case PROGRAM_2D_UINT_BIAS: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1149 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;
1150 case PROGRAM_1D_FLOAT: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1151 case PROGRAM_1D_INT: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1152 case PROGRAM_1D_UINT: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1153 case PROGRAM_1D_SHADOW: sampler = "sampler1DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1154 case PROGRAM_1D_FLOAT_BIAS: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1155 case PROGRAM_1D_INT_BIAS: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1156 case PROGRAM_1D_UINT_BIAS: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1157 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;
1158 case PROGRAM_CUBE_FLOAT: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord)"; break;
1159 case PROGRAM_CUBE_INT: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1160 case PROGRAM_CUBE_UINT: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1161 case PROGRAM_CUBE_SHADOW: sampler = "samplerCubeShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1162 case PROGRAM_CUBE_FLOAT_BIAS: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1163 case PROGRAM_CUBE_INT_BIAS: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1164 case PROGRAM_CUBE_UINT_BIAS: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1165 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;
1166 case PROGRAM_2D_ARRAY_FLOAT: sampler = "sampler2DArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1167 case PROGRAM_2D_ARRAY_INT: sampler = "isampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1168 case PROGRAM_2D_ARRAY_UINT: sampler = "usampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1169 case PROGRAM_2D_ARRAY_SHADOW: sampler = "sampler2DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1170 case PROGRAM_3D_FLOAT: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1171 case PROGRAM_3D_INT: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1172 case PROGRAM_3D_UINT: sampler =" usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1173 case PROGRAM_3D_FLOAT_BIAS: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1174 case PROGRAM_3D_INT_BIAS: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1175 case PROGRAM_3D_UINT_BIAS: sampler =" usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1176 case PROGRAM_CUBE_ARRAY_FLOAT: sampler = "samplerCubeArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1177 case PROGRAM_CUBE_ARRAY_INT: sampler = "isamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1178 case PROGRAM_CUBE_ARRAY_UINT: sampler = "usamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1179 case PROGRAM_CUBE_ARRAY_SHADOW: sampler = "samplerCubeArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1180 case PROGRAM_1D_ARRAY_FLOAT: sampler = "sampler1DArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1181 case PROGRAM_1D_ARRAY_INT: sampler = "isampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1182 case PROGRAM_1D_ARRAY_UINT: sampler = "usampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1183 case PROGRAM_1D_ARRAY_SHADOW: sampler = "sampler1DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1184 case PROGRAM_BUFFER_FLOAT: sampler = "samplerBuffer"; lookup = "texelFetch(u_sampler, int(v_texCoord))"; break;
1185 case PROGRAM_BUFFER_INT: sampler = "isamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break;
1186 case PROGRAM_BUFFER_UINT: sampler = "usamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break;
1191 else if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1193 sampler = isCube ? "samplerCube" : "sampler2D";
1197 case PROGRAM_2D_FLOAT: lookup = "texture2D(u_sampler, v_texCoord)"; break;
1198 case PROGRAM_2D_FLOAT_BIAS: lookup = "texture2D(u_sampler, v_texCoord, u_bias)"; break;
1199 case PROGRAM_CUBE_FLOAT: lookup = "textureCube(u_sampler, v_texCoord)"; break;
1200 case PROGRAM_CUBE_FLOAT_BIAS: lookup = "textureCube(u_sampler, v_texCoord, u_bias)"; break;
1206 DE_ASSERT(!"Unsupported version");
1208 params["SAMPLER_TYPE"] = sampler;
1209 params["LOOKUP"] = lookup;
1211 std::string vertSrc = tcu::StringTemplate(vertShaderTemplate).specialize(params);
1212 std::string fragSrc = tcu::StringTemplate(fragShaderTemplate).specialize(params);
1214 glu::ShaderProgram* progObj = new glu::ShaderProgram(m_context, glu::makeVtxFragSources(vertSrc, fragSrc));
1215 if (!progObj->isOk())
1219 TCU_FAIL("Failed to compile shader program");
1224 m_programs[program] = progObj;
1235 TextureRenderer::TextureRenderer (const glu::RenderContext& context, tcu::TestLog& log, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1236 : m_renderCtx (context)
1238 , m_programLibrary (context, log, glslVersion, texCoordPrecision)
1242 TextureRenderer::~TextureRenderer (void)
1247 void TextureRenderer::clear (void)
1249 m_programLibrary.clear();
1252 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, TextureType texType)
1254 renderQuad(texUnit, texCoord, RenderParams(texType));
1257 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, const RenderParams& params)
1259 const glw::Functions& gl = m_renderCtx.getFunctions();
1260 tcu::Vec4 wCoord = params.flags & RenderParams::PROJECTED ? params.w : tcu::Vec4(1.0f);
1261 bool useBias = !!(params.flags & RenderParams::USE_BIAS);
1262 bool logUniforms = !!(params.flags & RenderParams::LOG_UNIFORMS);
1264 // Render quad with texture.
1267 -1.0f*wCoord.x(), -1.0f*wCoord.x(), 0.0f, wCoord.x(),
1268 -1.0f*wCoord.y(), +1.0f*wCoord.y(), 0.0f, wCoord.y(),
1269 +1.0f*wCoord.z(), -1.0f*wCoord.z(), 0.0f, wCoord.z(),
1270 +1.0f*wCoord.w(), +1.0f*wCoord.w(), 0.0f, wCoord.w()
1272 static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
1274 Program progSpec = PROGRAM_LAST;
1276 if (params.texType == TEXTURETYPE_2D)
1280 switch (params.samplerType)
1282 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_2D_FLOAT_BIAS : PROGRAM_2D_FLOAT; break;
1283 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_2D_INT_BIAS : PROGRAM_2D_INT; break;
1284 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_2D_UINT_BIAS : PROGRAM_2D_UINT; break;
1285 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_2D_SHADOW_BIAS : PROGRAM_2D_SHADOW; break;
1286 default: DE_ASSERT(false);
1289 else if (params.texType == TEXTURETYPE_1D)
1293 switch (params.samplerType)
1295 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_1D_FLOAT_BIAS : PROGRAM_1D_FLOAT; break;
1296 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_1D_INT_BIAS : PROGRAM_1D_INT; break;
1297 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_1D_UINT_BIAS : PROGRAM_1D_UINT; break;
1298 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_1D_SHADOW_BIAS : PROGRAM_1D_SHADOW; break;
1299 default: DE_ASSERT(false);
1302 else if (params.texType == TEXTURETYPE_CUBE)
1306 switch (params.samplerType)
1308 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_CUBE_FLOAT_BIAS : PROGRAM_CUBE_FLOAT; break;
1309 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_CUBE_INT_BIAS : PROGRAM_CUBE_INT; break;
1310 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_CUBE_UINT_BIAS : PROGRAM_CUBE_UINT; break;
1311 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_CUBE_SHADOW_BIAS : PROGRAM_CUBE_SHADOW; break;
1312 default: DE_ASSERT(false);
1315 else if (params.texType == TEXTURETYPE_3D)
1319 switch (params.samplerType)
1321 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_3D_FLOAT_BIAS : PROGRAM_3D_FLOAT; break;
1322 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_3D_INT_BIAS : PROGRAM_3D_INT; break;
1323 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_3D_UINT_BIAS : PROGRAM_3D_UINT; break;
1324 default: DE_ASSERT(false);
1327 else if (params.texType == TEXTURETYPE_2D_ARRAY)
1329 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1333 switch (params.samplerType)
1335 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_2D_ARRAY_FLOAT; break;
1336 case SAMPLERTYPE_INT: progSpec = PROGRAM_2D_ARRAY_INT; break;
1337 case SAMPLERTYPE_UINT: progSpec = PROGRAM_2D_ARRAY_UINT; break;
1338 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_2D_ARRAY_SHADOW; break;
1339 default: DE_ASSERT(false);
1342 else if (params.texType == TEXTURETYPE_CUBE_ARRAY)
1344 DE_ASSERT(!useBias);
1348 switch (params.samplerType)
1350 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_CUBE_ARRAY_FLOAT; break;
1351 case SAMPLERTYPE_INT: progSpec = PROGRAM_CUBE_ARRAY_INT; break;
1352 case SAMPLERTYPE_UINT: progSpec = PROGRAM_CUBE_ARRAY_UINT; break;
1353 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_CUBE_ARRAY_SHADOW; break;
1354 default: DE_ASSERT(false);
1357 else if (params.texType == TEXTURETYPE_1D_ARRAY)
1359 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1363 switch (params.samplerType)
1365 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_1D_ARRAY_FLOAT; break;
1366 case SAMPLERTYPE_INT: progSpec = PROGRAM_1D_ARRAY_INT; break;
1367 case SAMPLERTYPE_UINT: progSpec = PROGRAM_1D_ARRAY_UINT; break;
1368 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_1D_ARRAY_SHADOW; break;
1369 default: DE_ASSERT(false);
1372 else if (params.texType == TEXTURETYPE_BUFFER)
1376 switch (params.samplerType)
1378 case SAMPLERTYPE_FETCH_FLOAT: progSpec = PROGRAM_BUFFER_FLOAT; break;
1379 case SAMPLERTYPE_FETCH_INT: progSpec = PROGRAM_BUFFER_INT; break;
1380 case SAMPLERTYPE_FETCH_UINT: progSpec = PROGRAM_BUFFER_UINT; break;
1381 default: DE_ASSERT(false);
1385 DE_ASSERT(DE_FALSE);
1387 glu::ShaderProgram* program = m_programLibrary.getProgram(progSpec);
1389 // \todo [2012-09-26 pyry] Move to ProgramLibrary and log unique programs only(?)
1390 if (params.flags & RenderParams::LOG_PROGRAMS)
1393 GLU_EXPECT_NO_ERROR(gl.getError(), "Set vertex attributes");
1395 // Program and uniforms.
1396 deUint32 prog = program->getProgram();
1397 gl.useProgram(prog);
1399 gl.uniform1i(gl.getUniformLocation(prog, "u_sampler"), texUnit);
1401 m_log << TestLog::Message << "u_sampler = " << texUnit << TestLog::EndMessage;
1405 gl.uniform1f(gl.getUniformLocation(prog, "u_bias"), params.bias);
1407 m_log << TestLog::Message << "u_bias = " << params.bias << TestLog::EndMessage;
1410 if (params.samplerType == SAMPLERTYPE_SHADOW)
1412 gl.uniform1f(gl.getUniformLocation(prog, "u_ref"), params.ref);
1414 m_log << TestLog::Message << "u_ref = " << params.ref << TestLog::EndMessage;
1417 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorScale"), 1, params.colorScale.getPtr());
1418 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorBias"), 1, params.colorBias.getPtr());
1422 m_log << TestLog::Message << "u_colorScale = " << params.colorScale << TestLog::EndMessage;
1423 m_log << TestLog::Message << "u_colorBias = " << params.colorBias << TestLog::EndMessage;
1426 GLU_EXPECT_NO_ERROR(gl.getError(), "Set program state");
1429 const glu::VertexArrayBinding vertexArrays[] =
1431 glu::va::Float("a_position", 4, 4, 0, &position[0]),
1432 glu::va::Float("a_texCoord", numComps, 4, 0, texCoord)
1434 glu::draw(m_renderCtx, prog, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
1435 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1439 void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
1449 void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
1453 dst[0] = left; dst[1] = (float)layerNdx;
1454 dst[2] = left; dst[3] = (float)layerNdx;
1455 dst[4] = right; dst[5] = (float)layerNdx;
1456 dst[6] = right; dst[7] = (float)layerNdx;
1459 void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1463 dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y();
1464 dst[2] = bottomLeft.x(); dst[3] = topRight.y();
1465 dst[4] = topRight.x(); dst[5] = bottomLeft.y();
1466 dst[6] = topRight.x(); dst[7] = topRight.y();
1469 void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1473 dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx;
1474 dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx;
1475 dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx;
1476 dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx;
1479 void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
1481 tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1482 tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1483 tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1484 tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1486 tcu::Vec3 v0 = p0 + (p1-p0)*f0;
1487 tcu::Vec3 v1 = p0 + (p1-p0)*f1;
1488 tcu::Vec3 v2 = p0 + (p1-p0)*f2;
1489 tcu::Vec3 v3 = p0 + (p1-p0)*f3;
1493 dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
1494 dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
1495 dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
1496 dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
1499 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
1501 static const float texCoordNegX[] =
1504 -1.0f, -1.0f, -1.0f,
1508 static const float texCoordPosX[] =
1515 static const float texCoordNegY[] =
1518 -1.0f, -1.0f, -1.0f,
1522 static const float texCoordPosY[] =
1524 -1.0f, +1.0f, -1.0f,
1529 static const float texCoordNegZ[] =
1536 static const float texCoordPosZ[] =
1539 -1.0f, -1.0f, +1.0f,
1544 const float* texCoord = DE_NULL;
1545 int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX);
1549 case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
1550 case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
1551 case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
1552 case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
1553 case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
1554 case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
1556 DE_ASSERT(DE_FALSE);
1560 dst.resize(texCoordSize);
1561 std::copy(texCoord, texCoord+texCoordSize, dst.begin());
1564 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1575 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1576 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1577 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1578 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1579 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1580 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1582 DE_ASSERT(DE_FALSE);
1588 dst[0+mRow] = mSign;
1589 dst[3+mRow] = mSign;
1590 dst[6+mRow] = mSign;
1591 dst[9+mRow] = mSign;
1593 dst[0+sRow] = sSign * bottomLeft.x();
1594 dst[3+sRow] = sSign * bottomLeft.x();
1595 dst[6+sRow] = sSign * topRight.x();
1596 dst[9+sRow] = sSign * topRight.x();
1598 dst[0+tRow] = tSign * bottomLeft.y();
1599 dst[3+tRow] = tSign * topRight.y();
1600 dst[6+tRow] = tSign * bottomLeft.y();
1601 dst[9+tRow] = tSign * topRight.y();
1604 void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
1613 const float l0 = layerRange.x();
1614 const float l1 = layerRange.y();
1618 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1619 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1620 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1621 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1622 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1623 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1625 DE_ASSERT(DE_FALSE);
1631 dst[ 0+mRow] = mSign;
1632 dst[ 4+mRow] = mSign;
1633 dst[ 8+mRow] = mSign;
1634 dst[12+mRow] = mSign;
1636 dst[ 0+sRow] = sSign * bottomLeft.x();
1637 dst[ 4+sRow] = sSign * bottomLeft.x();
1638 dst[ 8+sRow] = sSign * topRight.x();
1639 dst[12+sRow] = sSign * topRight.x();
1641 dst[ 0+tRow] = tSign * bottomLeft.y();
1642 dst[ 4+tRow] = tSign * topRight.y();
1643 dst[ 8+tRow] = tSign * bottomLeft.y();
1644 dst[12+tRow] = tSign * topRight.y();
1649 dst[ 4+qRow] = l0*0.5f + l1*0.5f;
1650 dst[ 8+qRow] = l0*0.5f + l1*0.5f;
1662 // Texture result verification
1664 //! Verifies texture lookup results and returns number of failed pixels.
1665 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1666 const tcu::ConstPixelBufferAccess& reference,
1667 const tcu::PixelBufferAccess& errorMask,
1668 const tcu::Texture1DView& baseView,
1669 const float* texCoord,
1670 const ReferenceParams& sampleParams,
1671 const tcu::LookupPrecision& lookupPrec,
1672 const tcu::LodPrecision& lodPrec,
1673 qpWatchDog* watchDog)
1675 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1676 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1678 const tcu::Texture1DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1680 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1682 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1683 const float dstW = float(dstSize.x());
1684 const float dstH = float(dstSize.y());
1685 const int srcSize = src.getWidth();
1687 // Coordinates and lod per triangle.
1688 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1689 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1691 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1695 const tcu::Vec2 lodOffsets[] =
1703 tcu::clear(errorMask, tcu::RGBA::green.toVec());
1705 for (int py = 0; py < result.getHeight(); py++)
1707 // Ugly hack, validation can take way too long at the moment.
1709 qpWatchDog_touch(watchDog);
1711 for (int px = 0; px < result.getWidth(); px++)
1713 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1714 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1716 // Try comparison to ideal reference first, and if that fails use slower verificator.
1717 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1719 const float wx = (float)px + 0.5f;
1720 const float wy = (float)py + 0.5f;
1721 const float nx = wx / dstW;
1722 const float ny = wy / dstH;
1724 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1725 const float triWx = triNdx ? dstW - wx : wx;
1726 const float triWy = triNdx ? dstH - wy : wy;
1727 const float triNx = triNdx ? 1.0f - nx : nx;
1728 const float triNy = triNdx ? 1.0f - ny : ny;
1730 const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1731 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1732 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1734 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1736 // Compute lod bounds across lodOffsets range.
1737 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1739 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1740 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1741 const float nxo = wxo/dstW;
1742 const float nyo = wyo/dstH;
1744 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1745 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1746 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1748 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1749 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1752 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1753 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1757 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
1767 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1768 const tcu::ConstPixelBufferAccess& reference,
1769 const tcu::PixelBufferAccess& errorMask,
1770 const tcu::Texture2DView& baseView,
1771 const float* texCoord,
1772 const ReferenceParams& sampleParams,
1773 const tcu::LookupPrecision& lookupPrec,
1774 const tcu::LodPrecision& lodPrec,
1775 qpWatchDog* watchDog)
1777 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1778 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1780 const tcu::Texture2DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1782 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1783 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1785 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1786 const float dstW = float(dstSize.x());
1787 const float dstH = float(dstSize.y());
1788 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
1790 // Coordinates and lod per triangle.
1791 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1792 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1793 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1795 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1799 const tcu::Vec2 lodOffsets[] =
1807 tcu::clear(errorMask, tcu::RGBA::green.toVec());
1809 for (int py = 0; py < result.getHeight(); py++)
1811 // Ugly hack, validation can take way too long at the moment.
1813 qpWatchDog_touch(watchDog);
1815 for (int px = 0; px < result.getWidth(); px++)
1817 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1818 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1820 // Try comparison to ideal reference first, and if that fails use slower verificator.
1821 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1823 const float wx = (float)px + 0.5f;
1824 const float wy = (float)py + 0.5f;
1825 const float nx = wx / dstW;
1826 const float ny = wy / dstH;
1828 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1829 const float triWx = triNdx ? dstW - wx : wx;
1830 const float triWy = triNdx ? dstH - wy : wy;
1831 const float triNx = triNdx ? 1.0f - nx : nx;
1832 const float triNy = triNdx ? 1.0f - ny : ny;
1834 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1835 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1836 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1837 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1838 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1839 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1841 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1843 // Compute lod bounds across lodOffsets range.
1844 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1846 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1847 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1848 const float nxo = wxo/dstW;
1849 const float nyo = wyo/dstH;
1851 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1852 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1853 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1854 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1855 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1857 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1858 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1861 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1862 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1866 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
1876 bool verifyTextureResult (tcu::TestContext& testCtx,
1877 const tcu::ConstPixelBufferAccess& result,
1878 const tcu::Texture1DView& src,
1879 const float* texCoord,
1880 const ReferenceParams& sampleParams,
1881 const tcu::LookupPrecision& lookupPrec,
1882 const tcu::LodPrecision& lodPrec,
1883 const tcu::PixelFormat& pixelFormat)
1885 tcu::TestLog& log = testCtx.getLog();
1886 tcu::Surface reference (result.getWidth(), result.getHeight());
1887 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1888 int numFailedPixels;
1890 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1892 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1893 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1895 if (numFailedPixels > 0)
1896 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1898 log << TestLog::ImageSet("VerifyResult", "Verification result")
1899 << TestLog::Image("Rendered", "Rendered image", result);
1901 if (numFailedPixels > 0)
1903 log << TestLog::Image("Reference", "Ideal reference image", reference)
1904 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1907 log << TestLog::EndImageSet;
1909 return numFailedPixels == 0;
1912 bool verifyTextureResult (tcu::TestContext& testCtx,
1913 const tcu::ConstPixelBufferAccess& result,
1914 const tcu::Texture2DView& src,
1915 const float* texCoord,
1916 const ReferenceParams& sampleParams,
1917 const tcu::LookupPrecision& lookupPrec,
1918 const tcu::LodPrecision& lodPrec,
1919 const tcu::PixelFormat& pixelFormat)
1921 tcu::TestLog& log = testCtx.getLog();
1922 tcu::Surface reference (result.getWidth(), result.getHeight());
1923 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1924 int numFailedPixels;
1926 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1928 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1929 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1931 if (numFailedPixels > 0)
1932 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1934 log << TestLog::ImageSet("VerifyResult", "Verification result")
1935 << TestLog::Image("Rendered", "Rendered image", result);
1937 if (numFailedPixels > 0)
1939 log << TestLog::Image("Reference", "Ideal reference image", reference)
1940 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1943 log << TestLog::EndImageSet;
1945 return numFailedPixels == 0;
1948 //! Verifies texture lookup results and returns number of failed pixels.
1949 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1950 const tcu::ConstPixelBufferAccess& reference,
1951 const tcu::PixelBufferAccess& errorMask,
1952 const tcu::TextureCubeView& baseView,
1953 const float* texCoord,
1954 const ReferenceParams& sampleParams,
1955 const tcu::LookupPrecision& lookupPrec,
1956 const tcu::LodPrecision& lodPrec,
1957 qpWatchDog* watchDog)
1959 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1960 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1962 const tcu::TextureCubeView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1964 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1965 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1966 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1968 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1969 const float dstW = float(dstSize.x());
1970 const float dstH = float(dstSize.y());
1971 const int srcSize = src.getSize();
1973 // Coordinates per triangle.
1974 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1975 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1976 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1977 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1979 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1981 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1985 const tcu::Vec2 lodOffsets[] =
1992 // \note Not strictly allowed by spec, but implementations do this in practice.
1999 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2001 for (int py = 0; py < result.getHeight(); py++)
2003 // Ugly hack, validation can take way too long at the moment.
2005 qpWatchDog_touch(watchDog);
2007 for (int px = 0; px < result.getWidth(); px++)
2009 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2010 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2012 // Try comparison to ideal reference first, and if that fails use slower verificator.
2013 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2015 const float wx = (float)px + 0.5f;
2016 const float wy = (float)py + 0.5f;
2017 const float nx = wx / dstW;
2018 const float ny = wy / dstH;
2020 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
2021 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
2025 DE_ASSERT(tri0 || tri1);
2027 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2028 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2030 const float triWx = triNdx ? dstW - wx : wx;
2031 const float triWy = triNdx ? dstH - wy : wy;
2032 const float triNx = triNdx ? 1.0f - nx : nx;
2033 const float triNy = triNdx ? 1.0f - ny : ny;
2035 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2036 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2037 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2038 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2039 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2040 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2041 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2042 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2043 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2045 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2047 // Compute lod bounds across lodOffsets range.
2048 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2050 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2051 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2052 const float nxo = wxo/dstW;
2053 const float nyo = wyo/dstH;
2055 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2056 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2057 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2058 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2059 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2060 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2061 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2062 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2063 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2064 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2066 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2067 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2070 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2072 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2081 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2091 bool verifyTextureResult (tcu::TestContext& testCtx,
2092 const tcu::ConstPixelBufferAccess& result,
2093 const tcu::TextureCubeView& src,
2094 const float* texCoord,
2095 const ReferenceParams& sampleParams,
2096 const tcu::LookupPrecision& lookupPrec,
2097 const tcu::LodPrecision& lodPrec,
2098 const tcu::PixelFormat& pixelFormat)
2100 tcu::TestLog& log = testCtx.getLog();
2101 tcu::Surface reference (result.getWidth(), result.getHeight());
2102 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2103 int numFailedPixels;
2105 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2107 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2108 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2110 if (numFailedPixels > 0)
2111 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2113 log << TestLog::ImageSet("VerifyResult", "Verification result")
2114 << TestLog::Image("Rendered", "Rendered image", result);
2116 if (numFailedPixels > 0)
2118 log << TestLog::Image("Reference", "Ideal reference image", reference)
2119 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2122 log << TestLog::EndImageSet;
2124 return numFailedPixels == 0;
2127 //! Verifies texture lookup results and returns number of failed pixels.
2128 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2129 const tcu::ConstPixelBufferAccess& reference,
2130 const tcu::PixelBufferAccess& errorMask,
2131 const tcu::Texture3DView& baseView,
2132 const float* texCoord,
2133 const ReferenceParams& sampleParams,
2134 const tcu::LookupPrecision& lookupPrec,
2135 const tcu::LodPrecision& lodPrec,
2136 qpWatchDog* watchDog)
2138 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2139 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2141 const tcu::Texture3DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
2143 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2144 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2145 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2147 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2148 const float dstW = float(dstSize.x());
2149 const float dstH = float(dstSize.y());
2150 const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
2152 // Coordinates and lod per triangle.
2153 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2154 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2155 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2156 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2158 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2160 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
2164 const tcu::Vec2 lodOffsets[] =
2172 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2174 for (int py = 0; py < result.getHeight(); py++)
2176 // Ugly hack, validation can take way too long at the moment.
2178 qpWatchDog_touch(watchDog);
2180 for (int px = 0; px < result.getWidth(); px++)
2182 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2183 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2185 // Try comparison to ideal reference first, and if that fails use slower verificator.
2186 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2188 const float wx = (float)px + 0.5f;
2189 const float wy = (float)py + 0.5f;
2190 const float nx = wx / dstW;
2191 const float ny = wy / dstH;
2193 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
2194 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
2198 DE_ASSERT(tri0 || tri1);
2200 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2201 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2203 const float triWx = triNdx ? dstW - wx : wx;
2204 const float triWy = triNdx ? dstH - wy : wy;
2205 const float triNx = triNdx ? 1.0f - nx : nx;
2206 const float triNy = triNdx ? 1.0f - ny : ny;
2208 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2209 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2210 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2211 const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2212 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2213 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2214 const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2215 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2216 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2218 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
2220 // Compute lod bounds across lodOffsets range.
2221 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2223 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2224 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2225 const float nxo = wxo/dstW;
2226 const float nyo = wyo/dstH;
2228 const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2229 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2230 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2231 const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2232 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2233 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2234 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
2236 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2237 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2240 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2242 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2251 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2261 bool verifyTextureResult (tcu::TestContext& testCtx,
2262 const tcu::ConstPixelBufferAccess& result,
2263 const tcu::Texture3DView& src,
2264 const float* texCoord,
2265 const ReferenceParams& sampleParams,
2266 const tcu::LookupPrecision& lookupPrec,
2267 const tcu::LodPrecision& lodPrec,
2268 const tcu::PixelFormat& pixelFormat)
2270 tcu::TestLog& log = testCtx.getLog();
2271 tcu::Surface reference (result.getWidth(), result.getHeight());
2272 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2273 int numFailedPixels;
2275 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2277 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2278 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2280 if (numFailedPixels > 0)
2281 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2283 log << TestLog::ImageSet("VerifyResult", "Verification result")
2284 << TestLog::Image("Rendered", "Rendered image", result);
2286 if (numFailedPixels > 0)
2288 log << TestLog::Image("Reference", "Ideal reference image", reference)
2289 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2292 log << TestLog::EndImageSet;
2294 return numFailedPixels == 0;
2297 //! Verifies texture lookup results and returns number of failed pixels.
2298 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2299 const tcu::ConstPixelBufferAccess& reference,
2300 const tcu::PixelBufferAccess& errorMask,
2301 const tcu::Texture1DArrayView& src,
2302 const float* texCoord,
2303 const ReferenceParams& sampleParams,
2304 const tcu::LookupPrecision& lookupPrec,
2305 const tcu::LodPrecision& lodPrec,
2306 qpWatchDog* watchDog)
2308 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2309 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2311 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2312 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2314 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2315 const float dstW = float(dstSize.x());
2316 const float dstH = float(dstSize.y());
2317 const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored.
2319 // Coordinates and lod per triangle.
2320 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2321 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2322 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2324 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2328 const tcu::Vec2 lodOffsets[] =
2336 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2338 for (int py = 0; py < result.getHeight(); py++)
2340 // Ugly hack, validation can take way too long at the moment.
2342 qpWatchDog_touch(watchDog);
2344 for (int px = 0; px < result.getWidth(); px++)
2346 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2347 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2349 // Try comparison to ideal reference first, and if that fails use slower verificator.
2350 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2352 const float wx = (float)px + 0.5f;
2353 const float wy = (float)py + 0.5f;
2354 const float nx = wx / dstW;
2355 const float ny = wy / dstH;
2357 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2358 const float triWx = triNdx ? dstW - wx : wx;
2359 const float triWy = triNdx ? dstH - wy : wy;
2360 const float triNx = triNdx ? 1.0f - nx : nx;
2361 const float triNy = triNdx ? 1.0f - ny : ny;
2363 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2364 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2365 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
2366 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
2368 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
2370 // Compute lod bounds across lodOffsets range.
2371 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2373 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2374 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2375 const float nxo = wxo/dstW;
2376 const float nyo = wyo/dstH;
2378 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
2379 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
2380 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
2382 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2383 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2386 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2387 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2391 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2401 //! Verifies texture lookup results and returns number of failed pixels.
2402 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2403 const tcu::ConstPixelBufferAccess& reference,
2404 const tcu::PixelBufferAccess& errorMask,
2405 const tcu::Texture2DArrayView& src,
2406 const float* texCoord,
2407 const ReferenceParams& sampleParams,
2408 const tcu::LookupPrecision& lookupPrec,
2409 const tcu::LodPrecision& lodPrec,
2410 qpWatchDog* watchDog)
2412 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2413 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2415 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2416 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2417 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2419 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2420 const float dstW = float(dstSize.x());
2421 const float dstH = float(dstSize.y());
2422 const tcu::Vec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2424 // Coordinates and lod per triangle.
2425 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2426 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2427 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2428 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2430 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2434 const tcu::Vec2 lodOffsets[] =
2442 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2444 for (int py = 0; py < result.getHeight(); py++)
2446 // Ugly hack, validation can take way too long at the moment.
2448 qpWatchDog_touch(watchDog);
2450 for (int px = 0; px < result.getWidth(); px++)
2452 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2453 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2455 // Try comparison to ideal reference first, and if that fails use slower verificator.
2456 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2458 const float wx = (float)px + 0.5f;
2459 const float wy = (float)py + 0.5f;
2460 const float nx = wx / dstW;
2461 const float ny = wy / dstH;
2463 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2464 const float triWx = triNdx ? dstW - wx : wx;
2465 const float triWy = triNdx ? dstH - wy : wy;
2466 const float triNx = triNdx ? 1.0f - nx : nx;
2467 const float triNy = triNdx ? 1.0f - ny : ny;
2469 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2470 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2471 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2472 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2473 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2474 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2475 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2477 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2479 // Compute lod bounds across lodOffsets range.
2480 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2482 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2483 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2484 const float nxo = wxo/dstW;
2485 const float nyo = wyo/dstH;
2487 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2488 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2489 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2490 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2491 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2493 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2494 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2497 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2498 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2502 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2512 bool verifyTextureResult (tcu::TestContext& testCtx,
2513 const tcu::ConstPixelBufferAccess& result,
2514 const tcu::Texture1DArrayView& src,
2515 const float* texCoord,
2516 const ReferenceParams& sampleParams,
2517 const tcu::LookupPrecision& lookupPrec,
2518 const tcu::LodPrecision& lodPrec,
2519 const tcu::PixelFormat& pixelFormat)
2521 tcu::TestLog& log = testCtx.getLog();
2522 tcu::Surface reference (result.getWidth(), result.getHeight());
2523 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2524 int numFailedPixels;
2526 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2528 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2529 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2531 if (numFailedPixels > 0)
2532 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2534 log << TestLog::ImageSet("VerifyResult", "Verification result")
2535 << TestLog::Image("Rendered", "Rendered image", result);
2537 if (numFailedPixels > 0)
2539 log << TestLog::Image("Reference", "Ideal reference image", reference)
2540 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2543 log << TestLog::EndImageSet;
2545 return numFailedPixels == 0;
2548 bool verifyTextureResult (tcu::TestContext& testCtx,
2549 const tcu::ConstPixelBufferAccess& result,
2550 const tcu::Texture2DArrayView& src,
2551 const float* texCoord,
2552 const ReferenceParams& sampleParams,
2553 const tcu::LookupPrecision& lookupPrec,
2554 const tcu::LodPrecision& lodPrec,
2555 const tcu::PixelFormat& pixelFormat)
2557 tcu::TestLog& log = testCtx.getLog();
2558 tcu::Surface reference (result.getWidth(), result.getHeight());
2559 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2560 int numFailedPixels;
2562 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2564 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2565 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2567 if (numFailedPixels > 0)
2568 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2570 log << TestLog::ImageSet("VerifyResult", "Verification result")
2571 << TestLog::Image("Rendered", "Rendered image", result);
2573 if (numFailedPixels > 0)
2575 log << TestLog::Image("Reference", "Ideal reference image", reference)
2576 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2579 log << TestLog::EndImageSet;
2581 return numFailedPixels == 0;
2584 //! Verifies texture lookup results and returns number of failed pixels.
2585 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2586 const tcu::ConstPixelBufferAccess& reference,
2587 const tcu::PixelBufferAccess& errorMask,
2588 const tcu::TextureCubeArrayView& baseView,
2589 const float* texCoord,
2590 const ReferenceParams& sampleParams,
2591 const tcu::LookupPrecision& lookupPrec,
2592 const tcu::IVec4& coordBits,
2593 const tcu::LodPrecision& lodPrec,
2594 qpWatchDog* watchDog)
2596 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2597 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2599 const tcu::TextureCubeArrayView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
2601 // 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
2602 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2603 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2604 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2605 const tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2607 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2608 const float dstW = float(dstSize.x());
2609 const float dstH = float(dstSize.y());
2610 const int srcSize = src.getSize();
2612 // Coordinates per triangle.
2613 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2614 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2615 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2616 const tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2617 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2619 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2621 const float posEps = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2625 const tcu::Vec2 lodOffsets[] =
2632 // \note Not strictly allowed by spec, but implementations do this in practice.
2639 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2641 for (int py = 0; py < result.getHeight(); py++)
2643 // Ugly hack, validation can take way too long at the moment.
2645 qpWatchDog_touch(watchDog);
2647 for (int px = 0; px < result.getWidth(); px++)
2649 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2650 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2652 // Try comparison to ideal reference first, and if that fails use slower verificator.
2653 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2655 const float wx = (float)px + 0.5f;
2656 const float wy = (float)py + 0.5f;
2657 const float nx = wx / dstW;
2658 const float ny = wy / dstH;
2660 const bool tri0 = nx + ny - posEps <= 1.0f;
2661 const bool tri1 = nx + ny + posEps >= 1.0f;
2665 DE_ASSERT(tri0 || tri1);
2667 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2668 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2670 const float triWx = triNdx ? dstW - wx : wx;
2671 const float triWy = triNdx ? dstH - wy : wy;
2672 const float triNx = triNdx ? 1.0f - nx : nx;
2673 const float triNy = triNdx ? 1.0f - ny : ny;
2675 const tcu::Vec4 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2676 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2677 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2678 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2679 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2680 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2681 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2682 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2683 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2684 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2686 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2688 // Compute lod bounds across lodOffsets range.
2689 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2691 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2692 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2693 const float nxo = wxo/dstW;
2694 const float nyo = wyo/dstH;
2696 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2697 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2698 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2699 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2700 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2701 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2702 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2703 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2704 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2705 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2707 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2708 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2711 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2713 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2722 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2732 bool verifyTextureResult (tcu::TestContext& testCtx,
2733 const tcu::ConstPixelBufferAccess& result,
2734 const tcu::TextureCubeArrayView& src,
2735 const float* texCoord,
2736 const ReferenceParams& sampleParams,
2737 const tcu::LookupPrecision& lookupPrec,
2738 const tcu::IVec4& coordBits,
2739 const tcu::LodPrecision& lodPrec,
2740 const tcu::PixelFormat& pixelFormat)
2742 tcu::TestLog& log = testCtx.getLog();
2743 tcu::Surface reference (result.getWidth(), result.getHeight());
2744 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2745 int numFailedPixels;
2747 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2749 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2750 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2752 if (numFailedPixels > 0)
2753 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2755 log << TestLog::ImageSet("VerifyResult", "Verification result")
2756 << TestLog::Image("Rendered", "Rendered image", result);
2758 if (numFailedPixels > 0)
2760 log << TestLog::Image("Reference", "Ideal reference image", reference)
2761 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2764 log << TestLog::EndImageSet;
2766 return numFailedPixels == 0;
2769 // Shadow lookup verification
2771 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2772 const tcu::ConstPixelBufferAccess& reference,
2773 const tcu::PixelBufferAccess& errorMask,
2774 const tcu::Texture2DView& src,
2775 const float* texCoord,
2776 const ReferenceParams& sampleParams,
2777 const tcu::TexComparePrecision& comparePrec,
2778 const tcu::LodPrecision& lodPrec,
2779 const tcu::Vec3& nonShadowThreshold)
2781 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2782 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2784 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2785 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2787 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2788 const float dstW = float(dstSize.x());
2789 const float dstH = float(dstSize.y());
2790 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2792 // Coordinates and lod per triangle.
2793 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2794 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2795 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2797 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2801 const tcu::Vec2 lodOffsets[] =
2809 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2811 for (int py = 0; py < result.getHeight(); py++)
2813 for (int px = 0; px < result.getWidth(); px++)
2815 const tcu::Vec4 resPix = result.getPixel(px, py);
2816 const tcu::Vec4 refPix = reference.getPixel(px, py);
2818 // Other channels should trivially match to reference.
2819 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2821 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2827 const float wx = (float)px + 0.5f;
2828 const float wy = (float)py + 0.5f;
2829 const float nx = wx / dstW;
2830 const float ny = wy / dstH;
2832 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2833 const float triWx = triNdx ? dstW - wx : wx;
2834 const float triWy = triNdx ? dstH - wy : wy;
2835 const float triNx = triNdx ? 1.0f - nx : nx;
2836 const float triNy = triNdx ? 1.0f - ny : ny;
2838 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2839 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2840 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2841 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2842 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2843 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2845 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2847 // Compute lod bounds across lodOffsets range.
2848 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2850 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2851 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2852 const float nxo = wxo/dstW;
2853 const float nyo = wyo/dstH;
2855 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2856 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2857 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2858 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2859 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2861 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2862 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2865 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2866 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2870 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2880 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2881 const tcu::ConstPixelBufferAccess& reference,
2882 const tcu::PixelBufferAccess& errorMask,
2883 const tcu::TextureCubeView& src,
2884 const float* texCoord,
2885 const ReferenceParams& sampleParams,
2886 const tcu::TexComparePrecision& comparePrec,
2887 const tcu::LodPrecision& lodPrec,
2888 const tcu::Vec3& nonShadowThreshold)
2890 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2891 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2893 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2894 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2895 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2897 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2898 const float dstW = float(dstSize.x());
2899 const float dstH = float(dstSize.y());
2900 const int srcSize = src.getSize();
2902 // Coordinates per triangle.
2903 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2904 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2905 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2906 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2908 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2912 const tcu::Vec2 lodOffsets[] =
2920 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2922 for (int py = 0; py < result.getHeight(); py++)
2924 for (int px = 0; px < result.getWidth(); px++)
2926 const tcu::Vec4 resPix = result.getPixel(px, py);
2927 const tcu::Vec4 refPix = reference.getPixel(px, py);
2929 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2931 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2937 const float wx = (float)px + 0.5f;
2938 const float wy = (float)py + 0.5f;
2939 const float nx = wx / dstW;
2940 const float ny = wy / dstH;
2942 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2943 const float triWx = triNdx ? dstW - wx : wx;
2944 const float triWy = triNdx ? dstH - wy : wy;
2945 const float triNx = triNdx ? 1.0f - nx : nx;
2946 const float triNy = triNdx ? 1.0f - ny : ny;
2948 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2949 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2950 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2951 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2952 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2953 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2954 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2955 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2956 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2958 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2960 // Compute lod bounds across lodOffsets range.
2961 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2963 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2964 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2965 const float nxo = wxo/dstW;
2966 const float nyo = wyo/dstH;
2968 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2969 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2970 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2971 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2972 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2973 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2974 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2975 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2976 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2977 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2979 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2980 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2983 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2984 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2988 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2998 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2999 const tcu::ConstPixelBufferAccess& reference,
3000 const tcu::PixelBufferAccess& errorMask,
3001 const tcu::Texture2DArrayView& src,
3002 const float* texCoord,
3003 const ReferenceParams& sampleParams,
3004 const tcu::TexComparePrecision& comparePrec,
3005 const tcu::LodPrecision& lodPrec,
3006 const tcu::Vec3& nonShadowThreshold)
3008 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3009 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3011 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
3012 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
3013 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
3015 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
3016 const float dstW = float(dstSize.x());
3017 const float dstH = float(dstSize.y());
3018 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
3020 // Coordinates and lod per triangle.
3021 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
3022 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
3023 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
3024 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
3026 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3030 const tcu::Vec2 lodOffsets[] =
3038 tcu::clear(errorMask, tcu::RGBA::green.toVec());
3040 for (int py = 0; py < result.getHeight(); py++)
3042 for (int px = 0; px < result.getWidth(); px++)
3044 const tcu::Vec4 resPix = result.getPixel(px, py);
3045 const tcu::Vec4 refPix = reference.getPixel(px, py);
3047 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
3049 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3055 const float wx = (float)px + 0.5f;
3056 const float wy = (float)py + 0.5f;
3057 const float nx = wx / dstW;
3058 const float ny = wy / dstH;
3060 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
3061 const float triWx = triNdx ? dstW - wx : wx;
3062 const float triWy = triNdx ? dstH - wy : wy;
3063 const float triNx = triNdx ? 1.0f - nx : nx;
3064 const float triNy = triNdx ? 1.0f - ny : ny;
3066 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3067 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
3068 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
3069 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
3070 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
3071 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
3072 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
3074 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
3076 // Compute lod bounds across lodOffsets range.
3077 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3079 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
3080 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
3081 const float nxo = wxo/dstW;
3082 const float nyo = wyo/dstH;
3084 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
3085 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
3086 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
3087 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
3088 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
3090 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3091 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3094 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3095 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3099 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3109 // Mipmap generation comparison.
3111 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3113 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3115 const float dstW = float(dst.getWidth());
3116 const float dstH = float(dst.getHeight());
3117 const float srcW = float(src.getWidth());
3118 const float srcH = float(src.getHeight());
3121 // Translation to lookup verification parameters.
3122 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3123 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3124 tcu::LookupPrecision lookupPrec;
3126 lookupPrec.colorThreshold = precision.colorThreshold;
3127 lookupPrec.colorMask = precision.colorMask;
3128 lookupPrec.coordBits = tcu::IVec3(22);
3129 lookupPrec.uvwBits = precision.filterBits;
3131 for (int y = 0; y < dst.getHeight(); y++)
3132 for (int x = 0; x < dst.getWidth(); x++)
3134 const tcu::Vec4 result = dst.getPixel(x, y);
3135 const float cx = (float(x)+0.5f) / dstW * srcW;
3136 const float cy = (float(y)+0.5f) / dstH * srcH;
3137 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3139 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3147 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3149 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3151 const float dstW = float(dst.getWidth());
3152 const float dstH = float(dst.getHeight());
3153 const float srcW = float(src.getWidth());
3154 const float srcH = float(src.getHeight());
3157 // Translation to lookup verification parameters.
3158 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3159 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3160 tcu::LookupPrecision lookupPrec;
3162 lookupPrec.colorThreshold = precision.colorThreshold;
3163 lookupPrec.colorMask = precision.colorMask;
3164 lookupPrec.coordBits = tcu::IVec3(22);
3165 lookupPrec.uvwBits = precision.filterBits;
3167 for (int y = 0; y < dst.getHeight(); y++)
3168 for (int x = 0; x < dst.getWidth(); x++)
3170 const tcu::Vec4 result = dst.getPixel(x, y);
3171 const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
3172 const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
3173 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3175 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3183 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3185 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3186 DE_UNREF(precision);
3188 const float dstW = float(dst.getWidth());
3189 const float dstH = float(dst.getHeight());
3190 const float srcW = float(src.getWidth());
3191 const float srcH = float(src.getHeight());
3194 for (int y = 0; y < dst.getHeight(); y++)
3195 for (int x = 0; x < dst.getWidth(); x++)
3197 const tcu::Vec4 result = dst.getPixel(x, y);
3198 const int minX = deFloorFloatToInt32(float(x-0.5f) / dstW * srcW);
3199 const int minY = deFloorFloatToInt32(float(y-0.5f) / dstH * srcH);
3200 const int maxX = deCeilFloatToInt32(float(x+1.5f) / dstW * srcW);
3201 const int maxY = deCeilFloatToInt32(float(y+1.5f) / dstH * srcH);
3202 tcu::Vec4 minVal, maxVal;
3205 DE_ASSERT(minX < maxX && minY < maxY);
3207 for (int ky = minY; ky <= maxY; ky++)
3209 for (int kx = minX; kx <= maxX; kx++)
3211 const int sx = de::clamp(kx, 0, src.getWidth()-1);
3212 const int sy = de::clamp(ky, 0, src.getHeight()-1);
3213 const tcu::Vec4 sample = src.getPixel(sx, sy);
3215 if (ky == minY && kx == minX)
3222 minVal = min(sample, minVal);
3223 maxVal = max(sample, maxVal);
3228 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
3230 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3238 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
3240 qpTestResult result = QP_TEST_RESULT_PASS;
3242 // Special comparison for level 0.
3244 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3245 const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
3249 log << TestLog::Message << "ERROR: Level 0 comparison failed!" << TestLog::EndMessage;
3250 result = QP_TEST_RESULT_FAIL;
3254 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3256 const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx-1);
3257 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx);
3258 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
3259 bool levelOk = false;
3261 // Try different comparisons in quality order.
3265 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3269 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3274 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3278 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3281 // At this point all high-quality methods have been used.
3282 if (!levelOk && result == QP_TEST_RESULT_PASS)
3283 result = QP_TEST_RESULT_QUALITY_WARNING;
3287 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3291 log << TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3295 result = QP_TEST_RESULT_FAIL;
3297 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
3298 << TestLog::Image("Result", "Result", dst);
3301 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3303 log << TestLog::EndImageSet;
3309 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
3311 qpTestResult result = QP_TEST_RESULT_PASS;
3313 static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
3314 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
3316 // Special comparison for level 0.
3317 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3319 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3320 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3321 const bool level0Ok = tcu::floatThresholdCompare(log,
3322 ("Level0Face" + de::toString(faceNdx)).c_str(),
3323 (string("Level 0, face ") + s_faceNames[face]).c_str(),
3324 level0Reference.getLevelFace(0, face),
3325 resultTexture.getLevelFace(0, face),
3326 threshold, tcu::COMPARE_LOG_RESULT);
3330 log << TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << TestLog::EndMessage;
3331 result = QP_TEST_RESULT_FAIL;
3335 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3337 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3339 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3340 const char* faceName = s_faceNames[face];
3341 const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx-1, face);
3342 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face);
3343 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
3344 bool levelOk = false;
3346 // Try different comparisons in quality order.
3350 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3354 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3359 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3363 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3366 // At this point all high-quality methods have been used.
3367 if (!levelOk && result == QP_TEST_RESULT_PASS)
3368 result = QP_TEST_RESULT_QUALITY_WARNING;
3372 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3376 log << TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3380 result = QP_TEST_RESULT_FAIL;
3382 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
3383 << TestLog::Image("Result", "Result", dst);
3386 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3388 log << TestLog::EndImageSet;
3395 // Logging utilities.
3397 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
3399 return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
3400 << "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
3401 << "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
3402 << "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3405 } // TextureTestUtil