3004 lines
122 KiB
C++
3004 lines
122 KiB
C++
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL ES Utilities
|
|
* ------------------------------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief Utility functions and structures for texture tests. This code
|
|
* is originated from the modules/glshared/glsTextureTestUtil.hpp and it
|
|
* is tightly coupled with the GLES and Vulkan texture tests!
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "gluTextureTestUtil.hpp"
|
|
|
|
#include "tcuFloat.hpp"
|
|
#include "tcuImageCompare.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuVectorUtil.hpp"
|
|
|
|
#include "deMath.h"
|
|
#include "deStringUtil.hpp"
|
|
|
|
#include <string>
|
|
|
|
using std::string;
|
|
|
|
namespace glu
|
|
{
|
|
|
|
namespace TextureTestUtil
|
|
{
|
|
|
|
enum
|
|
{
|
|
MIN_SUBPIXEL_BITS = 4
|
|
};
|
|
|
|
SamplerType getSamplerType (tcu::TextureFormat format)
|
|
{
|
|
using tcu::TextureFormat;
|
|
|
|
switch (format.type)
|
|
{
|
|
case TextureFormat::SIGNED_INT8:
|
|
case TextureFormat::SIGNED_INT16:
|
|
case TextureFormat::SIGNED_INT32:
|
|
return SAMPLERTYPE_INT;
|
|
|
|
case TextureFormat::UNSIGNED_INT8:
|
|
case TextureFormat::UNSIGNED_INT32:
|
|
case TextureFormat::UNSIGNED_INT_1010102_REV:
|
|
return SAMPLERTYPE_UINT;
|
|
|
|
// Texture formats used in depth/stencil textures.
|
|
case TextureFormat::UNSIGNED_INT16:
|
|
case TextureFormat::UNSIGNED_INT_24_8:
|
|
return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FLOAT : SAMPLERTYPE_UINT;
|
|
|
|
default:
|
|
return SAMPLERTYPE_FLOAT;
|
|
}
|
|
}
|
|
|
|
SamplerType getFetchSamplerType (tcu::TextureFormat format)
|
|
{
|
|
using tcu::TextureFormat;
|
|
|
|
switch (format.type)
|
|
{
|
|
case TextureFormat::SIGNED_INT8:
|
|
case TextureFormat::SIGNED_INT16:
|
|
case TextureFormat::SIGNED_INT32:
|
|
return SAMPLERTYPE_FETCH_INT;
|
|
|
|
case TextureFormat::UNSIGNED_INT8:
|
|
case TextureFormat::UNSIGNED_INT32:
|
|
case TextureFormat::UNSIGNED_INT_1010102_REV:
|
|
return SAMPLERTYPE_FETCH_UINT;
|
|
|
|
// Texture formats used in depth/stencil textures.
|
|
case TextureFormat::UNSIGNED_INT16:
|
|
case TextureFormat::UNSIGNED_INT_24_8:
|
|
return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FETCH_FLOAT : SAMPLERTYPE_FETCH_UINT;
|
|
|
|
default:
|
|
return SAMPLERTYPE_FETCH_FLOAT;
|
|
}
|
|
}
|
|
|
|
static tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLevel, int maxLevel)
|
|
{
|
|
const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
|
|
const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
|
|
const int numLevels = clampedMax-clampedBase+1;
|
|
return tcu::Texture1DView(numLevels, view.getLevels()+clampedBase);
|
|
}
|
|
|
|
static tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLevel, int maxLevel)
|
|
{
|
|
const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
|
|
const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
|
|
const int numLevels = clampedMax-clampedBase+1;
|
|
return tcu::Texture2DView(numLevels, view.getLevels()+clampedBase, view.isES2());
|
|
}
|
|
|
|
static tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int baseLevel, int maxLevel)
|
|
{
|
|
const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
|
|
const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
|
|
const int numLevels = clampedMax-clampedBase+1;
|
|
const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST];
|
|
|
|
for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
|
|
levels[face] = view.getFaceLevels((tcu::CubeFace)face) + clampedBase;
|
|
|
|
return tcu::TextureCubeView(numLevels, levels);
|
|
}
|
|
|
|
static tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLevel, int maxLevel)
|
|
{
|
|
const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
|
|
const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
|
|
const int numLevels = clampedMax-clampedBase+1;
|
|
return tcu::Texture3DView(numLevels, view.getLevels()+clampedBase);
|
|
}
|
|
|
|
static tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel)
|
|
{
|
|
const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
|
|
const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
|
|
const int numLevels = clampedMax-clampedBase+1;
|
|
return tcu::TextureCubeArrayView(numLevels, view.getLevels()+clampedBase);
|
|
}
|
|
|
|
inline float linearInterpolate (float t, float minVal, float maxVal)
|
|
{
|
|
return minVal + (maxVal - minVal) * t;
|
|
}
|
|
|
|
inline tcu::Vec4 linearInterpolate (float t, const tcu::Vec4& a, const tcu::Vec4& b)
|
|
{
|
|
return a + (b - a) * t;
|
|
}
|
|
|
|
inline float bilinearInterpolate (float x, float y, const tcu::Vec4& quad)
|
|
{
|
|
float w00 = (1.0f-x)*(1.0f-y);
|
|
float w01 = (1.0f-x)*y;
|
|
float w10 = x*(1.0f-y);
|
|
float w11 = x*y;
|
|
return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
|
|
}
|
|
|
|
float triangleInterpolate (float v0, float v1, float v2, float x, float y)
|
|
{
|
|
return v0 + (v2-v0)*x + (v1-v0)*y;
|
|
}
|
|
|
|
float triangleInterpolate (const tcu::Vec3& v, float x, float y)
|
|
{
|
|
return triangleInterpolate(v.x(), v.y(), v.z(), x, y);
|
|
}
|
|
|
|
// 1D lookup LOD computation.
|
|
|
|
float computeLodFromDerivates (LodMode mode, float dudx, float dudy)
|
|
{
|
|
float p = 0.0f;
|
|
switch (mode)
|
|
{
|
|
// \note [mika] Min and max bounds equal to exact with 1D textures
|
|
case LODMODE_EXACT:
|
|
case LODMODE_MIN_BOUND:
|
|
case LODMODE_MAX_BOUND:
|
|
p = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
return deFloatLog2(p);
|
|
}
|
|
|
|
float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, deInt32 srcSize, const tcu::Vec3& sq)
|
|
{
|
|
float dux = (sq.z() - sq.x()) * (float)srcSize;
|
|
float duy = (sq.y() - sq.x()) * (float)srcSize;
|
|
float dx = (float)dstSize.x();
|
|
float dy = (float)dstSize.y();
|
|
|
|
return computeLodFromDerivates(mode, dux/dx, duy/dy);
|
|
}
|
|
|
|
// 2D lookup LOD computation.
|
|
|
|
float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dudy, float dvdy)
|
|
{
|
|
float p = 0.0f;
|
|
switch (mode)
|
|
{
|
|
case LODMODE_EXACT:
|
|
p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx), deFloatSqrt(dudy*dudy + dvdy*dvdy));
|
|
break;
|
|
|
|
case LODMODE_MIN_BOUND:
|
|
case LODMODE_MAX_BOUND:
|
|
{
|
|
float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
|
|
float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
|
|
|
|
p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
return deFloatLog2(p);
|
|
}
|
|
|
|
float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec2& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq)
|
|
{
|
|
float dux = (sq.z() - sq.x()) * (float)srcSize.x();
|
|
float duy = (sq.y() - sq.x()) * (float)srcSize.x();
|
|
float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
|
|
float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
|
|
float dx = (float)dstSize.x();
|
|
float dy = (float)dstSize.y();
|
|
|
|
return computeLodFromDerivates(mode, dux/dx, dvx/dx, duy/dy, dvy/dy);
|
|
}
|
|
|
|
// 3D lookup LOD computation.
|
|
|
|
float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy)
|
|
{
|
|
float p = 0.0f;
|
|
switch (mode)
|
|
{
|
|
case LODMODE_EXACT:
|
|
p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx + dwdx*dwdx), deFloatSqrt(dudy*dudy + dvdy*dvdy + dwdy*dwdy));
|
|
break;
|
|
|
|
case LODMODE_MIN_BOUND:
|
|
case LODMODE_MAX_BOUND:
|
|
{
|
|
float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
|
|
float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
|
|
float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy));
|
|
|
|
p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
return deFloatLog2(p);
|
|
}
|
|
|
|
float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec3& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq, const tcu::Vec3& rq)
|
|
{
|
|
float dux = (sq.z() - sq.x()) * (float)srcSize.x();
|
|
float duy = (sq.y() - sq.x()) * (float)srcSize.x();
|
|
float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
|
|
float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
|
|
float dwx = (rq.z() - rq.x()) * (float)srcSize.z();
|
|
float dwy = (rq.y() - rq.x()) * (float)srcSize.z();
|
|
float dx = (float)dstSize.x();
|
|
float dy = (float)dstSize.y();
|
|
|
|
return computeLodFromDerivates(mode, dux/dx, dvx/dx, dwx/dx, duy/dy, dvy/dy, dwy/dy);
|
|
}
|
|
|
|
static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
|
|
{
|
|
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]);
|
|
}
|
|
|
|
static inline float triDerivateX (const tcu::Vec3& s, const tcu::Vec3& w, float wx, float width, float ny)
|
|
{
|
|
float d = w[1]*w[2]*(width*(ny - 1.0f) + wx) - w[0]*(w[2]*width*ny + w[1]*wx);
|
|
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);
|
|
}
|
|
|
|
static inline float triDerivateY (const tcu::Vec3& s, const tcu::Vec3& w, float wy, float height, float nx)
|
|
{
|
|
float d = w[1]*w[2]*(height*(nx - 1.0f) + wy) - w[0]*(w[1]*height*nx + w[2]*wy);
|
|
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);
|
|
}
|
|
|
|
// 1D lookup LOD.
|
|
static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& projection, float wx, float wy, float width, float height)
|
|
{
|
|
// Exact derivatives.
|
|
float dudx = triDerivateX(u, projection, wx, width, wy/height);
|
|
float dudy = triDerivateY(u, projection, wy, height, wx/width);
|
|
|
|
return computeLodFromDerivates(mode, dudx, dudy);
|
|
}
|
|
|
|
// 2D lookup LOD.
|
|
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)
|
|
{
|
|
// Exact derivatives.
|
|
float dudx = triDerivateX(u, projection, wx, width, wy/height);
|
|
float dvdx = triDerivateX(v, projection, wx, width, wy/height);
|
|
float dudy = triDerivateY(u, projection, wy, height, wx/width);
|
|
float dvdy = triDerivateY(v, projection, wy, height, wx/width);
|
|
|
|
return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy);
|
|
}
|
|
|
|
// 3D lookup LOD.
|
|
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)
|
|
{
|
|
// Exact derivatives.
|
|
float dudx = triDerivateX(u, projection, wx, width, wy/height);
|
|
float dvdx = triDerivateX(v, projection, wx, width, wy/height);
|
|
float dwdx = triDerivateX(w, projection, wx, width, wy/height);
|
|
float dudy = triDerivateY(u, projection, wy, height, wx/width);
|
|
float dvdy = triDerivateY(v, projection, wy, height, wx/width);
|
|
float dwdy = triDerivateY(w, projection, wy, height, wx/width);
|
|
|
|
return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy);
|
|
}
|
|
|
|
static inline tcu::Vec4 execSample (const tcu::Texture1DView& src, const ReferenceParams& params, float s, float lod)
|
|
{
|
|
if (params.samplerType == SAMPLERTYPE_SHADOW)
|
|
return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f);
|
|
else
|
|
return src.sample(params.sampler, s, lod);
|
|
}
|
|
|
|
static inline tcu::Vec4 execSample (const tcu::Texture2DView& src, const ReferenceParams& params, float s, float t, float lod)
|
|
{
|
|
if (params.samplerType == SAMPLERTYPE_SHADOW)
|
|
return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
|
|
else
|
|
return src.sample(params.sampler, s, t, lod);
|
|
}
|
|
|
|
static inline tcu::Vec4 execSample (const tcu::TextureCubeView& src, const ReferenceParams& params, float s, float t, float r, float lod)
|
|
{
|
|
if (params.samplerType == SAMPLERTYPE_SHADOW)
|
|
return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
|
|
else
|
|
return src.sample(params.sampler, s, t, r, lod);
|
|
}
|
|
|
|
static inline tcu::Vec4 execSample (const tcu::Texture2DArrayView& src, const ReferenceParams& params, float s, float t, float r, float lod)
|
|
{
|
|
if (params.samplerType == SAMPLERTYPE_SHADOW)
|
|
return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
|
|
else
|
|
return src.sample(params.sampler, s, t, r, lod);
|
|
}
|
|
|
|
static inline tcu::Vec4 execSample (const tcu::TextureCubeArrayView& src, const ReferenceParams& params, float s, float t, float r, float q, float lod)
|
|
{
|
|
if (params.samplerType == SAMPLERTYPE_SHADOW)
|
|
return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f);
|
|
else
|
|
return src.sample(params.sampler, s, t, r, q, lod);
|
|
}
|
|
|
|
static inline tcu::Vec4 execSample (const tcu::Texture1DArrayView& src, const ReferenceParams& params, float s, float t, float lod)
|
|
{
|
|
if (params.samplerType == SAMPLERTYPE_SHADOW)
|
|
return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
|
|
else
|
|
return src.sample(params.sampler, s, t, lod);
|
|
}
|
|
|
|
static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
|
|
tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
|
|
int srcSize = src.getWidth();
|
|
|
|
// Coordinates and lod per triangle.
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod),
|
|
de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) };
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
float yf = ((float)y + 0.5f) / (float)dst.getHeight();
|
|
float xf = ((float)x + 0.5f) / (float)dst.getWidth();
|
|
|
|
int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
|
|
float triX = triNdx ? 1.0f-xf : xf;
|
|
float triY = triNdx ? 1.0f-yf : yf;
|
|
|
|
float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
|
|
float lod = triLod[triNdx];
|
|
|
|
dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
|
|
tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
|
|
tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
|
|
|
|
// Coordinates and lod per triangle.
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
|
|
de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
float yf = ((float)y + 0.5f) / (float)dst.getHeight();
|
|
float xf = ((float)x + 0.5f) / (float)dst.getWidth();
|
|
|
|
int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
|
|
float triX = triNdx ? 1.0f-xf : xf;
|
|
float triY = triNdx ? 1.0f-yf : yf;
|
|
|
|
float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
|
|
float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
|
|
float lod = triLod[triNdx];
|
|
|
|
dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture1DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
float dstW = (float)dst.getWidth();
|
|
float dstH = (float)dst.getHeight();
|
|
|
|
tcu::Vec4 uq = sq * (float)src.getWidth();
|
|
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
|
|
|
|
for (int py = 0; py < dst.getHeight(); py++)
|
|
{
|
|
for (int px = 0; px < dst.getWidth(); px++)
|
|
{
|
|
float wx = (float)px + 0.5f;
|
|
float wy = (float)py + 0.5f;
|
|
float nx = wx / dstW;
|
|
float ny = wy / dstH;
|
|
|
|
int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
float triWx = triNdx ? dstW - wx : wx;
|
|
float triWy = triNdx ? dstH - wy : wy;
|
|
float triNx = triNdx ? 1.0f - nx : nx;
|
|
float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
|
|
float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
|
|
+ lodBias;
|
|
|
|
dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture2DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
float dstW = (float)dst.getWidth();
|
|
float dstH = (float)dst.getHeight();
|
|
|
|
tcu::Vec4 uq = sq * (float)src.getWidth();
|
|
tcu::Vec4 vq = tq * (float)src.getHeight();
|
|
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
|
|
|
|
for (int py = 0; py < dst.getHeight(); py++)
|
|
{
|
|
for (int px = 0; px < dst.getWidth(); px++)
|
|
{
|
|
float wx = (float)px + 0.5f;
|
|
float wy = (float)py + 0.5f;
|
|
float nx = wx / dstW;
|
|
float ny = wy / dstH;
|
|
|
|
int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
float triWx = triNdx ? dstW - wx : wx;
|
|
float triWy = triNdx ? dstH - wy : wy;
|
|
float triNx = triNdx ? 1.0f - nx : nx;
|
|
float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
|
|
float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
|
|
float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
|
|
+ lodBias;
|
|
|
|
dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
|
|
{
|
|
const tcu::Texture2DView view = getSubView(src, params.baseLevel, params.maxLevel);
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
|
|
|
|
if (params.flags & ReferenceParams::PROJECTED)
|
|
sampleTextureProjected(dst, view, sq, tq, params);
|
|
else
|
|
sampleTextureNonProjected(dst, view, sq, tq, params);
|
|
}
|
|
|
|
void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params)
|
|
{
|
|
const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel);
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
|
|
|
|
if (params.flags & ReferenceParams::PROJECTED)
|
|
sampleTextureProjected(dst, view, sq, params);
|
|
else
|
|
sampleTextureNonProjected(dst, view, sq, params);
|
|
}
|
|
|
|
static float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize)
|
|
{
|
|
const tcu::CubeFace face = tcu::selectCubeFace(coord);
|
|
int maNdx = 0;
|
|
int sNdx = 0;
|
|
int tNdx = 0;
|
|
|
|
// \note Derivate signs don't matter when computing lod
|
|
switch (face)
|
|
{
|
|
case tcu::CUBEFACE_NEGATIVE_X:
|
|
case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
|
|
case tcu::CUBEFACE_NEGATIVE_Y:
|
|
case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
|
|
case tcu::CUBEFACE_NEGATIVE_Z:
|
|
case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
{
|
|
const float sc = coord[sNdx];
|
|
const float tc = coord[tNdx];
|
|
const float ma = de::abs(coord[maNdx]);
|
|
const float scdx = coordDx[sNdx];
|
|
const float tcdx = coordDx[tNdx];
|
|
const float madx = de::abs(coordDx[maNdx]);
|
|
const float scdy = coordDy[sNdx];
|
|
const float tcdy = coordDy[tNdx];
|
|
const float mady = de::abs(coordDy[maNdx]);
|
|
const float dudx = float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma);
|
|
const float dvdx = float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma);
|
|
const float dudy = float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma);
|
|
const float dvdy = float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma);
|
|
|
|
return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
|
|
}
|
|
}
|
|
|
|
static void sampleTextureCube (const tcu::SurfaceAccess& dst, const tcu::TextureCubeView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::TextureCubeView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const int srcSize = src.getSize();
|
|
|
|
// Coordinates per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
|
|
|
|
const float lodBias ((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
|
|
|
|
for (int py = 0; py < dst.getHeight(); py++)
|
|
{
|
|
for (int px = 0; px < dst.getWidth(); px++)
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
|
|
triangleInterpolate(triT[triNdx], triNx, triNy),
|
|
triangleInterpolate(triR[triNdx], triNx, triNy));
|
|
const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
|
|
const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
|
|
|
|
const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod);
|
|
|
|
dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
|
|
{
|
|
const tcu::TextureCubeView view = getSubView(src, params.baseLevel, params.maxLevel);
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
|
|
const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
|
|
|
|
return sampleTextureCube(dst, view, sq, tq, rq, params);
|
|
}
|
|
|
|
static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture2DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture2DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
|
|
tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
|
|
tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
|
|
|
|
// Coordinates and lod per triangle.
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
|
|
de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
float yf = ((float)y + 0.5f) / (float)dst.getHeight();
|
|
float xf = ((float)x + 0.5f) / (float)dst.getWidth();
|
|
|
|
int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
|
|
float triX = triNdx ? 1.0f-xf : xf;
|
|
float triY = triNdx ? 1.0f-yf : yf;
|
|
|
|
float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
|
|
float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
|
|
float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
|
|
float lod = triLod[triNdx];
|
|
|
|
dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params)
|
|
{
|
|
tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
|
|
tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
|
|
tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
|
|
|
|
DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
|
|
sampleTextureNonProjected(dst, src, sq, tq, rq, params);
|
|
}
|
|
|
|
static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture1DArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
|
|
tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
|
|
deInt32 srcSize = src.getWidth();
|
|
|
|
// Coordinates and lod per triangle.
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
|
|
computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
float yf = ((float)y + 0.5f) / (float)dst.getHeight();
|
|
float xf = ((float)x + 0.5f) / (float)dst.getWidth();
|
|
|
|
int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
|
|
float triX = triNdx ? 1.0f-xf : xf;
|
|
float triY = triNdx ? 1.0f-yf : yf;
|
|
|
|
float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
|
|
float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
|
|
float lod = triLod[triNdx];
|
|
|
|
dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params)
|
|
{
|
|
tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
|
|
tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
|
|
|
|
DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
|
|
sampleTextureNonProjected(dst, src, sq, tq, params);
|
|
}
|
|
|
|
static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
|
|
tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
|
|
tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
|
|
|
|
// Coordinates and lod per triangle.
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod),
|
|
de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) };
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
float yf = ((float)y + 0.5f) / (float)dst.getHeight();
|
|
float xf = ((float)x + 0.5f) / (float)dst.getWidth();
|
|
|
|
int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
|
|
float triX = triNdx ? 1.0f-xf : xf;
|
|
float triY = triNdx ? 1.0f-yf : yf;
|
|
|
|
float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
|
|
float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
|
|
float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
|
|
float lod = triLod[triNdx];
|
|
|
|
dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sampleTextureProjected (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture3DView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
float dstW = (float)dst.getWidth();
|
|
float dstH = (float)dst.getHeight();
|
|
|
|
tcu::Vec4 uq = sq * (float)src.getWidth();
|
|
tcu::Vec4 vq = tq * (float)src.getHeight();
|
|
tcu::Vec4 wq = rq * (float)src.getDepth();
|
|
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triW[2] = { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triP[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
|
|
|
|
for (int py = 0; py < dst.getHeight(); py++)
|
|
{
|
|
for (int px = 0; px < dst.getWidth(); px++)
|
|
{
|
|
float wx = (float)px + 0.5f;
|
|
float wy = (float)py + 0.5f;
|
|
float nx = wx / dstW;
|
|
float ny = wy / dstH;
|
|
|
|
int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
float triWx = triNdx ? dstW - wx : wx;
|
|
float triWy = triNdx ? dstH - wy : wy;
|
|
float triNx = triNdx ? 1.0f - nx : nx;
|
|
float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
|
|
float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
|
|
float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
|
|
float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
|
|
+ lodBias;
|
|
|
|
dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params)
|
|
{
|
|
const tcu::Texture3DView view = getSubView(src, params.baseLevel, params.maxLevel);
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
|
|
const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
|
|
|
|
if (params.flags & ReferenceParams::PROJECTED)
|
|
sampleTextureProjected(dst, view, sq, tq, rq, params);
|
|
else
|
|
sampleTextureNonProjected(dst, view, sq, tq, rq, params);
|
|
}
|
|
|
|
static void sampleTextureCubeArray (const tcu::SurfaceAccess& dst, const tcu::TextureCubeArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const tcu::Vec4& qq, const ReferenceParams& params)
|
|
{
|
|
// Separate combined DS formats
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::TextureCubeArrayView src = getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
|
|
|
|
const float dstW = (float)dst.getWidth();
|
|
const float dstH = (float)dst.getHeight();
|
|
|
|
// Coordinates per triangle.
|
|
tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
|
|
|
|
const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
|
|
|
|
for (int py = 0; py < dst.getHeight(); py++)
|
|
{
|
|
for (int px = 0; px < dst.getWidth(); px++)
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
|
|
triangleInterpolate(triT[triNdx], triNx, triNy),
|
|
triangleInterpolate(triR[triNdx], triNx, triNy));
|
|
|
|
const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy);
|
|
|
|
const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
|
|
const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
|
|
|
|
const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
|
|
|
|
dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sampleTexture (const tcu::SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params)
|
|
{
|
|
tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
|
|
tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
|
|
tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
|
|
tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
|
|
|
|
sampleTextureCubeArray(dst, src, sq, tq, rq, qq, params);
|
|
}
|
|
|
|
void fetchTexture (const tcu::SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias)
|
|
{
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
{
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
const float yf = ((float)y + 0.5f) / (float)dst.getHeight();
|
|
const float xf = ((float)x + 0.5f) / (float)dst.getWidth();
|
|
|
|
const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
|
|
const float triX = triNdx ? 1.0f-xf : xf;
|
|
const float triY = triNdx ? 1.0f-yf : yf;
|
|
|
|
const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
|
|
|
|
dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool compareImages (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
|
|
{
|
|
return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
|
|
}
|
|
|
|
bool compareImages (tcu::TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
|
|
{
|
|
return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
|
|
}
|
|
|
|
int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
|
|
{
|
|
return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
|
|
}
|
|
|
|
inline int rangeDiff (int x, int a, int b)
|
|
{
|
|
if (x < a)
|
|
return a-x;
|
|
else if (x > b)
|
|
return x-b;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
|
|
{
|
|
int rMin = de::min(a.getRed(), b.getRed());
|
|
int rMax = de::max(a.getRed(), b.getRed());
|
|
int gMin = de::min(a.getGreen(), b.getGreen());
|
|
int gMax = de::max(a.getGreen(), b.getGreen());
|
|
int bMin = de::min(a.getBlue(), b.getBlue());
|
|
int bMax = de::max(a.getBlue(), b.getBlue());
|
|
int aMin = de::min(a.getAlpha(), b.getAlpha());
|
|
int aMax = de::max(a.getAlpha(), b.getAlpha());
|
|
|
|
return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax),
|
|
rangeDiff(p.getGreen(), gMin, gMax),
|
|
rangeDiff(p.getBlue(), bMin, bMax),
|
|
rangeDiff(p.getAlpha(), aMin, aMax));
|
|
}
|
|
|
|
inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
|
|
{
|
|
tcu::RGBA diff = rangeDiff(p, a, b);
|
|
return diff.getRed() <= threshold.getRed() &&
|
|
diff.getGreen() <= threshold.getGreen() &&
|
|
diff.getBlue() <= threshold.getBlue() &&
|
|
diff.getAlpha() <= threshold.getAlpha();
|
|
}
|
|
|
|
void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
|
|
{
|
|
dst.resize(4);
|
|
|
|
dst[0] = left;
|
|
dst[1] = left;
|
|
dst[2] = right;
|
|
dst[3] = right;
|
|
}
|
|
|
|
void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
|
|
{
|
|
dst.resize(4*2);
|
|
|
|
dst[0] = left; dst[1] = (float)layerNdx;
|
|
dst[2] = left; dst[3] = (float)layerNdx;
|
|
dst[4] = right; dst[5] = (float)layerNdx;
|
|
dst[6] = right; dst[7] = (float)layerNdx;
|
|
}
|
|
|
|
void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
|
|
{
|
|
dst.resize(4*2);
|
|
|
|
dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y();
|
|
dst[2] = bottomLeft.x(); dst[3] = topRight.y();
|
|
dst[4] = topRight.x(); dst[5] = bottomLeft.y();
|
|
dst[6] = topRight.x(); dst[7] = topRight.y();
|
|
}
|
|
|
|
void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
|
|
{
|
|
dst.resize(4*3);
|
|
|
|
dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx;
|
|
dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx;
|
|
dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx;
|
|
dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx;
|
|
}
|
|
|
|
void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
|
|
{
|
|
tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
|
|
tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
|
|
tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
|
|
tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
|
|
|
|
tcu::Vec3 v0 = p0 + (p1-p0)*f0;
|
|
tcu::Vec3 v1 = p0 + (p1-p0)*f1;
|
|
tcu::Vec3 v2 = p0 + (p1-p0)*f2;
|
|
tcu::Vec3 v3 = p0 + (p1-p0)*f3;
|
|
|
|
dst.resize(4*3);
|
|
|
|
dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
|
|
dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
|
|
dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
|
|
dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
|
|
}
|
|
|
|
void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
|
|
{
|
|
static const float texCoordNegX[] =
|
|
{
|
|
-1.0f, 1.0f, -1.0f,
|
|
-1.0f, -1.0f, -1.0f,
|
|
-1.0f, 1.0f, 1.0f,
|
|
-1.0f, -1.0f, 1.0f
|
|
};
|
|
static const float texCoordPosX[] =
|
|
{
|
|
+1.0f, 1.0f, 1.0f,
|
|
+1.0f, -1.0f, 1.0f,
|
|
+1.0f, 1.0f, -1.0f,
|
|
+1.0f, -1.0f, -1.0f
|
|
};
|
|
static const float texCoordNegY[] =
|
|
{
|
|
-1.0f, -1.0f, 1.0f,
|
|
-1.0f, -1.0f, -1.0f,
|
|
1.0f, -1.0f, 1.0f,
|
|
1.0f, -1.0f, -1.0f
|
|
};
|
|
static const float texCoordPosY[] =
|
|
{
|
|
-1.0f, +1.0f, -1.0f,
|
|
-1.0f, +1.0f, 1.0f,
|
|
1.0f, +1.0f, -1.0f,
|
|
1.0f, +1.0f, 1.0f
|
|
};
|
|
static const float texCoordNegZ[] =
|
|
{
|
|
1.0f, 1.0f, -1.0f,
|
|
1.0f, -1.0f, -1.0f,
|
|
-1.0f, 1.0f, -1.0f,
|
|
-1.0f, -1.0f, -1.0f
|
|
};
|
|
static const float texCoordPosZ[] =
|
|
{
|
|
-1.0f, 1.0f, +1.0f,
|
|
-1.0f, -1.0f, +1.0f,
|
|
1.0f, 1.0f, +1.0f,
|
|
1.0f, -1.0f, +1.0f
|
|
};
|
|
|
|
const float* texCoord = DE_NULL;
|
|
int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX);
|
|
|
|
switch (face)
|
|
{
|
|
case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
|
|
case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
|
|
case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
|
|
case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
|
|
case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
|
|
case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return;
|
|
}
|
|
|
|
dst.resize(texCoordSize);
|
|
std::copy(texCoord, texCoord+texCoordSize, dst.begin());
|
|
}
|
|
|
|
void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
|
|
{
|
|
int sRow = 0;
|
|
int tRow = 0;
|
|
int mRow = 0;
|
|
float sSign = 1.0f;
|
|
float tSign = 1.0f;
|
|
float mSign = 1.0f;
|
|
|
|
switch (face)
|
|
{
|
|
case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
|
|
case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
|
|
case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
|
|
case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
|
|
case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
|
|
case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return;
|
|
}
|
|
|
|
dst.resize(3*4);
|
|
|
|
dst[0+mRow] = mSign;
|
|
dst[3+mRow] = mSign;
|
|
dst[6+mRow] = mSign;
|
|
dst[9+mRow] = mSign;
|
|
|
|
dst[0+sRow] = sSign * bottomLeft.x();
|
|
dst[3+sRow] = sSign * bottomLeft.x();
|
|
dst[6+sRow] = sSign * topRight.x();
|
|
dst[9+sRow] = sSign * topRight.x();
|
|
|
|
dst[0+tRow] = tSign * bottomLeft.y();
|
|
dst[3+tRow] = tSign * topRight.y();
|
|
dst[6+tRow] = tSign * bottomLeft.y();
|
|
dst[9+tRow] = tSign * topRight.y();
|
|
}
|
|
|
|
void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
|
|
{
|
|
int sRow = 0;
|
|
int tRow = 0;
|
|
int mRow = 0;
|
|
const int qRow = 3;
|
|
float sSign = 1.0f;
|
|
float tSign = 1.0f;
|
|
float mSign = 1.0f;
|
|
const float l0 = layerRange.x();
|
|
const float l1 = layerRange.y();
|
|
|
|
switch (face)
|
|
{
|
|
case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
|
|
case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
|
|
case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
|
|
case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
|
|
case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
|
|
case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return;
|
|
}
|
|
|
|
dst.resize(4*4);
|
|
|
|
dst[ 0+mRow] = mSign;
|
|
dst[ 4+mRow] = mSign;
|
|
dst[ 8+mRow] = mSign;
|
|
dst[12+mRow] = mSign;
|
|
|
|
dst[ 0+sRow] = sSign * bottomLeft.x();
|
|
dst[ 4+sRow] = sSign * bottomLeft.x();
|
|
dst[ 8+sRow] = sSign * topRight.x();
|
|
dst[12+sRow] = sSign * topRight.x();
|
|
|
|
dst[ 0+tRow] = tSign * bottomLeft.y();
|
|
dst[ 4+tRow] = tSign * topRight.y();
|
|
dst[ 8+tRow] = tSign * bottomLeft.y();
|
|
dst[12+tRow] = tSign * topRight.y();
|
|
|
|
if (l0 != l1)
|
|
{
|
|
dst[ 0+qRow] = l0;
|
|
dst[ 4+qRow] = l0*0.5f + l1*0.5f;
|
|
dst[ 8+qRow] = l0*0.5f + l1*0.5f;
|
|
dst[12+qRow] = l1;
|
|
}
|
|
else
|
|
{
|
|
dst[ 0+qRow] = l0;
|
|
dst[ 4+qRow] = l0;
|
|
dst[ 8+qRow] = l0;
|
|
dst[12+qRow] = l0;
|
|
}
|
|
}
|
|
|
|
// Texture result verification
|
|
|
|
//! Verifies texture lookup results and returns number of failed pixels.
|
|
int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::Texture1DView& baseView,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
qpWatchDog* watchDog)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture1DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const int srcSize = src.getWidth();
|
|
|
|
// Coordinates and lod per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
// Ugly hack, validation can take way too long at the moment.
|
|
if (watchDog)
|
|
qpWatchDog_touch(watchDog);
|
|
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
|
|
// Try comparison to ideal reference first, and if that fails use slower verificator.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
|
|
const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
|
|
const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
|
|
const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
|
|
const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::Texture2DView& baseView,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
qpWatchDog* watchDog)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture2DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
|
|
|
|
// Coordinates and lod per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
// Ugly hack, validation can take way too long at the moment.
|
|
if (watchDog)
|
|
qpWatchDog_touch(watchDog);
|
|
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
|
|
// Try comparison to ideal reference first, and if that fails use slower verificator.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
|
|
const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
|
|
|
|
bool isOk = false;
|
|
|
|
DE_ASSERT(tri0 || tri1);
|
|
|
|
// Pixel can belong to either of the triangles if it lies close enough to the edge.
|
|
for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
|
|
{
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
|
|
const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
|
|
const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
|
|
const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
|
|
const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
|
|
{
|
|
isOk = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
bool verifyTextureResult (tcu::TestContext& testCtx,
|
|
const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::Texture1DView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::PixelFormat& pixelFormat)
|
|
{
|
|
tcu::TestLog& log = testCtx.getLog();
|
|
tcu::Surface reference (result.getWidth(), result.getHeight());
|
|
tcu::Surface errorMask (result.getWidth(), result.getHeight());
|
|
int numFailedPixels;
|
|
|
|
DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
|
|
|
|
sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
|
|
numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
|
|
|
|
if (numFailedPixels > 0)
|
|
log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
|
|
|
|
log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
|
|
<< tcu::TestLog::Image("Rendered", "Rendered image", result);
|
|
|
|
if (numFailedPixels > 0)
|
|
{
|
|
log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
|
|
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
}
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
|
|
return numFailedPixels == 0;
|
|
}
|
|
|
|
bool verifyTextureResult (tcu::TestContext& testCtx,
|
|
const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::Texture2DView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::PixelFormat& pixelFormat)
|
|
{
|
|
tcu::TestLog& log = testCtx.getLog();
|
|
tcu::Surface reference (result.getWidth(), result.getHeight());
|
|
tcu::Surface errorMask (result.getWidth(), result.getHeight());
|
|
int numFailedPixels;
|
|
|
|
DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
|
|
|
|
sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
|
|
numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
|
|
|
|
if (numFailedPixels > 0)
|
|
log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
|
|
|
|
log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
|
|
<< tcu::TestLog::Image("Rendered", "Rendered image", result);
|
|
|
|
if (numFailedPixels > 0)
|
|
{
|
|
log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
|
|
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
}
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
|
|
return numFailedPixels == 0;
|
|
}
|
|
|
|
//! Verifies texture lookup results and returns number of failed pixels.
|
|
int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::TextureCubeView& baseView,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
qpWatchDog* watchDog)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::TextureCubeView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
|
|
const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const int srcSize = src.getSize();
|
|
|
|
// Coordinates per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
|
|
// \note Not strictly allowed by spec, but implementations do this in practice.
|
|
tcu::Vec2(-1, -1),
|
|
tcu::Vec2(-1, +1),
|
|
tcu::Vec2(+1, -1),
|
|
tcu::Vec2(+1, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
// Ugly hack, validation can take way too long at the moment.
|
|
if (watchDog)
|
|
qpWatchDog_touch(watchDog);
|
|
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
|
|
// Try comparison to ideal reference first, and if that fails use slower verificator.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
|
|
const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
|
|
|
|
bool isOk = false;
|
|
|
|
DE_ASSERT(tri0 || tri1);
|
|
|
|
// Pixel can belong to either of the triangles if it lies close enough to the edge.
|
|
for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
|
|
{
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
|
|
const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
|
|
const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
|
|
const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
|
|
const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
|
|
const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
|
|
if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
|
|
{
|
|
isOk = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
bool verifyTextureResult (tcu::TestContext& testCtx,
|
|
const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::TextureCubeView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::PixelFormat& pixelFormat)
|
|
{
|
|
tcu::TestLog& log = testCtx.getLog();
|
|
tcu::Surface reference (result.getWidth(), result.getHeight());
|
|
tcu::Surface errorMask (result.getWidth(), result.getHeight());
|
|
int numFailedPixels;
|
|
|
|
DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
|
|
|
|
sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
|
|
numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
|
|
|
|
if (numFailedPixels > 0)
|
|
log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
|
|
|
|
log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
|
|
<< tcu::TestLog::Image("Rendered", "Rendered image", result);
|
|
|
|
if (numFailedPixels > 0)
|
|
{
|
|
log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
|
|
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
}
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
|
|
return numFailedPixels == 0;
|
|
}
|
|
|
|
//! Verifies texture lookup results and returns number of failed pixels.
|
|
int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::Texture3DView& baseView,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
qpWatchDog* watchDog)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture3DView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
|
|
const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
|
|
|
|
// Coordinates and lod per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
// Ugly hack, validation can take way too long at the moment.
|
|
if (watchDog)
|
|
qpWatchDog_touch(watchDog);
|
|
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
|
|
// Try comparison to ideal reference first, and if that fails use slower verificator.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
|
|
const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
|
|
|
|
bool isOk = false;
|
|
|
|
DE_ASSERT(tri0 || tri1);
|
|
|
|
// Pixel can belong to either of the triangles if it lies close enough to the edge.
|
|
for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
|
|
{
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
|
|
const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
|
|
const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
|
|
const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
|
|
const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
|
|
if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
|
|
{
|
|
isOk = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
bool verifyTextureResult (tcu::TestContext& testCtx,
|
|
const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::Texture3DView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::PixelFormat& pixelFormat)
|
|
{
|
|
tcu::TestLog& log = testCtx.getLog();
|
|
tcu::Surface reference (result.getWidth(), result.getHeight());
|
|
tcu::Surface errorMask (result.getWidth(), result.getHeight());
|
|
int numFailedPixels;
|
|
|
|
DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
|
|
|
|
sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
|
|
numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
|
|
|
|
if (numFailedPixels > 0)
|
|
log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
|
|
|
|
log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
|
|
<< tcu::TestLog::Image("Rendered", "Rendered image", result);
|
|
|
|
if (numFailedPixels > 0)
|
|
{
|
|
log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
|
|
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
}
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
|
|
return numFailedPixels == 0;
|
|
}
|
|
|
|
//! Verifies texture lookup results and returns number of failed pixels.
|
|
int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::Texture1DArrayView& baseView,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
qpWatchDog* watchDog)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture1DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored.
|
|
|
|
// Coordinates and lod per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
// Ugly hack, validation can take way too long at the moment.
|
|
if (watchDog)
|
|
qpWatchDog_touch(watchDog);
|
|
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
|
|
// Try comparison to ideal reference first, and if that fails use slower verificator.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
|
|
const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
|
|
const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
|
|
const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
|
|
const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
//! Verifies texture lookup results and returns number of failed pixels.
|
|
int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::Texture2DArrayView& baseView,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
qpWatchDog* watchDog)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::Texture2DArrayView src = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
|
|
const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const tcu::Vec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
|
|
|
|
// Coordinates and lod per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
// Ugly hack, validation can take way too long at the moment.
|
|
if (watchDog)
|
|
qpWatchDog_touch(watchDog);
|
|
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
|
|
// Try comparison to ideal reference first, and if that fails use slower verificator.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
|
|
const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
|
|
const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
|
|
const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
|
|
const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
bool verifyTextureResult (tcu::TestContext& testCtx,
|
|
const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::Texture1DArrayView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::PixelFormat& pixelFormat)
|
|
{
|
|
tcu::TestLog& log = testCtx.getLog();
|
|
tcu::Surface reference (result.getWidth(), result.getHeight());
|
|
tcu::Surface errorMask (result.getWidth(), result.getHeight());
|
|
int numFailedPixels;
|
|
|
|
DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
|
|
|
|
sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
|
|
numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
|
|
|
|
if (numFailedPixels > 0)
|
|
log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
|
|
|
|
log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
|
|
<< tcu::TestLog::Image("Rendered", "Rendered image", result);
|
|
|
|
if (numFailedPixels > 0)
|
|
{
|
|
log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
|
|
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
}
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
|
|
return numFailedPixels == 0;
|
|
}
|
|
|
|
bool verifyTextureResult (tcu::TestContext& testCtx,
|
|
const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::Texture2DArrayView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::PixelFormat& pixelFormat)
|
|
{
|
|
tcu::TestLog& log = testCtx.getLog();
|
|
tcu::Surface reference (result.getWidth(), result.getHeight());
|
|
tcu::Surface errorMask (result.getWidth(), result.getHeight());
|
|
int numFailedPixels;
|
|
|
|
DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
|
|
|
|
sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
|
|
numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
|
|
|
|
if (numFailedPixels > 0)
|
|
log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
|
|
|
|
log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
|
|
<< tcu::TestLog::Image("Rendered", "Rendered image", result);
|
|
|
|
if (numFailedPixels > 0)
|
|
{
|
|
log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
|
|
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
}
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
|
|
return numFailedPixels == 0;
|
|
}
|
|
|
|
//! Verifies texture lookup results and returns number of failed pixels.
|
|
int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::TextureCubeArrayView& baseView,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::IVec4& coordBits,
|
|
const tcu::LodPrecision& lodPrec,
|
|
qpWatchDog* watchDog)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage;
|
|
const tcu::TextureCubeArrayView src = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
|
|
const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
|
|
const tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const int srcSize = src.getSize();
|
|
|
|
// Coordinates per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
const float posEps = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
|
|
// \note Not strictly allowed by spec, but implementations do this in practice.
|
|
tcu::Vec2(-1, -1),
|
|
tcu::Vec2(-1, +1),
|
|
tcu::Vec2(+1, -1),
|
|
tcu::Vec2(+1, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
// Ugly hack, validation can take way too long at the moment.
|
|
if (watchDog)
|
|
qpWatchDog_touch(watchDog);
|
|
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
|
|
|
|
// Try comparison to ideal reference first, and if that fails use slower verificator.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const bool tri0 = nx + ny - posEps <= 1.0f;
|
|
const bool tri1 = nx + ny + posEps >= 1.0f;
|
|
|
|
bool isOk = false;
|
|
|
|
DE_ASSERT(tri0 || tri1);
|
|
|
|
// Pixel can belong to either of the triangles if it lies close enough to the edge.
|
|
for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
|
|
{
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec4 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
|
|
const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
|
|
const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
|
|
const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
|
|
const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
|
|
const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
|
|
if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
|
|
{
|
|
isOk = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
bool verifyTextureResult (tcu::TestContext& testCtx,
|
|
const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::TextureCubeArrayView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::LookupPrecision& lookupPrec,
|
|
const tcu::IVec4& coordBits,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::PixelFormat& pixelFormat)
|
|
{
|
|
tcu::TestLog& log = testCtx.getLog();
|
|
tcu::Surface reference (result.getWidth(), result.getHeight());
|
|
tcu::Surface errorMask (result.getWidth(), result.getHeight());
|
|
int numFailedPixels;
|
|
|
|
DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
|
|
|
|
sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
|
|
numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
|
|
|
|
if (numFailedPixels > 0)
|
|
log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
|
|
|
|
log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
|
|
<< tcu::TestLog::Image("Rendered", "Rendered image", result);
|
|
|
|
if (numFailedPixels > 0)
|
|
{
|
|
log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
|
|
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
}
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
|
|
return numFailedPixels == 0;
|
|
}
|
|
|
|
// Shadow lookup verification
|
|
|
|
int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::Texture2DView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::TexComparePrecision& comparePrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::Vec3& nonShadowThreshold)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
|
|
|
|
// Coordinates and lod per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = result.getPixel(px, py);
|
|
const tcu::Vec4 refPix = reference.getPixel(px, py);
|
|
|
|
// Other channels should trivially match to reference.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
continue;
|
|
}
|
|
|
|
// Reference result is known to be a valid result, we can
|
|
// skip verification if thes results are equal
|
|
if (resPix.x() != refPix.x())
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
|
|
const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
|
|
const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
|
|
const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
|
|
const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::TextureCubeView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::TexComparePrecision& comparePrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::Vec3& nonShadowThreshold)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
|
|
const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const int srcSize = src.getSize();
|
|
|
|
// Coordinates per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = result.getPixel(px, py);
|
|
const tcu::Vec4 refPix = reference.getPixel(px, py);
|
|
|
|
// Other channels should trivially match to reference.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
continue;
|
|
}
|
|
|
|
// Reference result is known to be a valid result, we can
|
|
// skip verification if thes results are equal
|
|
if (resPix.x() != refPix.x())
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
|
|
const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
|
|
const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
|
|
const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
|
|
const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
|
|
const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
|
|
const tcu::ConstPixelBufferAccess& reference,
|
|
const tcu::PixelBufferAccess& errorMask,
|
|
const tcu::Texture2DArrayView& src,
|
|
const float* texCoord,
|
|
const ReferenceParams& sampleParams,
|
|
const tcu::TexComparePrecision& comparePrec,
|
|
const tcu::LodPrecision& lodPrec,
|
|
const tcu::Vec3& nonShadowThreshold)
|
|
{
|
|
DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
|
|
DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
|
|
|
|
const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
|
|
const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
|
|
const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
|
|
|
|
const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
|
|
const float dstW = float(dstSize.x());
|
|
const float dstH = float(dstSize.y());
|
|
const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
|
|
|
|
// Coordinates and lod per triangle.
|
|
const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
|
|
const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
|
|
|
|
const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
|
|
|
|
int numFailed = 0;
|
|
|
|
const tcu::Vec2 lodOffsets[] =
|
|
{
|
|
tcu::Vec2(-1, 0),
|
|
tcu::Vec2(+1, 0),
|
|
tcu::Vec2( 0, -1),
|
|
tcu::Vec2( 0, +1),
|
|
};
|
|
|
|
tcu::clear(errorMask, tcu::RGBA::green().toVec());
|
|
|
|
for (int py = 0; py < result.getHeight(); py++)
|
|
{
|
|
for (int px = 0; px < result.getWidth(); px++)
|
|
{
|
|
const tcu::Vec4 resPix = result.getPixel(px, py);
|
|
const tcu::Vec4 refPix = reference.getPixel(px, py);
|
|
|
|
// Other channels should trivially match to reference.
|
|
if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
continue;
|
|
}
|
|
|
|
// Reference result is known to be a valid result, we can
|
|
// skip verification if thes results are equal
|
|
if (resPix.x() != refPix.x())
|
|
{
|
|
const float wx = (float)px + 0.5f;
|
|
const float wy = (float)py + 0.5f;
|
|
const float nx = wx / dstW;
|
|
const float ny = wy / dstH;
|
|
|
|
const int triNdx = nx + ny >= 1.0f ? 1 : 0;
|
|
const float triWx = triNdx ? dstW - wx : wx;
|
|
const float triWy = triNdx ? dstH - wy : wy;
|
|
const float triNx = triNdx ? 1.0f - nx : nx;
|
|
const float triNy = triNdx ? 1.0f - ny : ny;
|
|
|
|
const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
|
|
projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
|
|
const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
|
|
const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
|
|
|
|
tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
|
|
|
|
// Compute lod bounds across lodOffsets range.
|
|
for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
|
|
{
|
|
const float wxo = triWx + lodOffsets[lodOffsNdx].x();
|
|
const float wyo = triWy + lodOffsets[lodOffsNdx].y();
|
|
const float nxo = wxo/dstW;
|
|
const float nyo = wyo/dstH;
|
|
|
|
const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
|
|
triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
|
|
const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
|
|
triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
|
|
const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
|
|
|
|
lodBounds.x() = de::min(lodBounds.x(), lodO.x());
|
|
lodBounds.y() = de::max(lodBounds.y(), lodO.y());
|
|
}
|
|
|
|
const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
|
|
const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
|
|
|
|
if (!isOk)
|
|
{
|
|
errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
|
|
numFailed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
// Mipmap generation comparison.
|
|
|
|
static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
|
|
{
|
|
DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
|
|
|
|
const float dstW = float(dst.getWidth());
|
|
const float dstH = float(dst.getHeight());
|
|
const float srcW = float(src.getWidth());
|
|
const float srcH = float(src.getHeight());
|
|
int numFailed = 0;
|
|
|
|
// Translation to lookup verification parameters.
|
|
const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
|
|
tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
|
|
tcu::LookupPrecision lookupPrec;
|
|
|
|
lookupPrec.colorThreshold = precision.colorThreshold;
|
|
lookupPrec.colorMask = precision.colorMask;
|
|
lookupPrec.coordBits = tcu::IVec3(22);
|
|
lookupPrec.uvwBits = precision.filterBits;
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
const tcu::Vec4 result = dst.getPixel(x, y);
|
|
const float cx = (float(x)+0.5f) / dstW * srcW;
|
|
const float cy = (float(y)+0.5f) / dstH * srcH;
|
|
const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
|
|
|
|
errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
|
|
if (!isOk)
|
|
numFailed += 1;
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
|
|
{
|
|
DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
|
|
|
|
const float dstW = float(dst.getWidth());
|
|
const float dstH = float(dst.getHeight());
|
|
const float srcW = float(src.getWidth());
|
|
const float srcH = float(src.getHeight());
|
|
int numFailed = 0;
|
|
|
|
// Translation to lookup verification parameters.
|
|
const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
|
|
tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
|
|
tcu::LookupPrecision lookupPrec;
|
|
|
|
lookupPrec.colorThreshold = precision.colorThreshold;
|
|
lookupPrec.colorMask = precision.colorMask;
|
|
lookupPrec.coordBits = tcu::IVec3(22);
|
|
lookupPrec.uvwBits = precision.filterBits;
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
const tcu::Vec4 result = dst.getPixel(x, y);
|
|
const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
|
|
const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
|
|
const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
|
|
|
|
errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
|
|
if (!isOk)
|
|
numFailed += 1;
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
|
|
{
|
|
DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
|
|
DE_UNREF(precision);
|
|
|
|
const float dstW = float(dst.getWidth());
|
|
const float dstH = float(dst.getHeight());
|
|
const float srcW = float(src.getWidth());
|
|
const float srcH = float(src.getHeight());
|
|
int numFailed = 0;
|
|
|
|
for (int y = 0; y < dst.getHeight(); y++)
|
|
for (int x = 0; x < dst.getWidth(); x++)
|
|
{
|
|
const tcu::Vec4 result = dst.getPixel(x, y);
|
|
const int minX = deFloorFloatToInt32(((float)x-0.5f) / dstW * srcW);
|
|
const int minY = deFloorFloatToInt32(((float)y-0.5f) / dstH * srcH);
|
|
const int maxX = deCeilFloatToInt32(((float)x+1.5f) / dstW * srcW);
|
|
const int maxY = deCeilFloatToInt32(((float)y+1.5f) / dstH * srcH);
|
|
tcu::Vec4 minVal, maxVal;
|
|
bool isOk;
|
|
|
|
DE_ASSERT(minX < maxX && minY < maxY);
|
|
|
|
for (int ky = minY; ky <= maxY; ky++)
|
|
{
|
|
for (int kx = minX; kx <= maxX; kx++)
|
|
{
|
|
const int sx = de::clamp(kx, 0, src.getWidth()-1);
|
|
const int sy = de::clamp(ky, 0, src.getHeight()-1);
|
|
const tcu::Vec4 sample = src.getPixel(sx, sy);
|
|
|
|
if (ky == minY && kx == minX)
|
|
{
|
|
minVal = sample;
|
|
maxVal = sample;
|
|
}
|
|
else
|
|
{
|
|
minVal = min(sample, minVal);
|
|
maxVal = max(sample, maxVal);
|
|
}
|
|
}
|
|
}
|
|
|
|
isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
|
|
|
|
errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
|
|
if (!isOk)
|
|
numFailed += 1;
|
|
}
|
|
|
|
return numFailed;
|
|
}
|
|
|
|
qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
|
|
{
|
|
qpTestResult result = QP_TEST_RESULT_PASS;
|
|
|
|
// Special comparison for level 0.
|
|
{
|
|
const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
|
|
const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
|
|
|
|
if (!level0Ok)
|
|
{
|
|
log << tcu::TestLog::Message << "ERROR: Level 0 comparison failed!" << tcu::TestLog::EndMessage;
|
|
result = QP_TEST_RESULT_FAIL;
|
|
}
|
|
}
|
|
|
|
for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
|
|
{
|
|
const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx-1);
|
|
const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx);
|
|
tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
|
|
bool levelOk = false;
|
|
|
|
// Try different comparisons in quality order.
|
|
|
|
if (!levelOk)
|
|
{
|
|
const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
|
|
if (numFailed == 0)
|
|
levelOk = true;
|
|
else
|
|
log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
if (!levelOk)
|
|
{
|
|
const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
|
|
if (numFailed == 0)
|
|
levelOk = true;
|
|
else
|
|
log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
// At this point all high-quality methods have been used.
|
|
if (!levelOk && result == QP_TEST_RESULT_PASS)
|
|
result = QP_TEST_RESULT_QUALITY_WARNING;
|
|
|
|
if (!levelOk)
|
|
{
|
|
const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
|
|
if (numFailed == 0)
|
|
levelOk = true;
|
|
else
|
|
log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
if (!levelOk)
|
|
result = QP_TEST_RESULT_FAIL;
|
|
|
|
log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
|
|
<< tcu::TestLog::Image("Result", "Result", dst);
|
|
|
|
if (!levelOk)
|
|
log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
|
|
{
|
|
qpTestResult result = QP_TEST_RESULT_PASS;
|
|
|
|
static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
|
|
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
|
|
|
|
// Special comparison for level 0.
|
|
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
|
|
{
|
|
const tcu::CubeFace face = tcu::CubeFace(faceNdx);
|
|
const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
|
|
const bool level0Ok = tcu::floatThresholdCompare(log,
|
|
("Level0Face" + de::toString(faceNdx)).c_str(),
|
|
(string("Level 0, face ") + s_faceNames[face]).c_str(),
|
|
level0Reference.getLevelFace(0, face),
|
|
resultTexture.getLevelFace(0, face),
|
|
threshold, tcu::COMPARE_LOG_RESULT);
|
|
|
|
if (!level0Ok)
|
|
{
|
|
log << tcu::TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << tcu::TestLog::EndMessage;
|
|
result = QP_TEST_RESULT_FAIL;
|
|
}
|
|
}
|
|
|
|
for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
|
|
{
|
|
for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
|
|
{
|
|
const tcu::CubeFace face = tcu::CubeFace(faceNdx);
|
|
const char* faceName = s_faceNames[face];
|
|
const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx-1, face);
|
|
const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face);
|
|
tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
|
|
bool levelOk = false;
|
|
|
|
// Try different comparisons in quality order.
|
|
|
|
if (!levelOk)
|
|
{
|
|
const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
|
|
if (numFailed == 0)
|
|
levelOk = true;
|
|
else
|
|
log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
if (!levelOk)
|
|
{
|
|
const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
|
|
if (numFailed == 0)
|
|
levelOk = true;
|
|
else
|
|
log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
// At this point all high-quality methods have been used.
|
|
if (!levelOk && result == QP_TEST_RESULT_PASS)
|
|
result = QP_TEST_RESULT_QUALITY_WARNING;
|
|
|
|
if (!levelOk)
|
|
{
|
|
const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
|
|
if (numFailed == 0)
|
|
levelOk = true;
|
|
else
|
|
log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
if (!levelOk)
|
|
result = QP_TEST_RESULT_FAIL;
|
|
|
|
log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
|
|
<< tcu::TestLog::Image("Result", "Result", dst);
|
|
|
|
if (!levelOk)
|
|
log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
|
|
|
|
log << tcu::TestLog::EndImageSet;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Logging utilities.
|
|
|
|
std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
|
|
{
|
|
return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
|
|
<< "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
|
|
<< "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
|
|
<< "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
|
|
}
|
|
|
|
} // TextureTestUtil
|
|
} // glu
|