| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Tester Core |
| * ---------------------------------------- |
| * |
| * 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 Internal utilities shared between TexLookup and TexCompare verifiers. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "tcuTexVerifierUtil.hpp" |
| #include "tcuFloat.hpp" |
| |
| namespace tcu |
| { |
| namespace TexVerifierUtil |
| { |
| |
| float computeFloatingPointError (const float value, const int numAccurateBits) |
| { |
| const int numGarbageBits = 23-numAccurateBits; |
| const deUint32 mask = (1u<<numGarbageBits)-1u; |
| const int exp = tcu::Float32(value).exponent(); |
| |
| return Float32::construct(+1, exp, (1u<<23) | mask).asFloat() - Float32::construct(+1, exp, 1u<<23).asFloat(); |
| } |
| |
| float computeFixedPointError (const int numAccurateBits) |
| { |
| return computeFloatingPointError(1.0f, numAccurateBits); |
| } |
| |
| float computeColorBitsError(const int bits, const int numAccurateBits) |
| { |
| // Color bits error is not a generic function, it just for compute the error value that cannot be accurately shown in integer data format. |
| // |
| // "bits" is color bit width, "numAccurateBits" is the number of accurate bits in color bits, "1 << (bits - numAccurateBits)" is the threshold in integer. |
| // "1.0f / 256.0f" is epsilon value, to make sure the threshold use to calculate in float can be a little bigger than the real value. |
| return (float(1 << (bits - numAccurateBits)) + 1.0f / 256.0f) / float((1 << bits) - 1); |
| } |
| |
| Vec2 computeNonNormalizedCoordBounds (const bool normalizedCoords, const int dim, const float coord, const int coordBits, const int uvBits) |
| { |
| const float coordErr = computeFloatingPointError(coord, coordBits); |
| const float minN = coord - coordErr; |
| const float maxN = coord + coordErr; |
| const float minA = normalizedCoords ? minN*float(dim) : minN; |
| const float maxA = normalizedCoords ? maxN*float(dim) : maxN; |
| const float minC = minA - computeFixedPointError(uvBits); |
| const float maxC = maxA + computeFixedPointError(uvBits); |
| |
| DE_ASSERT(minC <= maxC); |
| |
| return Vec2(minC, maxC); |
| } |
| |
| void getPossibleCubeFaces (const Vec3& coord, const IVec3& bits, CubeFace* faces, int& numFaces) |
| { |
| const float x = coord.x(); |
| const float y = coord.y(); |
| const float z = coord.z(); |
| const float ax = de::abs(x); |
| const float ay = de::abs(y); |
| const float az = de::abs(z); |
| const float ex = computeFloatingPointError(x, bits.x()); |
| const float ey = computeFloatingPointError(y, bits.y()); |
| const float ez = computeFloatingPointError(z, bits.z()); |
| |
| numFaces = 0; |
| |
| if (ay+ey < ax-ex && az+ez < ax-ex) |
| { |
| if (x >= ex) faces[numFaces++] = CUBEFACE_POSITIVE_X; |
| if (x <= ex) faces[numFaces++] = CUBEFACE_NEGATIVE_X; |
| } |
| else if (ax+ex < ay-ey && az+ez < ay-ey) |
| { |
| if (y >= ey) faces[numFaces++] = CUBEFACE_POSITIVE_Y; |
| if (y <= ey) faces[numFaces++] = CUBEFACE_NEGATIVE_Y; |
| } |
| else if (ax+ex < az-ez && ay+ey < az-ez) |
| { |
| if (z >= ez) faces[numFaces++] = CUBEFACE_POSITIVE_Z; |
| if (z <= ez) faces[numFaces++] = CUBEFACE_NEGATIVE_Z; |
| } |
| else |
| { |
| // One or more components are equal (or within error bounds). Allow all faces where major axis is not zero. |
| if (ax > ex) |
| { |
| faces[numFaces++] = CUBEFACE_NEGATIVE_X; |
| faces[numFaces++] = CUBEFACE_POSITIVE_X; |
| } |
| |
| if (ay > ey) |
| { |
| faces[numFaces++] = CUBEFACE_NEGATIVE_Y; |
| faces[numFaces++] = CUBEFACE_POSITIVE_Y; |
| } |
| |
| if (az > ez) |
| { |
| faces[numFaces++] = CUBEFACE_NEGATIVE_Z; |
| faces[numFaces++] = CUBEFACE_POSITIVE_Z; |
| } |
| } |
| } |
| |
| Sampler getUnnormalizedCoordSampler (const Sampler& sampler) |
| { |
| Sampler copy = sampler; |
| copy.normalizedCoords = false; |
| return copy; |
| } |
| |
| static inline int imod (int a, int b) |
| { |
| int m = a % b; |
| return m < 0 ? m + b : m; |
| } |
| |
| static inline int mirror (int a) |
| { |
| return a >= 0 ? a : -(1 + a); |
| } |
| |
| int wrap (Sampler::WrapMode mode, int c, int size) |
| { |
| switch (mode) |
| { |
| // \note CL and GL modes are handled identically here, as verification process accounts for |
| // accuracy differences caused by different methods (wrapping vs. denormalizing first). |
| case tcu::Sampler::CLAMP_TO_BORDER: |
| return deClamp32(c, -1, size); |
| |
| case tcu::Sampler::CLAMP_TO_EDGE: |
| return deClamp32(c, 0, size-1); |
| |
| case tcu::Sampler::REPEAT_GL: |
| case tcu::Sampler::REPEAT_CL: |
| return imod(c, size); |
| |
| case tcu::Sampler::MIRRORED_ONCE: |
| c = deClamp32(c, -size, size); |
| // Fall-through |
| |
| case tcu::Sampler::MIRRORED_REPEAT_GL: |
| case tcu::Sampler::MIRRORED_REPEAT_CL: |
| return (size - 1) - mirror(imod(c, 2*size) - size); |
| |
| default: |
| DE_ASSERT(DE_FALSE); |
| return 0; |
| } |
| } |
| } // TexVerifierUtil |
| } // tcu |