xref: /aosp_15_r20/external/deqp/framework/common/tcuTexLookupVerifier.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker  * drawElements Quality Program Tester Core
3*35238bceSAndroid Build Coastguard Worker  * ----------------------------------------
4*35238bceSAndroid Build Coastguard Worker  *
5*35238bceSAndroid Build Coastguard Worker  * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker  *
7*35238bceSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker  *
11*35238bceSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker  *
13*35238bceSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker  * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker  *
19*35238bceSAndroid Build Coastguard Worker  *//*!
20*35238bceSAndroid Build Coastguard Worker  * \file
21*35238bceSAndroid Build Coastguard Worker  * \brief Texture lookup simulator that is capable of verifying generic
22*35238bceSAndroid Build Coastguard Worker  *          lookup results based on accuracy parameters.
23*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
24*35238bceSAndroid Build Coastguard Worker 
25*35238bceSAndroid Build Coastguard Worker #include "tcuTexLookupVerifier.hpp"
26*35238bceSAndroid Build Coastguard Worker #include "tcuTexVerifierUtil.hpp"
27*35238bceSAndroid Build Coastguard Worker #include "tcuVectorUtil.hpp"
28*35238bceSAndroid Build Coastguard Worker #include "tcuTextureUtil.hpp"
29*35238bceSAndroid Build Coastguard Worker #include "deMath.h"
30*35238bceSAndroid Build Coastguard Worker 
31*35238bceSAndroid Build Coastguard Worker namespace tcu
32*35238bceSAndroid Build Coastguard Worker {
33*35238bceSAndroid Build Coastguard Worker 
34*35238bceSAndroid Build Coastguard Worker using namespace TexVerifierUtil;
35*35238bceSAndroid Build Coastguard Worker 
36*35238bceSAndroid Build Coastguard Worker // Generic utilities
37*35238bceSAndroid Build Coastguard Worker 
38*35238bceSAndroid Build Coastguard Worker #if defined(DE_DEBUG)
isSamplerSupported(const Sampler & sampler)39*35238bceSAndroid Build Coastguard Worker static bool isSamplerSupported(const Sampler &sampler)
40*35238bceSAndroid Build Coastguard Worker {
41*35238bceSAndroid Build Coastguard Worker     return sampler.compare == Sampler::COMPAREMODE_NONE && isWrapModeSupported(sampler.wrapS) &&
42*35238bceSAndroid Build Coastguard Worker            isWrapModeSupported(sampler.wrapT) && isWrapModeSupported(sampler.wrapR);
43*35238bceSAndroid Build Coastguard Worker }
44*35238bceSAndroid Build Coastguard Worker #endif // DE_DEBUG
45*35238bceSAndroid Build Coastguard Worker 
46*35238bceSAndroid Build Coastguard Worker // Color read & compare utilities
47*35238bceSAndroid Build Coastguard Worker 
coordsInBounds(const ConstPixelBufferAccess & access,int x,int y,int z)48*35238bceSAndroid Build Coastguard Worker static inline bool coordsInBounds(const ConstPixelBufferAccess &access, int x, int y, int z)
49*35238bceSAndroid Build Coastguard Worker {
50*35238bceSAndroid Build Coastguard Worker     return de::inBounds(x, 0, access.getWidth()) && de::inBounds(y, 0, access.getHeight()) &&
51*35238bceSAndroid Build Coastguard Worker            de::inBounds(z, 0, access.getDepth());
52*35238bceSAndroid Build Coastguard Worker }
53*35238bceSAndroid Build Coastguard Worker 
54*35238bceSAndroid Build Coastguard Worker template <typename ScalarType>
lookup(const ConstPixelBufferAccess & access,const Sampler & sampler,int i,int j,int k)55*35238bceSAndroid Build Coastguard Worker inline Vector<ScalarType, 4> lookup(const ConstPixelBufferAccess &access, const Sampler &sampler, int i, int j, int k)
56*35238bceSAndroid Build Coastguard Worker {
57*35238bceSAndroid Build Coastguard Worker     if (coordsInBounds(access, i, j, k))
58*35238bceSAndroid Build Coastguard Worker         return access.getPixelT<ScalarType>(i, j, k);
59*35238bceSAndroid Build Coastguard Worker     else
60*35238bceSAndroid Build Coastguard Worker         return sampleTextureBorder<ScalarType>(access.getFormat(), sampler);
61*35238bceSAndroid Build Coastguard Worker }
62*35238bceSAndroid Build Coastguard Worker 
63*35238bceSAndroid Build Coastguard Worker template <>
lookup(const ConstPixelBufferAccess & access,const Sampler & sampler,int i,int j,int k)64*35238bceSAndroid Build Coastguard Worker inline Vector<float, 4> lookup(const ConstPixelBufferAccess &access, const Sampler &sampler, int i, int j, int k)
65*35238bceSAndroid Build Coastguard Worker {
66*35238bceSAndroid Build Coastguard Worker     // Specialization for float lookups: sRGB conversion is performed as specified in format.
67*35238bceSAndroid Build Coastguard Worker     if (coordsInBounds(access, i, j, k))
68*35238bceSAndroid Build Coastguard Worker     {
69*35238bceSAndroid Build Coastguard Worker         const Vec4 p = access.getPixel(i, j, k);
70*35238bceSAndroid Build Coastguard Worker         return isSRGB(access.getFormat()) ? sRGBToLinear(p) : p;
71*35238bceSAndroid Build Coastguard Worker     }
72*35238bceSAndroid Build Coastguard Worker     else
73*35238bceSAndroid Build Coastguard Worker         return sampleTextureBorder<float>(access.getFormat(), sampler);
74*35238bceSAndroid Build Coastguard Worker }
75*35238bceSAndroid Build Coastguard Worker 
isColorValid(const LookupPrecision & prec,const Vec4 & ref,const Vec4 & result)76*35238bceSAndroid Build Coastguard Worker static inline bool isColorValid(const LookupPrecision &prec, const Vec4 &ref, const Vec4 &result)
77*35238bceSAndroid Build Coastguard Worker {
78*35238bceSAndroid Build Coastguard Worker     const Vec4 diff = abs(ref - result);
79*35238bceSAndroid Build Coastguard Worker     return boolAll(logicalOr(lessThanEqual(diff, prec.colorThreshold), logicalNot(prec.colorMask)));
80*35238bceSAndroid Build Coastguard Worker }
81*35238bceSAndroid Build Coastguard Worker 
isColorValid(const IntLookupPrecision & prec,const IVec4 & ref,const IVec4 & result)82*35238bceSAndroid Build Coastguard Worker static inline bool isColorValid(const IntLookupPrecision &prec, const IVec4 &ref, const IVec4 &result)
83*35238bceSAndroid Build Coastguard Worker {
84*35238bceSAndroid Build Coastguard Worker     return boolAll(
85*35238bceSAndroid Build Coastguard Worker         logicalOr(lessThanEqual(absDiff(ref, result).asUint(), prec.colorThreshold), logicalNot(prec.colorMask)));
86*35238bceSAndroid Build Coastguard Worker }
87*35238bceSAndroid Build Coastguard Worker 
isColorValid(const IntLookupPrecision & prec,const UVec4 & ref,const UVec4 & result)88*35238bceSAndroid Build Coastguard Worker static inline bool isColorValid(const IntLookupPrecision &prec, const UVec4 &ref, const UVec4 &result)
89*35238bceSAndroid Build Coastguard Worker {
90*35238bceSAndroid Build Coastguard Worker     return boolAll(logicalOr(lessThanEqual(absDiff(ref, result), prec.colorThreshold), logicalNot(prec.colorMask)));
91*35238bceSAndroid Build Coastguard Worker }
92*35238bceSAndroid Build Coastguard Worker 
93*35238bceSAndroid Build Coastguard Worker struct ColorQuad
94*35238bceSAndroid Build Coastguard Worker {
95*35238bceSAndroid Build Coastguard Worker     Vec4 p00; //!< (0, 0)
96*35238bceSAndroid Build Coastguard Worker     Vec4 p01; //!< (1, 0)
97*35238bceSAndroid Build Coastguard Worker     Vec4 p10; //!< (0, 1)
98*35238bceSAndroid Build Coastguard Worker     Vec4 p11; //!< (1, 1)
99*35238bceSAndroid Build Coastguard Worker };
100*35238bceSAndroid Build Coastguard Worker 
lookupQuad(ColorQuad & dst,const ConstPixelBufferAccess & level,const Sampler & sampler,int x0,int x1,int y0,int y1,int z)101*35238bceSAndroid Build Coastguard Worker static void lookupQuad(ColorQuad &dst, const ConstPixelBufferAccess &level, const Sampler &sampler, int x0, int x1,
102*35238bceSAndroid Build Coastguard Worker                        int y0, int y1, int z)
103*35238bceSAndroid Build Coastguard Worker {
104*35238bceSAndroid Build Coastguard Worker     dst.p00 = lookup<float>(level, sampler, x0, y0, z);
105*35238bceSAndroid Build Coastguard Worker     dst.p10 = lookup<float>(level, sampler, x1, y0, z);
106*35238bceSAndroid Build Coastguard Worker     dst.p01 = lookup<float>(level, sampler, x0, y1, z);
107*35238bceSAndroid Build Coastguard Worker     dst.p11 = lookup<float>(level, sampler, x1, y1, z);
108*35238bceSAndroid Build Coastguard Worker }
109*35238bceSAndroid Build Coastguard Worker 
110*35238bceSAndroid Build Coastguard Worker struct ColorLine
111*35238bceSAndroid Build Coastguard Worker {
112*35238bceSAndroid Build Coastguard Worker     Vec4 p0; //!< 0
113*35238bceSAndroid Build Coastguard Worker     Vec4 p1; //!< 1
114*35238bceSAndroid Build Coastguard Worker };
115*35238bceSAndroid Build Coastguard Worker 
lookupLine(ColorLine & dst,const ConstPixelBufferAccess & level,const Sampler & sampler,int x0,int x1,int y)116*35238bceSAndroid Build Coastguard Worker static void lookupLine(ColorLine &dst, const ConstPixelBufferAccess &level, const Sampler &sampler, int x0, int x1,
117*35238bceSAndroid Build Coastguard Worker                        int y)
118*35238bceSAndroid Build Coastguard Worker {
119*35238bceSAndroid Build Coastguard Worker     dst.p0 = lookup<float>(level, sampler, x0, y, 0);
120*35238bceSAndroid Build Coastguard Worker     dst.p1 = lookup<float>(level, sampler, x1, y, 0);
121*35238bceSAndroid Build Coastguard Worker }
122*35238bceSAndroid Build Coastguard Worker 
123*35238bceSAndroid Build Coastguard Worker template <typename T, int Size>
minComp(const Vector<T,Size> & vec)124*35238bceSAndroid Build Coastguard Worker static T minComp(const Vector<T, Size> &vec)
125*35238bceSAndroid Build Coastguard Worker {
126*35238bceSAndroid Build Coastguard Worker     T minVal = vec[0];
127*35238bceSAndroid Build Coastguard Worker     for (int ndx = 1; ndx < Size; ndx++)
128*35238bceSAndroid Build Coastguard Worker         minVal = de::min(minVal, vec[ndx]);
129*35238bceSAndroid Build Coastguard Worker     return minVal;
130*35238bceSAndroid Build Coastguard Worker }
131*35238bceSAndroid Build Coastguard Worker 
132*35238bceSAndroid Build Coastguard Worker template <typename T, int Size>
maxComp(const Vector<T,Size> & vec)133*35238bceSAndroid Build Coastguard Worker static T maxComp(const Vector<T, Size> &vec)
134*35238bceSAndroid Build Coastguard Worker {
135*35238bceSAndroid Build Coastguard Worker     T maxVal = vec[0];
136*35238bceSAndroid Build Coastguard Worker     for (int ndx = 1; ndx < Size; ndx++)
137*35238bceSAndroid Build Coastguard Worker         maxVal = de::max(maxVal, vec[ndx]);
138*35238bceSAndroid Build Coastguard Worker     return maxVal;
139*35238bceSAndroid Build Coastguard Worker }
140*35238bceSAndroid Build Coastguard Worker 
computeBilinearSearchStepFromFloatLine(const LookupPrecision & prec,const ColorLine & line)141*35238bceSAndroid Build Coastguard Worker static float computeBilinearSearchStepFromFloatLine(const LookupPrecision &prec, const ColorLine &line)
142*35238bceSAndroid Build Coastguard Worker {
143*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(boolAll(greaterThan(prec.colorThreshold, Vec4(0.0f))));
144*35238bceSAndroid Build Coastguard Worker 
145*35238bceSAndroid Build Coastguard Worker     const int maxSteps   = 1 << 16;
146*35238bceSAndroid Build Coastguard Worker     const Vec4 d         = abs(line.p1 - line.p0);
147*35238bceSAndroid Build Coastguard Worker     const Vec4 stepCount = d / prec.colorThreshold;
148*35238bceSAndroid Build Coastguard Worker     const Vec4 minStep   = 1.0f / (stepCount + 1.0f);
149*35238bceSAndroid Build Coastguard Worker     const float step     = de::max(minComp(minStep), 1.0f / float(maxSteps));
150*35238bceSAndroid Build Coastguard Worker 
151*35238bceSAndroid Build Coastguard Worker     return step;
152*35238bceSAndroid Build Coastguard Worker }
153*35238bceSAndroid Build Coastguard Worker 
computeBilinearSearchStepFromFloatQuad(const LookupPrecision & prec,const ColorQuad & quad)154*35238bceSAndroid Build Coastguard Worker static float computeBilinearSearchStepFromFloatQuad(const LookupPrecision &prec, const ColorQuad &quad)
155*35238bceSAndroid Build Coastguard Worker {
156*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(boolAll(greaterThan(prec.colorThreshold, Vec4(0.0f))));
157*35238bceSAndroid Build Coastguard Worker 
158*35238bceSAndroid Build Coastguard Worker     const int maxSteps   = 1 << 16;
159*35238bceSAndroid Build Coastguard Worker     const Vec4 d0        = abs(quad.p10 - quad.p00);
160*35238bceSAndroid Build Coastguard Worker     const Vec4 d1        = abs(quad.p01 - quad.p00);
161*35238bceSAndroid Build Coastguard Worker     const Vec4 d2        = abs(quad.p11 - quad.p10);
162*35238bceSAndroid Build Coastguard Worker     const Vec4 d3        = abs(quad.p11 - quad.p01);
163*35238bceSAndroid Build Coastguard Worker     const Vec4 maxD      = max(d0, max(d1, max(d2, d3)));
164*35238bceSAndroid Build Coastguard Worker     const Vec4 stepCount = maxD / prec.colorThreshold;
165*35238bceSAndroid Build Coastguard Worker     const Vec4 minStep   = 1.0f / (stepCount + 1.0f);
166*35238bceSAndroid Build Coastguard Worker     const float step     = de::max(minComp(minStep), 1.0f / float(maxSteps));
167*35238bceSAndroid Build Coastguard Worker 
168*35238bceSAndroid Build Coastguard Worker     return step;
169*35238bceSAndroid Build Coastguard Worker }
170*35238bceSAndroid Build Coastguard Worker 
computeBilinearSearchStepForUnorm(const LookupPrecision & prec)171*35238bceSAndroid Build Coastguard Worker static float computeBilinearSearchStepForUnorm(const LookupPrecision &prec)
172*35238bceSAndroid Build Coastguard Worker {
173*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(boolAll(greaterThan(prec.colorThreshold, Vec4(0.0f))));
174*35238bceSAndroid Build Coastguard Worker 
175*35238bceSAndroid Build Coastguard Worker     const Vec4 stepCount = 1.0f / prec.colorThreshold;
176*35238bceSAndroid Build Coastguard Worker     const Vec4 minStep   = 1.0f / (stepCount + 1.0f);
177*35238bceSAndroid Build Coastguard Worker     const float step     = minComp(minStep);
178*35238bceSAndroid Build Coastguard Worker 
179*35238bceSAndroid Build Coastguard Worker     return step;
180*35238bceSAndroid Build Coastguard Worker }
181*35238bceSAndroid Build Coastguard Worker 
computeBilinearSearchStepForSnorm(const LookupPrecision & prec)182*35238bceSAndroid Build Coastguard Worker static float computeBilinearSearchStepForSnorm(const LookupPrecision &prec)
183*35238bceSAndroid Build Coastguard Worker {
184*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(boolAll(greaterThan(prec.colorThreshold, Vec4(0.0f))));
185*35238bceSAndroid Build Coastguard Worker 
186*35238bceSAndroid Build Coastguard Worker     const Vec4 stepCount = 2.0f / prec.colorThreshold;
187*35238bceSAndroid Build Coastguard Worker     const Vec4 minStep   = 1.0f / (stepCount + 1.0f);
188*35238bceSAndroid Build Coastguard Worker     const float step     = minComp(minStep);
189*35238bceSAndroid Build Coastguard Worker 
190*35238bceSAndroid Build Coastguard Worker     return step;
191*35238bceSAndroid Build Coastguard Worker }
192*35238bceSAndroid Build Coastguard Worker 
min(const ColorLine & line)193*35238bceSAndroid Build Coastguard Worker static inline Vec4 min(const ColorLine &line)
194*35238bceSAndroid Build Coastguard Worker {
195*35238bceSAndroid Build Coastguard Worker     return min(line.p0, line.p1);
196*35238bceSAndroid Build Coastguard Worker }
197*35238bceSAndroid Build Coastguard Worker 
max(const ColorLine & line)198*35238bceSAndroid Build Coastguard Worker static inline Vec4 max(const ColorLine &line)
199*35238bceSAndroid Build Coastguard Worker {
200*35238bceSAndroid Build Coastguard Worker     return max(line.p0, line.p1);
201*35238bceSAndroid Build Coastguard Worker }
202*35238bceSAndroid Build Coastguard Worker 
min(const ColorQuad & quad)203*35238bceSAndroid Build Coastguard Worker static inline Vec4 min(const ColorQuad &quad)
204*35238bceSAndroid Build Coastguard Worker {
205*35238bceSAndroid Build Coastguard Worker     return min(quad.p00, min(quad.p10, min(quad.p01, quad.p11)));
206*35238bceSAndroid Build Coastguard Worker }
207*35238bceSAndroid Build Coastguard Worker 
max(const ColorQuad & quad)208*35238bceSAndroid Build Coastguard Worker static inline Vec4 max(const ColorQuad &quad)
209*35238bceSAndroid Build Coastguard Worker {
210*35238bceSAndroid Build Coastguard Worker     return max(quad.p00, max(quad.p10, max(quad.p01, quad.p11)));
211*35238bceSAndroid Build Coastguard Worker }
212*35238bceSAndroid Build Coastguard Worker 
isInColorBounds(const LookupPrecision & prec,const ColorQuad & quad,const Vec4 & result)213*35238bceSAndroid Build Coastguard Worker static bool isInColorBounds(const LookupPrecision &prec, const ColorQuad &quad, const Vec4 &result)
214*35238bceSAndroid Build Coastguard Worker {
215*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 minVal = min(quad) - prec.colorThreshold;
216*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 maxVal = max(quad) + prec.colorThreshold;
217*35238bceSAndroid Build Coastguard Worker     return boolAll(logicalOr(logicalAnd(greaterThanEqual(result, minVal), lessThanEqual(result, maxVal)),
218*35238bceSAndroid Build Coastguard Worker                              logicalNot(prec.colorMask)));
219*35238bceSAndroid Build Coastguard Worker }
220*35238bceSAndroid Build Coastguard Worker 
isInColorBounds(const LookupPrecision & prec,const ColorQuad & quad0,const ColorQuad & quad1,const Vec4 & result)221*35238bceSAndroid Build Coastguard Worker static bool isInColorBounds(const LookupPrecision &prec, const ColorQuad &quad0, const ColorQuad &quad1,
222*35238bceSAndroid Build Coastguard Worker                             const Vec4 &result)
223*35238bceSAndroid Build Coastguard Worker {
224*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 minVal = min(min(quad0), min(quad1)) - prec.colorThreshold;
225*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 maxVal = max(max(quad0), max(quad1)) + prec.colorThreshold;
226*35238bceSAndroid Build Coastguard Worker     return boolAll(logicalOr(logicalAnd(greaterThanEqual(result, minVal), lessThanEqual(result, maxVal)),
227*35238bceSAndroid Build Coastguard Worker                              logicalNot(prec.colorMask)));
228*35238bceSAndroid Build Coastguard Worker }
229*35238bceSAndroid Build Coastguard Worker 
isInColorBounds(const LookupPrecision & prec,const ColorLine & line0,const ColorLine & line1,const Vec4 & result)230*35238bceSAndroid Build Coastguard Worker static bool isInColorBounds(const LookupPrecision &prec, const ColorLine &line0, const ColorLine &line1,
231*35238bceSAndroid Build Coastguard Worker                             const Vec4 &result)
232*35238bceSAndroid Build Coastguard Worker {
233*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 minVal = min(min(line0), min(line1)) - prec.colorThreshold;
234*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 maxVal = max(max(line0), max(line1)) + prec.colorThreshold;
235*35238bceSAndroid Build Coastguard Worker     return boolAll(logicalOr(logicalAnd(greaterThanEqual(result, minVal), lessThanEqual(result, maxVal)),
236*35238bceSAndroid Build Coastguard Worker                              logicalNot(prec.colorMask)));
237*35238bceSAndroid Build Coastguard Worker }
238*35238bceSAndroid Build Coastguard Worker 
isInColorBounds(const LookupPrecision & prec,const ColorQuad & quad00,const ColorQuad & quad01,const ColorQuad & quad10,const ColorQuad & quad11,const Vec4 & result)239*35238bceSAndroid Build Coastguard Worker static bool isInColorBounds(const LookupPrecision &prec, const ColorQuad &quad00, const ColorQuad &quad01,
240*35238bceSAndroid Build Coastguard Worker                             const ColorQuad &quad10, const ColorQuad &quad11, const Vec4 &result)
241*35238bceSAndroid Build Coastguard Worker {
242*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 minVal = min(min(quad00), min(min(quad01), min(min(quad10), min(quad11)))) - prec.colorThreshold;
243*35238bceSAndroid Build Coastguard Worker     const tcu::Vec4 maxVal = max(max(quad00), max(max(quad01), max(max(quad10), max(quad11)))) + prec.colorThreshold;
244*35238bceSAndroid Build Coastguard Worker     return boolAll(logicalOr(logicalAnd(greaterThanEqual(result, minVal), lessThanEqual(result, maxVal)),
245*35238bceSAndroid Build Coastguard Worker                              logicalNot(prec.colorMask)));
246*35238bceSAndroid Build Coastguard Worker }
247*35238bceSAndroid Build Coastguard Worker 
248*35238bceSAndroid Build Coastguard Worker // Range search utilities
249*35238bceSAndroid Build Coastguard Worker 
isLinearRangeValid(const LookupPrecision & prec,const Vec4 & c0,const Vec4 & c1,const Vec2 & fBounds,const Vec4 & result)250*35238bceSAndroid Build Coastguard Worker static bool isLinearRangeValid(const LookupPrecision &prec, const Vec4 &c0, const Vec4 &c1, const Vec2 &fBounds,
251*35238bceSAndroid Build Coastguard Worker                                const Vec4 &result)
252*35238bceSAndroid Build Coastguard Worker {
253*35238bceSAndroid Build Coastguard Worker     // This is basically line segment - AABB test. Valid interpolation line is checked
254*35238bceSAndroid Build Coastguard Worker     // against result AABB constructed by applying threshold.
255*35238bceSAndroid Build Coastguard Worker 
256*35238bceSAndroid Build Coastguard Worker     const Vec4 i0     = c0 * (1.0f - fBounds[0]) + c1 * fBounds[0];
257*35238bceSAndroid Build Coastguard Worker     const Vec4 i1     = c0 * (1.0f - fBounds[1]) + c1 * fBounds[1];
258*35238bceSAndroid Build Coastguard Worker     const Vec4 rMin   = result - prec.colorThreshold;
259*35238bceSAndroid Build Coastguard Worker     const Vec4 rMax   = result + prec.colorThreshold;
260*35238bceSAndroid Build Coastguard Worker     bool allIntersect = true;
261*35238bceSAndroid Build Coastguard Worker 
262*35238bceSAndroid Build Coastguard Worker     // Algorithm: For each component check whether segment endpoints are inside, or intersect with slab.
263*35238bceSAndroid Build Coastguard Worker     // If all intersect or are inside, line segment intersects the whole 4D AABB.
264*35238bceSAndroid Build Coastguard Worker     for (int compNdx = 0; compNdx < 4; compNdx++)
265*35238bceSAndroid Build Coastguard Worker     {
266*35238bceSAndroid Build Coastguard Worker         if (!prec.colorMask[compNdx])
267*35238bceSAndroid Build Coastguard Worker             continue;
268*35238bceSAndroid Build Coastguard Worker 
269*35238bceSAndroid Build Coastguard Worker         // Signs for both bounds: false = left, true = right.
270*35238bceSAndroid Build Coastguard Worker         const bool sMin0 = i0[compNdx] >= rMin[compNdx];
271*35238bceSAndroid Build Coastguard Worker         const bool sMin1 = i1[compNdx] >= rMin[compNdx];
272*35238bceSAndroid Build Coastguard Worker         const bool sMax0 = i0[compNdx] > rMax[compNdx];
273*35238bceSAndroid Build Coastguard Worker         const bool sMax1 = i1[compNdx] > rMax[compNdx];
274*35238bceSAndroid Build Coastguard Worker 
275*35238bceSAndroid Build Coastguard Worker         // If all signs are equal, line segment is outside bounds.
276*35238bceSAndroid Build Coastguard Worker         if (sMin0 == sMin1 && sMin1 == sMax0 && sMax0 == sMax1)
277*35238bceSAndroid Build Coastguard Worker         {
278*35238bceSAndroid Build Coastguard Worker             allIntersect = false;
279*35238bceSAndroid Build Coastguard Worker             break;
280*35238bceSAndroid Build Coastguard Worker         }
281*35238bceSAndroid Build Coastguard Worker     }
282*35238bceSAndroid Build Coastguard Worker 
283*35238bceSAndroid Build Coastguard Worker     return allIntersect;
284*35238bceSAndroid Build Coastguard Worker }
285*35238bceSAndroid Build Coastguard Worker 
isBilinearRangeValid(const LookupPrecision & prec,const ColorQuad & quad,const Vec2 & xBounds,const Vec2 & yBounds,const float searchStep,const Vec4 & result)286*35238bceSAndroid Build Coastguard Worker static bool isBilinearRangeValid(const LookupPrecision &prec, const ColorQuad &quad, const Vec2 &xBounds,
287*35238bceSAndroid Build Coastguard Worker                                  const Vec2 &yBounds, const float searchStep, const Vec4 &result)
288*35238bceSAndroid Build Coastguard Worker {
289*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds.x() <= xBounds.y());
290*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds.x() <= yBounds.y());
291*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds.x() + searchStep > xBounds.x()); // step is not effectively 0
292*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds.y() + searchStep > xBounds.y());
293*35238bceSAndroid Build Coastguard Worker 
294*35238bceSAndroid Build Coastguard Worker     if (!isInColorBounds(prec, quad, result))
295*35238bceSAndroid Build Coastguard Worker         return false;
296*35238bceSAndroid Build Coastguard Worker 
297*35238bceSAndroid Build Coastguard Worker     for (float x = xBounds.x(); x < xBounds.y() + searchStep; x += searchStep)
298*35238bceSAndroid Build Coastguard Worker     {
299*35238bceSAndroid Build Coastguard Worker         const float a = de::min(x, xBounds.y());
300*35238bceSAndroid Build Coastguard Worker         const Vec4 c0 = quad.p00 * (1.0f - a) + quad.p10 * a;
301*35238bceSAndroid Build Coastguard Worker         const Vec4 c1 = quad.p01 * (1.0f - a) + quad.p11 * a;
302*35238bceSAndroid Build Coastguard Worker 
303*35238bceSAndroid Build Coastguard Worker         if (isLinearRangeValid(prec, c0, c1, yBounds, result))
304*35238bceSAndroid Build Coastguard Worker             return true;
305*35238bceSAndroid Build Coastguard Worker     }
306*35238bceSAndroid Build Coastguard Worker 
307*35238bceSAndroid Build Coastguard Worker     return false;
308*35238bceSAndroid Build Coastguard Worker }
309*35238bceSAndroid Build Coastguard Worker 
isTrilinearRangeValid(const LookupPrecision & prec,const ColorQuad & quad0,const ColorQuad & quad1,const Vec2 & xBounds,const Vec2 & yBounds,const Vec2 & zBounds,const float searchStep,const Vec4 & result)310*35238bceSAndroid Build Coastguard Worker static bool isTrilinearRangeValid(const LookupPrecision &prec, const ColorQuad &quad0, const ColorQuad &quad1,
311*35238bceSAndroid Build Coastguard Worker                                   const Vec2 &xBounds, const Vec2 &yBounds, const Vec2 &zBounds, const float searchStep,
312*35238bceSAndroid Build Coastguard Worker                                   const Vec4 &result)
313*35238bceSAndroid Build Coastguard Worker {
314*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds.x() <= xBounds.y());
315*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds.x() <= yBounds.y());
316*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(zBounds.x() <= zBounds.y());
317*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds.x() + searchStep > xBounds.x()); // step is not effectively 0
318*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds.y() + searchStep > xBounds.y());
319*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds.x() + searchStep > yBounds.x());
320*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds.y() + searchStep > yBounds.y());
321*35238bceSAndroid Build Coastguard Worker 
322*35238bceSAndroid Build Coastguard Worker     if (!isInColorBounds(prec, quad0, quad1, result))
323*35238bceSAndroid Build Coastguard Worker         return false;
324*35238bceSAndroid Build Coastguard Worker 
325*35238bceSAndroid Build Coastguard Worker     for (float x = xBounds.x(); x < xBounds.y() + searchStep; x += searchStep)
326*35238bceSAndroid Build Coastguard Worker     {
327*35238bceSAndroid Build Coastguard Worker         for (float y = yBounds.x(); y < yBounds.y() + searchStep; y += searchStep)
328*35238bceSAndroid Build Coastguard Worker         {
329*35238bceSAndroid Build Coastguard Worker             const float a = de::min(x, xBounds.y());
330*35238bceSAndroid Build Coastguard Worker             const float b = de::min(y, yBounds.y());
331*35238bceSAndroid Build Coastguard Worker             const Vec4 c0 = quad0.p00 * (1.0f - a) * (1.0f - b) + quad0.p10 * a * (1.0f - b) +
332*35238bceSAndroid Build Coastguard Worker                             quad0.p01 * (1.0f - a) * b + quad0.p11 * a * b;
333*35238bceSAndroid Build Coastguard Worker             const Vec4 c1 = quad1.p00 * (1.0f - a) * (1.0f - b) + quad1.p10 * a * (1.0f - b) +
334*35238bceSAndroid Build Coastguard Worker                             quad1.p01 * (1.0f - a) * b + quad1.p11 * a * b;
335*35238bceSAndroid Build Coastguard Worker 
336*35238bceSAndroid Build Coastguard Worker             if (isLinearRangeValid(prec, c0, c1, zBounds, result))
337*35238bceSAndroid Build Coastguard Worker                 return true;
338*35238bceSAndroid Build Coastguard Worker         }
339*35238bceSAndroid Build Coastguard Worker     }
340*35238bceSAndroid Build Coastguard Worker 
341*35238bceSAndroid Build Coastguard Worker     return false;
342*35238bceSAndroid Build Coastguard Worker }
343*35238bceSAndroid Build Coastguard Worker 
isReductionValid(const LookupPrecision & prec,const Vec4 & c0,const Vec4 & c1,tcu::Sampler::ReductionMode reductionMode,const Vec4 & result)344*35238bceSAndroid Build Coastguard Worker static bool isReductionValid(const LookupPrecision &prec, const Vec4 &c0, const Vec4 &c1,
345*35238bceSAndroid Build Coastguard Worker                              tcu::Sampler::ReductionMode reductionMode, const Vec4 &result)
346*35238bceSAndroid Build Coastguard Worker {
347*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(reductionMode == tcu::Sampler::MIN || reductionMode == tcu::Sampler::MAX);
348*35238bceSAndroid Build Coastguard Worker 
349*35238bceSAndroid Build Coastguard Worker     const Vec4 color = (reductionMode == tcu::Sampler::MIN ? tcu::min(c0, c1) : tcu::max(c0, c1));
350*35238bceSAndroid Build Coastguard Worker 
351*35238bceSAndroid Build Coastguard Worker     return isColorValid(prec, color, result);
352*35238bceSAndroid Build Coastguard Worker }
353*35238bceSAndroid Build Coastguard Worker 
isReductionValid(const LookupPrecision & prec,const ColorQuad & quad,tcu::Sampler::ReductionMode reductionMode,const Vec4 & result)354*35238bceSAndroid Build Coastguard Worker static bool isReductionValid(const LookupPrecision &prec, const ColorQuad &quad,
355*35238bceSAndroid Build Coastguard Worker                              tcu::Sampler::ReductionMode reductionMode, const Vec4 &result)
356*35238bceSAndroid Build Coastguard Worker {
357*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(reductionMode == tcu::Sampler::MIN || reductionMode == tcu::Sampler::MAX);
358*35238bceSAndroid Build Coastguard Worker 
359*35238bceSAndroid Build Coastguard Worker     const Vec4 c0 = (reductionMode == tcu::Sampler::MIN ? tcu::min(quad.p00, quad.p01) : tcu::max(quad.p00, quad.p01));
360*35238bceSAndroid Build Coastguard Worker     const Vec4 c1 = (reductionMode == tcu::Sampler::MIN ? tcu::min(quad.p10, quad.p11) : tcu::max(quad.p10, quad.p11));
361*35238bceSAndroid Build Coastguard Worker 
362*35238bceSAndroid Build Coastguard Worker     return isReductionValid(prec, c0, c1, reductionMode, result);
363*35238bceSAndroid Build Coastguard Worker }
364*35238bceSAndroid Build Coastguard Worker 
isReductionValid(const LookupPrecision & prec,const ColorQuad & quad0,const ColorQuad & quad1,tcu::Sampler::ReductionMode reductionMode,const Vec4 & result)365*35238bceSAndroid Build Coastguard Worker static bool isReductionValid(const LookupPrecision &prec, const ColorQuad &quad0, const ColorQuad &quad1,
366*35238bceSAndroid Build Coastguard Worker                              tcu::Sampler::ReductionMode reductionMode, const Vec4 &result)
367*35238bceSAndroid Build Coastguard Worker {
368*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(reductionMode == tcu::Sampler::MIN || reductionMode == tcu::Sampler::MAX);
369*35238bceSAndroid Build Coastguard Worker 
370*35238bceSAndroid Build Coastguard Worker     const ColorQuad quad = {
371*35238bceSAndroid Build Coastguard Worker         reductionMode == tcu::Sampler::MIN ? tcu::min(quad0.p00, quad1.p00) : tcu::max(quad0.p00, quad1.p00), // p00
372*35238bceSAndroid Build Coastguard Worker         reductionMode == tcu::Sampler::MIN ? tcu::min(quad0.p01, quad1.p01) : tcu::max(quad0.p01, quad1.p01), // p01
373*35238bceSAndroid Build Coastguard Worker         reductionMode == tcu::Sampler::MIN ? tcu::min(quad0.p10, quad1.p10) : tcu::max(quad0.p10, quad1.p10), // p10
374*35238bceSAndroid Build Coastguard Worker         reductionMode == tcu::Sampler::MIN ? tcu::min(quad0.p11, quad1.p11) : tcu::max(quad0.p11, quad1.p11), // p11
375*35238bceSAndroid Build Coastguard Worker     };
376*35238bceSAndroid Build Coastguard Worker 
377*35238bceSAndroid Build Coastguard Worker     return isReductionValid(prec, quad, reductionMode, result);
378*35238bceSAndroid Build Coastguard Worker }
379*35238bceSAndroid Build Coastguard Worker 
is1DTrilinearFilterResultValid(const LookupPrecision & prec,const ColorLine & line0,const ColorLine & line1,const Vec2 & xBounds0,const Vec2 & xBounds1,const Vec2 & zBounds,const float searchStep,const Vec4 & result)380*35238bceSAndroid Build Coastguard Worker static bool is1DTrilinearFilterResultValid(const LookupPrecision &prec, const ColorLine &line0, const ColorLine &line1,
381*35238bceSAndroid Build Coastguard Worker                                            const Vec2 &xBounds0, const Vec2 &xBounds1, const Vec2 &zBounds,
382*35238bceSAndroid Build Coastguard Worker                                            const float searchStep, const Vec4 &result)
383*35238bceSAndroid Build Coastguard Worker {
384*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.x() <= xBounds0.y());
385*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.x() <= xBounds1.y());
386*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.x() + searchStep > xBounds0.x()); // step is not effectively 0
387*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.y() + searchStep > xBounds0.y());
388*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.x() + searchStep > xBounds1.x());
389*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.y() + searchStep > xBounds1.y());
390*35238bceSAndroid Build Coastguard Worker 
391*35238bceSAndroid Build Coastguard Worker     if (!isInColorBounds(prec, line0, line1, result))
392*35238bceSAndroid Build Coastguard Worker         return false;
393*35238bceSAndroid Build Coastguard Worker 
394*35238bceSAndroid Build Coastguard Worker     for (float x0 = xBounds0.x(); x0 < xBounds0.y() + searchStep; x0 += searchStep)
395*35238bceSAndroid Build Coastguard Worker     {
396*35238bceSAndroid Build Coastguard Worker         const float a0 = de::min(x0, xBounds0.y());
397*35238bceSAndroid Build Coastguard Worker         const Vec4 c0  = line0.p0 * (1.0f - a0) + line0.p1 * a0;
398*35238bceSAndroid Build Coastguard Worker 
399*35238bceSAndroid Build Coastguard Worker         for (float x1 = xBounds1.x(); x1 <= xBounds1.y(); x1 += searchStep)
400*35238bceSAndroid Build Coastguard Worker         {
401*35238bceSAndroid Build Coastguard Worker             const float a1 = de::min(x1, xBounds1.y());
402*35238bceSAndroid Build Coastguard Worker             const Vec4 c1  = line1.p0 * (1.0f - a1) + line1.p1 * a1;
403*35238bceSAndroid Build Coastguard Worker 
404*35238bceSAndroid Build Coastguard Worker             if (isLinearRangeValid(prec, c0, c1, zBounds, result))
405*35238bceSAndroid Build Coastguard Worker                 return true;
406*35238bceSAndroid Build Coastguard Worker         }
407*35238bceSAndroid Build Coastguard Worker     }
408*35238bceSAndroid Build Coastguard Worker 
409*35238bceSAndroid Build Coastguard Worker     return false;
410*35238bceSAndroid Build Coastguard Worker }
411*35238bceSAndroid Build Coastguard Worker 
is2DTrilinearFilterResultValid(const LookupPrecision & prec,const ColorQuad & quad0,const ColorQuad & quad1,const Vec2 & xBounds0,const Vec2 & yBounds0,const Vec2 & xBounds1,const Vec2 & yBounds1,const Vec2 & zBounds,const float searchStep,const Vec4 & result)412*35238bceSAndroid Build Coastguard Worker static bool is2DTrilinearFilterResultValid(const LookupPrecision &prec, const ColorQuad &quad0, const ColorQuad &quad1,
413*35238bceSAndroid Build Coastguard Worker                                            const Vec2 &xBounds0, const Vec2 &yBounds0, const Vec2 &xBounds1,
414*35238bceSAndroid Build Coastguard Worker                                            const Vec2 &yBounds1, const Vec2 &zBounds, const float searchStep,
415*35238bceSAndroid Build Coastguard Worker                                            const Vec4 &result)
416*35238bceSAndroid Build Coastguard Worker {
417*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.x() <= xBounds0.y());
418*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds0.x() <= yBounds0.y());
419*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.x() <= xBounds1.y());
420*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds1.x() <= yBounds1.y());
421*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.x() + searchStep > xBounds0.x()); // step is not effectively 0
422*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.y() + searchStep > xBounds0.y());
423*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds0.x() + searchStep > yBounds0.x());
424*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds0.y() + searchStep > yBounds0.y());
425*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.x() + searchStep > xBounds1.x());
426*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.y() + searchStep > xBounds1.y());
427*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds1.x() + searchStep > yBounds1.x());
428*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds1.y() + searchStep > yBounds1.y());
429*35238bceSAndroid Build Coastguard Worker 
430*35238bceSAndroid Build Coastguard Worker     if (!isInColorBounds(prec, quad0, quad1, result))
431*35238bceSAndroid Build Coastguard Worker         return false;
432*35238bceSAndroid Build Coastguard Worker 
433*35238bceSAndroid Build Coastguard Worker     for (float x0 = xBounds0.x(); x0 < xBounds0.y() + searchStep; x0 += searchStep)
434*35238bceSAndroid Build Coastguard Worker     {
435*35238bceSAndroid Build Coastguard Worker         for (float y0 = yBounds0.x(); y0 < yBounds0.y() + searchStep; y0 += searchStep)
436*35238bceSAndroid Build Coastguard Worker         {
437*35238bceSAndroid Build Coastguard Worker             const float a0 = de::min(x0, xBounds0.y());
438*35238bceSAndroid Build Coastguard Worker             const float b0 = de::min(y0, yBounds0.y());
439*35238bceSAndroid Build Coastguard Worker             const Vec4 c0  = quad0.p00 * (1.0f - a0) * (1.0f - b0) + quad0.p10 * a0 * (1.0f - b0) +
440*35238bceSAndroid Build Coastguard Worker                             quad0.p01 * (1.0f - a0) * b0 + quad0.p11 * a0 * b0;
441*35238bceSAndroid Build Coastguard Worker 
442*35238bceSAndroid Build Coastguard Worker             for (float x1 = xBounds1.x(); x1 <= xBounds1.y(); x1 += searchStep)
443*35238bceSAndroid Build Coastguard Worker             {
444*35238bceSAndroid Build Coastguard Worker                 for (float y1 = yBounds1.x(); y1 <= yBounds1.y(); y1 += searchStep)
445*35238bceSAndroid Build Coastguard Worker                 {
446*35238bceSAndroid Build Coastguard Worker                     const float a1 = de::min(x1, xBounds1.y());
447*35238bceSAndroid Build Coastguard Worker                     const float b1 = de::min(y1, yBounds1.y());
448*35238bceSAndroid Build Coastguard Worker                     const Vec4 c1  = quad1.p00 * (1.0f - a1) * (1.0f - b1) + quad1.p10 * a1 * (1.0f - b1) +
449*35238bceSAndroid Build Coastguard Worker                                     quad1.p01 * (1.0f - a1) * b1 + quad1.p11 * a1 * b1;
450*35238bceSAndroid Build Coastguard Worker 
451*35238bceSAndroid Build Coastguard Worker                     if (isLinearRangeValid(prec, c0, c1, zBounds, result))
452*35238bceSAndroid Build Coastguard Worker                         return true;
453*35238bceSAndroid Build Coastguard Worker                 }
454*35238bceSAndroid Build Coastguard Worker             }
455*35238bceSAndroid Build Coastguard Worker         }
456*35238bceSAndroid Build Coastguard Worker     }
457*35238bceSAndroid Build Coastguard Worker 
458*35238bceSAndroid Build Coastguard Worker     return false;
459*35238bceSAndroid Build Coastguard Worker }
460*35238bceSAndroid Build Coastguard Worker 
is3DTrilinearFilterResultValid(const LookupPrecision & prec,const ColorQuad & quad00,const ColorQuad & quad01,const ColorQuad & quad10,const ColorQuad & quad11,const Vec2 & xBounds0,const Vec2 & yBounds0,const Vec2 & zBounds0,const Vec2 & xBounds1,const Vec2 & yBounds1,const Vec2 & zBounds1,const Vec2 & wBounds,const float searchStep,const Vec4 & result)461*35238bceSAndroid Build Coastguard Worker static bool is3DTrilinearFilterResultValid(const LookupPrecision &prec, const ColorQuad &quad00,
462*35238bceSAndroid Build Coastguard Worker                                            const ColorQuad &quad01, const ColorQuad &quad10, const ColorQuad &quad11,
463*35238bceSAndroid Build Coastguard Worker                                            const Vec2 &xBounds0, const Vec2 &yBounds0, const Vec2 &zBounds0,
464*35238bceSAndroid Build Coastguard Worker                                            const Vec2 &xBounds1, const Vec2 &yBounds1, const Vec2 &zBounds1,
465*35238bceSAndroid Build Coastguard Worker                                            const Vec2 &wBounds, const float searchStep, const Vec4 &result)
466*35238bceSAndroid Build Coastguard Worker {
467*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.x() <= xBounds0.y());
468*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds0.x() <= yBounds0.y());
469*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(zBounds0.x() <= zBounds0.y());
470*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.x() <= xBounds1.y());
471*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds1.x() <= yBounds1.y());
472*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(zBounds1.x() <= zBounds1.y());
473*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.x() + searchStep > xBounds0.x()); // step is not effectively 0
474*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds0.y() + searchStep > xBounds0.y());
475*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds0.x() + searchStep > yBounds0.x());
476*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds0.y() + searchStep > yBounds0.y());
477*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(zBounds0.x() + searchStep > zBounds0.x());
478*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(zBounds0.y() + searchStep > zBounds0.y());
479*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.x() + searchStep > xBounds1.x());
480*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(xBounds1.y() + searchStep > xBounds1.y());
481*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds1.x() + searchStep > yBounds1.x());
482*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(yBounds1.y() + searchStep > yBounds1.y());
483*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(zBounds1.x() + searchStep > zBounds1.x());
484*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(zBounds1.y() + searchStep > zBounds1.y());
485*35238bceSAndroid Build Coastguard Worker 
486*35238bceSAndroid Build Coastguard Worker     if (!isInColorBounds(prec, quad00, quad01, quad10, quad11, result))
487*35238bceSAndroid Build Coastguard Worker         return false;
488*35238bceSAndroid Build Coastguard Worker 
489*35238bceSAndroid Build Coastguard Worker     for (float x0 = xBounds0.x(); x0 < xBounds0.y() + searchStep; x0 += searchStep)
490*35238bceSAndroid Build Coastguard Worker     {
491*35238bceSAndroid Build Coastguard Worker         for (float y0 = yBounds0.x(); y0 < yBounds0.y() + searchStep; y0 += searchStep)
492*35238bceSAndroid Build Coastguard Worker         {
493*35238bceSAndroid Build Coastguard Worker             const float a0 = de::min(x0, xBounds0.y());
494*35238bceSAndroid Build Coastguard Worker             const float b0 = de::min(y0, yBounds0.y());
495*35238bceSAndroid Build Coastguard Worker             const Vec4 c00 = quad00.p00 * (1.0f - a0) * (1.0f - b0) + quad00.p10 * a0 * (1.0f - b0) +
496*35238bceSAndroid Build Coastguard Worker                              quad00.p01 * (1.0f - a0) * b0 + quad00.p11 * a0 * b0;
497*35238bceSAndroid Build Coastguard Worker             const Vec4 c01 = quad01.p00 * (1.0f - a0) * (1.0f - b0) + quad01.p10 * a0 * (1.0f - b0) +
498*35238bceSAndroid Build Coastguard Worker                              quad01.p01 * (1.0f - a0) * b0 + quad01.p11 * a0 * b0;
499*35238bceSAndroid Build Coastguard Worker 
500*35238bceSAndroid Build Coastguard Worker             for (float z0 = zBounds0.x(); z0 < zBounds0.y() + searchStep; z0 += searchStep)
501*35238bceSAndroid Build Coastguard Worker             {
502*35238bceSAndroid Build Coastguard Worker                 const float c0 = de::min(z0, zBounds0.y());
503*35238bceSAndroid Build Coastguard Worker                 const Vec4 cz0 = c00 * (1.0f - c0) + c01 * c0;
504*35238bceSAndroid Build Coastguard Worker 
505*35238bceSAndroid Build Coastguard Worker                 for (float x1 = xBounds1.x(); x1 < xBounds1.y() + searchStep; x1 += searchStep)
506*35238bceSAndroid Build Coastguard Worker                 {
507*35238bceSAndroid Build Coastguard Worker                     for (float y1 = yBounds1.x(); y1 < yBounds1.y() + searchStep; y1 += searchStep)
508*35238bceSAndroid Build Coastguard Worker                     {
509*35238bceSAndroid Build Coastguard Worker                         const float a1 = de::min(x1, xBounds1.y());
510*35238bceSAndroid Build Coastguard Worker                         const float b1 = de::min(y1, yBounds1.y());
511*35238bceSAndroid Build Coastguard Worker                         const Vec4 c10 = quad10.p00 * (1.0f - a1) * (1.0f - b1) + quad10.p10 * a1 * (1.0f - b1) +
512*35238bceSAndroid Build Coastguard Worker                                          quad10.p01 * (1.0f - a1) * b1 + quad10.p11 * a1 * b1;
513*35238bceSAndroid Build Coastguard Worker                         const Vec4 c11 = quad11.p00 * (1.0f - a1) * (1.0f - b1) + quad11.p10 * a1 * (1.0f - b1) +
514*35238bceSAndroid Build Coastguard Worker                                          quad11.p01 * (1.0f - a1) * b1 + quad11.p11 * a1 * b1;
515*35238bceSAndroid Build Coastguard Worker 
516*35238bceSAndroid Build Coastguard Worker                         for (float z1 = zBounds1.x(); z1 < zBounds1.y() + searchStep; z1 += searchStep)
517*35238bceSAndroid Build Coastguard Worker                         {
518*35238bceSAndroid Build Coastguard Worker                             const float c1 = de::min(z1, zBounds1.y());
519*35238bceSAndroid Build Coastguard Worker                             const Vec4 cz1 = c10 * (1.0f - c1) + c11 * c1;
520*35238bceSAndroid Build Coastguard Worker 
521*35238bceSAndroid Build Coastguard Worker                             if (isLinearRangeValid(prec, cz0, cz1, wBounds, result))
522*35238bceSAndroid Build Coastguard Worker                                 return true;
523*35238bceSAndroid Build Coastguard Worker                         }
524*35238bceSAndroid Build Coastguard Worker                     }
525*35238bceSAndroid Build Coastguard Worker                 }
526*35238bceSAndroid Build Coastguard Worker             }
527*35238bceSAndroid Build Coastguard Worker         }
528*35238bceSAndroid Build Coastguard Worker     }
529*35238bceSAndroid Build Coastguard Worker 
530*35238bceSAndroid Build Coastguard Worker     return false;
531*35238bceSAndroid Build Coastguard Worker }
532*35238bceSAndroid Build Coastguard Worker 
533*35238bceSAndroid Build Coastguard Worker template <typename PrecType, typename ScalarType>
isNearestSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const PrecType & prec,const float coordX,const int coordY,const Vector<ScalarType,4> & result)534*35238bceSAndroid Build Coastguard Worker static bool isNearestSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler,
535*35238bceSAndroid Build Coastguard Worker                                        const PrecType &prec, const float coordX, const int coordY,
536*35238bceSAndroid Build Coastguard Worker                                        const Vector<ScalarType, 4> &result)
537*35238bceSAndroid Build Coastguard Worker {
538*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(level.getDepth() == 1);
539*35238bceSAndroid Build Coastguard Worker 
540*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coordX,
541*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.x(), prec.uvwBits.x());
542*35238bceSAndroid Build Coastguard Worker 
543*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x());
544*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y());
545*35238bceSAndroid Build Coastguard Worker 
546*35238bceSAndroid Build Coastguard Worker     for (int i = minI; i <= maxI; i++)
547*35238bceSAndroid Build Coastguard Worker     {
548*35238bceSAndroid Build Coastguard Worker         const int x                       = wrap(sampler.wrapS, i, level.getWidth());
549*35238bceSAndroid Build Coastguard Worker         const Vector<ScalarType, 4> color = lookup<ScalarType>(level, sampler, x, coordY, 0);
550*35238bceSAndroid Build Coastguard Worker 
551*35238bceSAndroid Build Coastguard Worker         if (isColorValid(prec, color, result))
552*35238bceSAndroid Build Coastguard Worker             return true;
553*35238bceSAndroid Build Coastguard Worker     }
554*35238bceSAndroid Build Coastguard Worker 
555*35238bceSAndroid Build Coastguard Worker     return false;
556*35238bceSAndroid Build Coastguard Worker }
557*35238bceSAndroid Build Coastguard Worker 
558*35238bceSAndroid Build Coastguard Worker template <typename PrecType, typename ScalarType>
isNearestSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const PrecType & prec,const Vec2 & coord,const int coordZ,const Vector<ScalarType,4> & result)559*35238bceSAndroid Build Coastguard Worker static bool isNearestSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler,
560*35238bceSAndroid Build Coastguard Worker                                        const PrecType &prec, const Vec2 &coord, const int coordZ,
561*35238bceSAndroid Build Coastguard Worker                                        const Vector<ScalarType, 4> &result)
562*35238bceSAndroid Build Coastguard Worker {
563*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(),
564*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.x(), prec.uvwBits.x());
565*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(),
566*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.y(), prec.uvwBits.y());
567*35238bceSAndroid Build Coastguard Worker 
568*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
569*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x());
570*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y());
571*35238bceSAndroid Build Coastguard Worker     const int minJ = deFloorFloatToInt32(vBounds.x());
572*35238bceSAndroid Build Coastguard Worker     const int maxJ = deFloorFloatToInt32(vBounds.y());
573*35238bceSAndroid Build Coastguard Worker 
574*35238bceSAndroid Build Coastguard Worker     // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
575*35238bceSAndroid Build Coastguard Worker 
576*35238bceSAndroid Build Coastguard Worker     for (int j = minJ; j <= maxJ; j++)
577*35238bceSAndroid Build Coastguard Worker     {
578*35238bceSAndroid Build Coastguard Worker         for (int i = minI; i <= maxI; i++)
579*35238bceSAndroid Build Coastguard Worker         {
580*35238bceSAndroid Build Coastguard Worker             const int x                       = wrap(sampler.wrapS, i, level.getWidth());
581*35238bceSAndroid Build Coastguard Worker             const int y                       = wrap(sampler.wrapT, j, level.getHeight());
582*35238bceSAndroid Build Coastguard Worker             const Vector<ScalarType, 4> color = lookup<ScalarType>(level, sampler, x, y, coordZ);
583*35238bceSAndroid Build Coastguard Worker 
584*35238bceSAndroid Build Coastguard Worker             if (isColorValid(prec, color, result))
585*35238bceSAndroid Build Coastguard Worker                 return true;
586*35238bceSAndroid Build Coastguard Worker         }
587*35238bceSAndroid Build Coastguard Worker     }
588*35238bceSAndroid Build Coastguard Worker 
589*35238bceSAndroid Build Coastguard Worker     return false;
590*35238bceSAndroid Build Coastguard Worker }
591*35238bceSAndroid Build Coastguard Worker 
592*35238bceSAndroid Build Coastguard Worker template <typename PrecType, typename ScalarType>
isNearestSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const PrecType & prec,const Vec3 & coord,const Vector<ScalarType,4> & result)593*35238bceSAndroid Build Coastguard Worker static bool isNearestSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler,
594*35238bceSAndroid Build Coastguard Worker                                        const PrecType &prec, const Vec3 &coord, const Vector<ScalarType, 4> &result)
595*35238bceSAndroid Build Coastguard Worker {
596*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(),
597*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.x(), prec.uvwBits.x());
598*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(),
599*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.y(), prec.uvwBits.y());
600*35238bceSAndroid Build Coastguard Worker     const Vec2 wBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getDepth(), coord.z(),
601*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.z(), prec.uvwBits.z());
602*35238bceSAndroid Build Coastguard Worker 
603*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
604*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x());
605*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y());
606*35238bceSAndroid Build Coastguard Worker     const int minJ = deFloorFloatToInt32(vBounds.x());
607*35238bceSAndroid Build Coastguard Worker     const int maxJ = deFloorFloatToInt32(vBounds.y());
608*35238bceSAndroid Build Coastguard Worker     const int minK = deFloorFloatToInt32(wBounds.x());
609*35238bceSAndroid Build Coastguard Worker     const int maxK = deFloorFloatToInt32(wBounds.y());
610*35238bceSAndroid Build Coastguard Worker 
611*35238bceSAndroid Build Coastguard Worker     // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
612*35238bceSAndroid Build Coastguard Worker 
613*35238bceSAndroid Build Coastguard Worker     for (int k = minK; k <= maxK; k++)
614*35238bceSAndroid Build Coastguard Worker     {
615*35238bceSAndroid Build Coastguard Worker         for (int j = minJ; j <= maxJ; j++)
616*35238bceSAndroid Build Coastguard Worker         {
617*35238bceSAndroid Build Coastguard Worker             for (int i = minI; i <= maxI; i++)
618*35238bceSAndroid Build Coastguard Worker             {
619*35238bceSAndroid Build Coastguard Worker                 const int x                       = wrap(sampler.wrapS, i, level.getWidth());
620*35238bceSAndroid Build Coastguard Worker                 const int y                       = wrap(sampler.wrapT, j, level.getHeight());
621*35238bceSAndroid Build Coastguard Worker                 const int z                       = wrap(sampler.wrapR, k, level.getDepth());
622*35238bceSAndroid Build Coastguard Worker                 const Vector<ScalarType, 4> color = lookup<ScalarType>(level, sampler, x, y, z);
623*35238bceSAndroid Build Coastguard Worker 
624*35238bceSAndroid Build Coastguard Worker                 if (isColorValid(prec, color, result))
625*35238bceSAndroid Build Coastguard Worker                     return true;
626*35238bceSAndroid Build Coastguard Worker             }
627*35238bceSAndroid Build Coastguard Worker         }
628*35238bceSAndroid Build Coastguard Worker     }
629*35238bceSAndroid Build Coastguard Worker 
630*35238bceSAndroid Build Coastguard Worker     return false;
631*35238bceSAndroid Build Coastguard Worker }
632*35238bceSAndroid Build Coastguard Worker 
isLinearSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const LookupPrecision & prec,const float coordX,const int coordY,const Vec4 & result)633*35238bceSAndroid Build Coastguard Worker bool isLinearSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler, const LookupPrecision &prec,
634*35238bceSAndroid Build Coastguard Worker                                const float coordX, const int coordY, const Vec4 &result)
635*35238bceSAndroid Build Coastguard Worker {
636*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coordX,
637*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.x(), prec.uvwBits.x());
638*35238bceSAndroid Build Coastguard Worker 
639*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x() - 0.5f);
640*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y() - 0.5f);
641*35238bceSAndroid Build Coastguard Worker 
642*35238bceSAndroid Build Coastguard Worker     const int w = level.getWidth();
643*35238bceSAndroid Build Coastguard Worker 
644*35238bceSAndroid Build Coastguard Worker     const TextureFormat format         = level.getFormat();
645*35238bceSAndroid Build Coastguard Worker     const TextureChannelClass texClass = getTextureChannelClass(format.type);
646*35238bceSAndroid Build Coastguard Worker 
647*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
648*35238bceSAndroid Build Coastguard Worker               texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || texClass == TEXTURECHANNELCLASS_FLOATING_POINT ||
649*35238bceSAndroid Build Coastguard Worker               sampler.reductionMode != Sampler::WEIGHTED_AVERAGE);
650*35238bceSAndroid Build Coastguard Worker 
651*35238bceSAndroid Build Coastguard Worker     DE_UNREF(texClass);
652*35238bceSAndroid Build Coastguard Worker     DE_UNREF(format);
653*35238bceSAndroid Build Coastguard Worker 
654*35238bceSAndroid Build Coastguard Worker     for (int i = minI; i <= maxI; i++)
655*35238bceSAndroid Build Coastguard Worker     {
656*35238bceSAndroid Build Coastguard Worker         // Wrapped coordinates
657*35238bceSAndroid Build Coastguard Worker         const int x0 = wrap(sampler.wrapS, i, w);
658*35238bceSAndroid Build Coastguard Worker         const int x1 = wrap(sampler.wrapS, i + 1, w);
659*35238bceSAndroid Build Coastguard Worker 
660*35238bceSAndroid Build Coastguard Worker         // Bounds for filtering factors
661*35238bceSAndroid Build Coastguard Worker         const float minA = de::clamp((uBounds.x() - 0.5f) - float(i), 0.0f, 1.0f);
662*35238bceSAndroid Build Coastguard Worker         const float maxA = de::clamp((uBounds.y() - 0.5f) - float(i), 0.0f, 1.0f);
663*35238bceSAndroid Build Coastguard Worker 
664*35238bceSAndroid Build Coastguard Worker         const Vec4 colorA = lookup<float>(level, sampler, x0, coordY, 0);
665*35238bceSAndroid Build Coastguard Worker         const Vec4 colorB = lookup<float>(level, sampler, x1, coordY, 0);
666*35238bceSAndroid Build Coastguard Worker 
667*35238bceSAndroid Build Coastguard Worker         if (sampler.reductionMode == Sampler::WEIGHTED_AVERAGE)
668*35238bceSAndroid Build Coastguard Worker         {
669*35238bceSAndroid Build Coastguard Worker             if (isLinearRangeValid(prec, colorA, colorB, Vec2(minA, maxA), result))
670*35238bceSAndroid Build Coastguard Worker                 return true;
671*35238bceSAndroid Build Coastguard Worker         }
672*35238bceSAndroid Build Coastguard Worker         else
673*35238bceSAndroid Build Coastguard Worker         {
674*35238bceSAndroid Build Coastguard Worker             if (isReductionValid(prec, colorA, colorB, sampler.reductionMode, result))
675*35238bceSAndroid Build Coastguard Worker                 return true;
676*35238bceSAndroid Build Coastguard Worker         }
677*35238bceSAndroid Build Coastguard Worker     }
678*35238bceSAndroid Build Coastguard Worker 
679*35238bceSAndroid Build Coastguard Worker     return false;
680*35238bceSAndroid Build Coastguard Worker }
681*35238bceSAndroid Build Coastguard Worker 
isLinearSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const LookupPrecision & prec,const Vec2 & coord,const int coordZ,const Vec4 & result)682*35238bceSAndroid Build Coastguard Worker bool isLinearSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler, const LookupPrecision &prec,
683*35238bceSAndroid Build Coastguard Worker                                const Vec2 &coord, const int coordZ, const Vec4 &result)
684*35238bceSAndroid Build Coastguard Worker {
685*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(),
686*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.x(), prec.uvwBits.x());
687*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(),
688*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.y(), prec.uvwBits.y());
689*35238bceSAndroid Build Coastguard Worker 
690*35238bceSAndroid Build Coastguard Worker     // Integer coordinate bounds for (x0,y0) - without wrap mode
691*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x() - 0.5f);
692*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y() - 0.5f);
693*35238bceSAndroid Build Coastguard Worker     const int minJ = deFloorFloatToInt32(vBounds.x() - 0.5f);
694*35238bceSAndroid Build Coastguard Worker     const int maxJ = deFloorFloatToInt32(vBounds.y() - 0.5f);
695*35238bceSAndroid Build Coastguard Worker 
696*35238bceSAndroid Build Coastguard Worker     const int w = level.getWidth();
697*35238bceSAndroid Build Coastguard Worker     const int h = level.getHeight();
698*35238bceSAndroid Build Coastguard Worker 
699*35238bceSAndroid Build Coastguard Worker     const TextureChannelClass texClass = getTextureChannelClass(level.getFormat().type);
700*35238bceSAndroid Build Coastguard Worker     float searchStep                   = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ?
701*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForUnorm(prec) :
702*35238bceSAndroid Build Coastguard Worker                                          texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ?
703*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForSnorm(prec) :
704*35238bceSAndroid Build Coastguard Worker                                              0.0f; // Step is computed for floating-point quads based on texel values.
705*35238bceSAndroid Build Coastguard Worker 
706*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
707*35238bceSAndroid Build Coastguard Worker               texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || texClass == TEXTURECHANNELCLASS_FLOATING_POINT ||
708*35238bceSAndroid Build Coastguard Worker               sampler.reductionMode != Sampler::WEIGHTED_AVERAGE);
709*35238bceSAndroid Build Coastguard Worker 
710*35238bceSAndroid Build Coastguard Worker     // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
711*35238bceSAndroid Build Coastguard Worker 
712*35238bceSAndroid Build Coastguard Worker     for (int j = minJ; j <= maxJ; j++)
713*35238bceSAndroid Build Coastguard Worker     {
714*35238bceSAndroid Build Coastguard Worker         for (int i = minI; i <= maxI; i++)
715*35238bceSAndroid Build Coastguard Worker         {
716*35238bceSAndroid Build Coastguard Worker             // Wrapped coordinates
717*35238bceSAndroid Build Coastguard Worker             const int x0 = wrap(sampler.wrapS, i, w);
718*35238bceSAndroid Build Coastguard Worker             const int x1 = wrap(sampler.wrapS, i + 1, w);
719*35238bceSAndroid Build Coastguard Worker             const int y0 = wrap(sampler.wrapT, j, h);
720*35238bceSAndroid Build Coastguard Worker             const int y1 = wrap(sampler.wrapT, j + 1, h);
721*35238bceSAndroid Build Coastguard Worker 
722*35238bceSAndroid Build Coastguard Worker             // Bounds for filtering factors
723*35238bceSAndroid Build Coastguard Worker             const float minA = de::clamp((uBounds.x() - 0.5f) - float(i), 0.0f, 1.0f);
724*35238bceSAndroid Build Coastguard Worker             const float maxA = de::clamp((uBounds.y() - 0.5f) - float(i), 0.0f, 1.0f);
725*35238bceSAndroid Build Coastguard Worker             const float minB = de::clamp((vBounds.x() - 0.5f) - float(j), 0.0f, 1.0f);
726*35238bceSAndroid Build Coastguard Worker             const float maxB = de::clamp((vBounds.y() - 0.5f) - float(j), 0.0f, 1.0f);
727*35238bceSAndroid Build Coastguard Worker 
728*35238bceSAndroid Build Coastguard Worker             ColorQuad quad;
729*35238bceSAndroid Build Coastguard Worker             lookupQuad(quad, level, sampler, x0, x1, y0, y1, coordZ);
730*35238bceSAndroid Build Coastguard Worker 
731*35238bceSAndroid Build Coastguard Worker             if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
732*35238bceSAndroid Build Coastguard Worker                 searchStep = computeBilinearSearchStepFromFloatQuad(prec, quad);
733*35238bceSAndroid Build Coastguard Worker 
734*35238bceSAndroid Build Coastguard Worker             if (sampler.reductionMode == Sampler::WEIGHTED_AVERAGE)
735*35238bceSAndroid Build Coastguard Worker             {
736*35238bceSAndroid Build Coastguard Worker                 if (isBilinearRangeValid(prec, quad, Vec2(minA, maxA), Vec2(minB, maxB), searchStep, result))
737*35238bceSAndroid Build Coastguard Worker                     return true;
738*35238bceSAndroid Build Coastguard Worker             }
739*35238bceSAndroid Build Coastguard Worker             else
740*35238bceSAndroid Build Coastguard Worker             {
741*35238bceSAndroid Build Coastguard Worker                 if (isReductionValid(prec, quad, sampler.reductionMode, result))
742*35238bceSAndroid Build Coastguard Worker                     return true;
743*35238bceSAndroid Build Coastguard Worker             }
744*35238bceSAndroid Build Coastguard Worker         }
745*35238bceSAndroid Build Coastguard Worker     }
746*35238bceSAndroid Build Coastguard Worker 
747*35238bceSAndroid Build Coastguard Worker     return false;
748*35238bceSAndroid Build Coastguard Worker }
749*35238bceSAndroid Build Coastguard Worker 
isLinearSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const LookupPrecision & prec,const Vec3 & coord,const Vec4 & result)750*35238bceSAndroid Build Coastguard Worker static bool isLinearSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler,
751*35238bceSAndroid Build Coastguard Worker                                       const LookupPrecision &prec, const Vec3 &coord, const Vec4 &result)
752*35238bceSAndroid Build Coastguard Worker {
753*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(),
754*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.x(), prec.uvwBits.x());
755*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(),
756*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.y(), prec.uvwBits.y());
757*35238bceSAndroid Build Coastguard Worker     const Vec2 wBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getDepth(), coord.z(),
758*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.z(), prec.uvwBits.z());
759*35238bceSAndroid Build Coastguard Worker 
760*35238bceSAndroid Build Coastguard Worker     // Integer coordinate bounds for (x0,y0) - without wrap mode
761*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x() - 0.5f);
762*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y() - 0.5f);
763*35238bceSAndroid Build Coastguard Worker     const int minJ = deFloorFloatToInt32(vBounds.x() - 0.5f);
764*35238bceSAndroid Build Coastguard Worker     const int maxJ = deFloorFloatToInt32(vBounds.y() - 0.5f);
765*35238bceSAndroid Build Coastguard Worker     const int minK = deFloorFloatToInt32(wBounds.x() - 0.5f);
766*35238bceSAndroid Build Coastguard Worker     const int maxK = deFloorFloatToInt32(wBounds.y() - 0.5f);
767*35238bceSAndroid Build Coastguard Worker 
768*35238bceSAndroid Build Coastguard Worker     const int w = level.getWidth();
769*35238bceSAndroid Build Coastguard Worker     const int h = level.getHeight();
770*35238bceSAndroid Build Coastguard Worker     const int d = level.getDepth();
771*35238bceSAndroid Build Coastguard Worker 
772*35238bceSAndroid Build Coastguard Worker     const TextureChannelClass texClass = getTextureChannelClass(level.getFormat().type);
773*35238bceSAndroid Build Coastguard Worker     float searchStep                   = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ?
774*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForUnorm(prec) :
775*35238bceSAndroid Build Coastguard Worker                                          texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ?
776*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForSnorm(prec) :
777*35238bceSAndroid Build Coastguard Worker                                              0.0f; // Step is computed for floating-point quads based on texel values.
778*35238bceSAndroid Build Coastguard Worker 
779*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
780*35238bceSAndroid Build Coastguard Worker               texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || texClass == TEXTURECHANNELCLASS_FLOATING_POINT ||
781*35238bceSAndroid Build Coastguard Worker               sampler.reductionMode != Sampler::WEIGHTED_AVERAGE);
782*35238bceSAndroid Build Coastguard Worker 
783*35238bceSAndroid Build Coastguard Worker     // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
784*35238bceSAndroid Build Coastguard Worker 
785*35238bceSAndroid Build Coastguard Worker     for (int k = minK; k <= maxK; k++)
786*35238bceSAndroid Build Coastguard Worker     {
787*35238bceSAndroid Build Coastguard Worker         for (int j = minJ; j <= maxJ; j++)
788*35238bceSAndroid Build Coastguard Worker         {
789*35238bceSAndroid Build Coastguard Worker             for (int i = minI; i <= maxI; i++)
790*35238bceSAndroid Build Coastguard Worker             {
791*35238bceSAndroid Build Coastguard Worker                 // Wrapped coordinates
792*35238bceSAndroid Build Coastguard Worker                 const int x0 = wrap(sampler.wrapS, i, w);
793*35238bceSAndroid Build Coastguard Worker                 const int x1 = wrap(sampler.wrapS, i + 1, w);
794*35238bceSAndroid Build Coastguard Worker                 const int y0 = wrap(sampler.wrapT, j, h);
795*35238bceSAndroid Build Coastguard Worker                 const int y1 = wrap(sampler.wrapT, j + 1, h);
796*35238bceSAndroid Build Coastguard Worker                 const int z0 = wrap(sampler.wrapR, k, d);
797*35238bceSAndroid Build Coastguard Worker                 const int z1 = wrap(sampler.wrapR, k + 1, d);
798*35238bceSAndroid Build Coastguard Worker 
799*35238bceSAndroid Build Coastguard Worker                 // Bounds for filtering factors
800*35238bceSAndroid Build Coastguard Worker                 const float minA = de::clamp((uBounds.x() - 0.5f) - float(i), 0.0f, 1.0f);
801*35238bceSAndroid Build Coastguard Worker                 const float maxA = de::clamp((uBounds.y() - 0.5f) - float(i), 0.0f, 1.0f);
802*35238bceSAndroid Build Coastguard Worker                 const float minB = de::clamp((vBounds.x() - 0.5f) - float(j), 0.0f, 1.0f);
803*35238bceSAndroid Build Coastguard Worker                 const float maxB = de::clamp((vBounds.y() - 0.5f) - float(j), 0.0f, 1.0f);
804*35238bceSAndroid Build Coastguard Worker                 const float minC = de::clamp((wBounds.x() - 0.5f) - float(k), 0.0f, 1.0f);
805*35238bceSAndroid Build Coastguard Worker                 const float maxC = de::clamp((wBounds.y() - 0.5f) - float(k), 0.0f, 1.0f);
806*35238bceSAndroid Build Coastguard Worker 
807*35238bceSAndroid Build Coastguard Worker                 ColorQuad quad0, quad1;
808*35238bceSAndroid Build Coastguard Worker                 lookupQuad(quad0, level, sampler, x0, x1, y0, y1, z0);
809*35238bceSAndroid Build Coastguard Worker                 lookupQuad(quad1, level, sampler, x0, x1, y0, y1, z1);
810*35238bceSAndroid Build Coastguard Worker 
811*35238bceSAndroid Build Coastguard Worker                 if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
812*35238bceSAndroid Build Coastguard Worker                     searchStep = de::min(computeBilinearSearchStepFromFloatQuad(prec, quad0),
813*35238bceSAndroid Build Coastguard Worker                                          computeBilinearSearchStepFromFloatQuad(prec, quad1));
814*35238bceSAndroid Build Coastguard Worker 
815*35238bceSAndroid Build Coastguard Worker                 if (sampler.reductionMode == Sampler::WEIGHTED_AVERAGE)
816*35238bceSAndroid Build Coastguard Worker                 {
817*35238bceSAndroid Build Coastguard Worker                     if (isTrilinearRangeValid(prec, quad0, quad1, Vec2(minA, maxA), Vec2(minB, maxB), Vec2(minC, maxC),
818*35238bceSAndroid Build Coastguard Worker                                               searchStep, result))
819*35238bceSAndroid Build Coastguard Worker                         return true;
820*35238bceSAndroid Build Coastguard Worker                 }
821*35238bceSAndroid Build Coastguard Worker                 else
822*35238bceSAndroid Build Coastguard Worker                 {
823*35238bceSAndroid Build Coastguard Worker                     if (isReductionValid(prec, quad0, quad1, sampler.reductionMode, result))
824*35238bceSAndroid Build Coastguard Worker                         return true;
825*35238bceSAndroid Build Coastguard Worker                 }
826*35238bceSAndroid Build Coastguard Worker             }
827*35238bceSAndroid Build Coastguard Worker         }
828*35238bceSAndroid Build Coastguard Worker     }
829*35238bceSAndroid Build Coastguard Worker 
830*35238bceSAndroid Build Coastguard Worker     return false;
831*35238bceSAndroid Build Coastguard Worker }
832*35238bceSAndroid Build Coastguard Worker 
isNearestMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const LookupPrecision & prec,const float coord,const int coordY,const Vec2 & fBounds,const Vec4 & result)833*35238bceSAndroid Build Coastguard Worker static bool isNearestMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0,
834*35238bceSAndroid Build Coastguard Worker                                                    const ConstPixelBufferAccess &level1, const Sampler &sampler,
835*35238bceSAndroid Build Coastguard Worker                                                    const LookupPrecision &prec, const float coord, const int coordY,
836*35238bceSAndroid Build Coastguard Worker                                                    const Vec2 &fBounds, const Vec4 &result)
837*35238bceSAndroid Build Coastguard Worker {
838*35238bceSAndroid Build Coastguard Worker     const int w0 = level0.getWidth();
839*35238bceSAndroid Build Coastguard Worker     const int w1 = level1.getWidth();
840*35238bceSAndroid Build Coastguard Worker 
841*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds0 =
842*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord, prec.coordBits.x(), prec.uvwBits.x());
843*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds1 =
844*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord, prec.coordBits.x(), prec.uvwBits.x());
845*35238bceSAndroid Build Coastguard Worker 
846*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
847*35238bceSAndroid Build Coastguard Worker     const int minI0 = deFloorFloatToInt32(uBounds0.x());
848*35238bceSAndroid Build Coastguard Worker     const int maxI0 = deFloorFloatToInt32(uBounds0.y());
849*35238bceSAndroid Build Coastguard Worker     const int minI1 = deFloorFloatToInt32(uBounds1.x());
850*35238bceSAndroid Build Coastguard Worker     const int maxI1 = deFloorFloatToInt32(uBounds1.y());
851*35238bceSAndroid Build Coastguard Worker 
852*35238bceSAndroid Build Coastguard Worker     for (int i0 = minI0; i0 <= maxI0; i0++)
853*35238bceSAndroid Build Coastguard Worker     {
854*35238bceSAndroid Build Coastguard Worker         for (int i1 = minI1; i1 <= maxI1; i1++)
855*35238bceSAndroid Build Coastguard Worker         {
856*35238bceSAndroid Build Coastguard Worker             const Vec4 c0 = lookup<float>(level0, sampler, wrap(sampler.wrapS, i0, w0), coordY, 0);
857*35238bceSAndroid Build Coastguard Worker             const Vec4 c1 = lookup<float>(level1, sampler, wrap(sampler.wrapS, i1, w1), coordY, 0);
858*35238bceSAndroid Build Coastguard Worker 
859*35238bceSAndroid Build Coastguard Worker             if (isLinearRangeValid(prec, c0, c1, fBounds, result))
860*35238bceSAndroid Build Coastguard Worker                 return true;
861*35238bceSAndroid Build Coastguard Worker         }
862*35238bceSAndroid Build Coastguard Worker     }
863*35238bceSAndroid Build Coastguard Worker 
864*35238bceSAndroid Build Coastguard Worker     return false;
865*35238bceSAndroid Build Coastguard Worker }
866*35238bceSAndroid Build Coastguard Worker 
isNearestMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const LookupPrecision & prec,const Vec2 & coord,const int coordZ,const Vec2 & fBounds,const Vec4 & result)867*35238bceSAndroid Build Coastguard Worker static bool isNearestMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0,
868*35238bceSAndroid Build Coastguard Worker                                                    const ConstPixelBufferAccess &level1, const Sampler &sampler,
869*35238bceSAndroid Build Coastguard Worker                                                    const LookupPrecision &prec, const Vec2 &coord, const int coordZ,
870*35238bceSAndroid Build Coastguard Worker                                                    const Vec2 &fBounds, const Vec4 &result)
871*35238bceSAndroid Build Coastguard Worker {
872*35238bceSAndroid Build Coastguard Worker     const int w0 = level0.getWidth();
873*35238bceSAndroid Build Coastguard Worker     const int w1 = level1.getWidth();
874*35238bceSAndroid Build Coastguard Worker     const int h0 = level0.getHeight();
875*35238bceSAndroid Build Coastguard Worker     const int h1 = level1.getHeight();
876*35238bceSAndroid Build Coastguard Worker 
877*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds0 =
878*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
879*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds1 =
880*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
881*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds0 =
882*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
883*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds1 =
884*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
885*35238bceSAndroid Build Coastguard Worker 
886*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
887*35238bceSAndroid Build Coastguard Worker     const int minI0 = deFloorFloatToInt32(uBounds0.x());
888*35238bceSAndroid Build Coastguard Worker     const int maxI0 = deFloorFloatToInt32(uBounds0.y());
889*35238bceSAndroid Build Coastguard Worker     const int minI1 = deFloorFloatToInt32(uBounds1.x());
890*35238bceSAndroid Build Coastguard Worker     const int maxI1 = deFloorFloatToInt32(uBounds1.y());
891*35238bceSAndroid Build Coastguard Worker     const int minJ0 = deFloorFloatToInt32(vBounds0.x());
892*35238bceSAndroid Build Coastguard Worker     const int maxJ0 = deFloorFloatToInt32(vBounds0.y());
893*35238bceSAndroid Build Coastguard Worker     const int minJ1 = deFloorFloatToInt32(vBounds1.x());
894*35238bceSAndroid Build Coastguard Worker     const int maxJ1 = deFloorFloatToInt32(vBounds1.y());
895*35238bceSAndroid Build Coastguard Worker 
896*35238bceSAndroid Build Coastguard Worker     for (int j0 = minJ0; j0 <= maxJ0; j0++)
897*35238bceSAndroid Build Coastguard Worker     {
898*35238bceSAndroid Build Coastguard Worker         for (int i0 = minI0; i0 <= maxI0; i0++)
899*35238bceSAndroid Build Coastguard Worker         {
900*35238bceSAndroid Build Coastguard Worker             for (int j1 = minJ1; j1 <= maxJ1; j1++)
901*35238bceSAndroid Build Coastguard Worker             {
902*35238bceSAndroid Build Coastguard Worker                 for (int i1 = minI1; i1 <= maxI1; i1++)
903*35238bceSAndroid Build Coastguard Worker                 {
904*35238bceSAndroid Build Coastguard Worker                     const Vec4 c0 = lookup<float>(level0, sampler, wrap(sampler.wrapS, i0, w0),
905*35238bceSAndroid Build Coastguard Worker                                                   wrap(sampler.wrapT, j0, h0), coordZ);
906*35238bceSAndroid Build Coastguard Worker                     const Vec4 c1 = lookup<float>(level1, sampler, wrap(sampler.wrapS, i1, w1),
907*35238bceSAndroid Build Coastguard Worker                                                   wrap(sampler.wrapT, j1, h1), coordZ);
908*35238bceSAndroid Build Coastguard Worker 
909*35238bceSAndroid Build Coastguard Worker                     if (isLinearRangeValid(prec, c0, c1, fBounds, result))
910*35238bceSAndroid Build Coastguard Worker                         return true;
911*35238bceSAndroid Build Coastguard Worker                 }
912*35238bceSAndroid Build Coastguard Worker             }
913*35238bceSAndroid Build Coastguard Worker         }
914*35238bceSAndroid Build Coastguard Worker     }
915*35238bceSAndroid Build Coastguard Worker 
916*35238bceSAndroid Build Coastguard Worker     return false;
917*35238bceSAndroid Build Coastguard Worker }
918*35238bceSAndroid Build Coastguard Worker 
isNearestMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const LookupPrecision & prec,const Vec3 & coord,const Vec2 & fBounds,const Vec4 & result)919*35238bceSAndroid Build Coastguard Worker static bool isNearestMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0,
920*35238bceSAndroid Build Coastguard Worker                                                    const ConstPixelBufferAccess &level1, const Sampler &sampler,
921*35238bceSAndroid Build Coastguard Worker                                                    const LookupPrecision &prec, const Vec3 &coord, const Vec2 &fBounds,
922*35238bceSAndroid Build Coastguard Worker                                                    const Vec4 &result)
923*35238bceSAndroid Build Coastguard Worker {
924*35238bceSAndroid Build Coastguard Worker     const int w0 = level0.getWidth();
925*35238bceSAndroid Build Coastguard Worker     const int w1 = level1.getWidth();
926*35238bceSAndroid Build Coastguard Worker     const int h0 = level0.getHeight();
927*35238bceSAndroid Build Coastguard Worker     const int h1 = level1.getHeight();
928*35238bceSAndroid Build Coastguard Worker     const int d0 = level0.getDepth();
929*35238bceSAndroid Build Coastguard Worker     const int d1 = level1.getDepth();
930*35238bceSAndroid Build Coastguard Worker 
931*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds0 =
932*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
933*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds1 =
934*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
935*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds0 =
936*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
937*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds1 =
938*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
939*35238bceSAndroid Build Coastguard Worker     const Vec2 wBounds0 =
940*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, d0, coord.z(), prec.coordBits.z(), prec.uvwBits.z());
941*35238bceSAndroid Build Coastguard Worker     const Vec2 wBounds1 =
942*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, d1, coord.z(), prec.coordBits.z(), prec.uvwBits.z());
943*35238bceSAndroid Build Coastguard Worker 
944*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
945*35238bceSAndroid Build Coastguard Worker     const int minI0 = deFloorFloatToInt32(uBounds0.x());
946*35238bceSAndroid Build Coastguard Worker     const int maxI0 = deFloorFloatToInt32(uBounds0.y());
947*35238bceSAndroid Build Coastguard Worker     const int minI1 = deFloorFloatToInt32(uBounds1.x());
948*35238bceSAndroid Build Coastguard Worker     const int maxI1 = deFloorFloatToInt32(uBounds1.y());
949*35238bceSAndroid Build Coastguard Worker     const int minJ0 = deFloorFloatToInt32(vBounds0.x());
950*35238bceSAndroid Build Coastguard Worker     const int maxJ0 = deFloorFloatToInt32(vBounds0.y());
951*35238bceSAndroid Build Coastguard Worker     const int minJ1 = deFloorFloatToInt32(vBounds1.x());
952*35238bceSAndroid Build Coastguard Worker     const int maxJ1 = deFloorFloatToInt32(vBounds1.y());
953*35238bceSAndroid Build Coastguard Worker     const int minK0 = deFloorFloatToInt32(wBounds0.x());
954*35238bceSAndroid Build Coastguard Worker     const int maxK0 = deFloorFloatToInt32(wBounds0.y());
955*35238bceSAndroid Build Coastguard Worker     const int minK1 = deFloorFloatToInt32(wBounds1.x());
956*35238bceSAndroid Build Coastguard Worker     const int maxK1 = deFloorFloatToInt32(wBounds1.y());
957*35238bceSAndroid Build Coastguard Worker 
958*35238bceSAndroid Build Coastguard Worker     for (int k0 = minK0; k0 <= maxK0; k0++)
959*35238bceSAndroid Build Coastguard Worker     {
960*35238bceSAndroid Build Coastguard Worker         for (int j0 = minJ0; j0 <= maxJ0; j0++)
961*35238bceSAndroid Build Coastguard Worker         {
962*35238bceSAndroid Build Coastguard Worker             for (int i0 = minI0; i0 <= maxI0; i0++)
963*35238bceSAndroid Build Coastguard Worker             {
964*35238bceSAndroid Build Coastguard Worker                 for (int k1 = minK1; k1 <= maxK1; k1++)
965*35238bceSAndroid Build Coastguard Worker                 {
966*35238bceSAndroid Build Coastguard Worker                     for (int j1 = minJ1; j1 <= maxJ1; j1++)
967*35238bceSAndroid Build Coastguard Worker                     {
968*35238bceSAndroid Build Coastguard Worker                         for (int i1 = minI1; i1 <= maxI1; i1++)
969*35238bceSAndroid Build Coastguard Worker                         {
970*35238bceSAndroid Build Coastguard Worker                             const Vec4 c0 = lookup<float>(level0, sampler, wrap(sampler.wrapS, i0, w0),
971*35238bceSAndroid Build Coastguard Worker                                                           wrap(sampler.wrapT, j0, h0), wrap(sampler.wrapR, k0, d0));
972*35238bceSAndroid Build Coastguard Worker                             const Vec4 c1 = lookup<float>(level1, sampler, wrap(sampler.wrapS, i1, w1),
973*35238bceSAndroid Build Coastguard Worker                                                           wrap(sampler.wrapT, j1, h1), wrap(sampler.wrapR, k1, d1));
974*35238bceSAndroid Build Coastguard Worker 
975*35238bceSAndroid Build Coastguard Worker                             if (isLinearRangeValid(prec, c0, c1, fBounds, result))
976*35238bceSAndroid Build Coastguard Worker                                 return true;
977*35238bceSAndroid Build Coastguard Worker                         }
978*35238bceSAndroid Build Coastguard Worker                     }
979*35238bceSAndroid Build Coastguard Worker                 }
980*35238bceSAndroid Build Coastguard Worker             }
981*35238bceSAndroid Build Coastguard Worker         }
982*35238bceSAndroid Build Coastguard Worker     }
983*35238bceSAndroid Build Coastguard Worker 
984*35238bceSAndroid Build Coastguard Worker     return false;
985*35238bceSAndroid Build Coastguard Worker }
986*35238bceSAndroid Build Coastguard Worker 
isLinearMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const LookupPrecision & prec,const float coordX,const int coordY,const Vec2 & fBounds,const Vec4 & result)987*35238bceSAndroid Build Coastguard Worker static bool isLinearMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0,
988*35238bceSAndroid Build Coastguard Worker                                                   const ConstPixelBufferAccess &level1, const Sampler &sampler,
989*35238bceSAndroid Build Coastguard Worker                                                   const LookupPrecision &prec, const float coordX, const int coordY,
990*35238bceSAndroid Build Coastguard Worker                                                   const Vec2 &fBounds, const Vec4 &result)
991*35238bceSAndroid Build Coastguard Worker {
992*35238bceSAndroid Build Coastguard Worker     // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
993*35238bceSAndroid Build Coastguard Worker     //                           Right now this allows pairing any two valid bilinear quads.
994*35238bceSAndroid Build Coastguard Worker 
995*35238bceSAndroid Build Coastguard Worker     const int w0 = level0.getWidth();
996*35238bceSAndroid Build Coastguard Worker     const int w1 = level1.getWidth();
997*35238bceSAndroid Build Coastguard Worker 
998*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds0 =
999*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coordX, prec.coordBits.x(), prec.uvwBits.x());
1000*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds1 =
1001*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coordX, prec.coordBits.x(), prec.uvwBits.x());
1002*35238bceSAndroid Build Coastguard Worker 
1003*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
1004*35238bceSAndroid Build Coastguard Worker     const int minI0 = deFloorFloatToInt32(uBounds0.x() - 0.5f);
1005*35238bceSAndroid Build Coastguard Worker     const int maxI0 = deFloorFloatToInt32(uBounds0.y() - 0.5f);
1006*35238bceSAndroid Build Coastguard Worker     const int minI1 = deFloorFloatToInt32(uBounds1.x() - 0.5f);
1007*35238bceSAndroid Build Coastguard Worker     const int maxI1 = deFloorFloatToInt32(uBounds1.y() - 0.5f);
1008*35238bceSAndroid Build Coastguard Worker 
1009*35238bceSAndroid Build Coastguard Worker     const TextureChannelClass texClass = getTextureChannelClass(level0.getFormat().type);
1010*35238bceSAndroid Build Coastguard Worker     const float cSearchStep            = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ?
1011*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForUnorm(prec) :
1012*35238bceSAndroid Build Coastguard Worker                                          texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ?
1013*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForSnorm(prec) :
1014*35238bceSAndroid Build Coastguard Worker                                              0.0f; // Step is computed for floating-point quads based on texel values.
1015*35238bceSAndroid Build Coastguard Worker 
1016*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
1017*35238bceSAndroid Build Coastguard Worker               texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || texClass == TEXTURECHANNELCLASS_FLOATING_POINT ||
1018*35238bceSAndroid Build Coastguard Worker               sampler.reductionMode != Sampler::WEIGHTED_AVERAGE);
1019*35238bceSAndroid Build Coastguard Worker 
1020*35238bceSAndroid Build Coastguard Worker     for (int i0 = minI0; i0 <= maxI0; i0++)
1021*35238bceSAndroid Build Coastguard Worker     {
1022*35238bceSAndroid Build Coastguard Worker         ColorLine line0;
1023*35238bceSAndroid Build Coastguard Worker         float searchStep0;
1024*35238bceSAndroid Build Coastguard Worker 
1025*35238bceSAndroid Build Coastguard Worker         {
1026*35238bceSAndroid Build Coastguard Worker             const int x0 = wrap(sampler.wrapS, i0, w0);
1027*35238bceSAndroid Build Coastguard Worker             const int x1 = wrap(sampler.wrapS, i0 + 1, w0);
1028*35238bceSAndroid Build Coastguard Worker             lookupLine(line0, level0, sampler, x0, x1, coordY);
1029*35238bceSAndroid Build Coastguard Worker 
1030*35238bceSAndroid Build Coastguard Worker             if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1031*35238bceSAndroid Build Coastguard Worker                 searchStep0 = computeBilinearSearchStepFromFloatLine(prec, line0);
1032*35238bceSAndroid Build Coastguard Worker             else
1033*35238bceSAndroid Build Coastguard Worker                 searchStep0 = cSearchStep;
1034*35238bceSAndroid Build Coastguard Worker         }
1035*35238bceSAndroid Build Coastguard Worker 
1036*35238bceSAndroid Build Coastguard Worker         const float minA0 = de::clamp((uBounds0.x() - 0.5f) - float(i0), 0.0f, 1.0f);
1037*35238bceSAndroid Build Coastguard Worker         const float maxA0 = de::clamp((uBounds0.y() - 0.5f) - float(i0), 0.0f, 1.0f);
1038*35238bceSAndroid Build Coastguard Worker 
1039*35238bceSAndroid Build Coastguard Worker         for (int i1 = minI1; i1 <= maxI1; i1++)
1040*35238bceSAndroid Build Coastguard Worker         {
1041*35238bceSAndroid Build Coastguard Worker             ColorLine line1;
1042*35238bceSAndroid Build Coastguard Worker             float searchStep1;
1043*35238bceSAndroid Build Coastguard Worker 
1044*35238bceSAndroid Build Coastguard Worker             {
1045*35238bceSAndroid Build Coastguard Worker                 const int x0 = wrap(sampler.wrapS, i1, w1);
1046*35238bceSAndroid Build Coastguard Worker                 const int x1 = wrap(sampler.wrapS, i1 + 1, w1);
1047*35238bceSAndroid Build Coastguard Worker                 lookupLine(line1, level1, sampler, x0, x1, coordY);
1048*35238bceSAndroid Build Coastguard Worker 
1049*35238bceSAndroid Build Coastguard Worker                 if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1050*35238bceSAndroid Build Coastguard Worker                     searchStep1 = computeBilinearSearchStepFromFloatLine(prec, line1);
1051*35238bceSAndroid Build Coastguard Worker                 else
1052*35238bceSAndroid Build Coastguard Worker                     searchStep1 = cSearchStep;
1053*35238bceSAndroid Build Coastguard Worker             }
1054*35238bceSAndroid Build Coastguard Worker 
1055*35238bceSAndroid Build Coastguard Worker             const float minA1 = de::clamp((uBounds1.x() - 0.5f) - float(i1), 0.0f, 1.0f);
1056*35238bceSAndroid Build Coastguard Worker             const float maxA1 = de::clamp((uBounds1.y() - 0.5f) - float(i1), 0.0f, 1.0f);
1057*35238bceSAndroid Build Coastguard Worker 
1058*35238bceSAndroid Build Coastguard Worker             if (is1DTrilinearFilterResultValid(prec, line0, line1, Vec2(minA0, maxA0), Vec2(minA1, maxA1), fBounds,
1059*35238bceSAndroid Build Coastguard Worker                                                de::min(searchStep0, searchStep1), result))
1060*35238bceSAndroid Build Coastguard Worker                 return true;
1061*35238bceSAndroid Build Coastguard Worker         }
1062*35238bceSAndroid Build Coastguard Worker     }
1063*35238bceSAndroid Build Coastguard Worker 
1064*35238bceSAndroid Build Coastguard Worker     return false;
1065*35238bceSAndroid Build Coastguard Worker }
1066*35238bceSAndroid Build Coastguard Worker 
isLinearMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const LookupPrecision & prec,const Vec2 & coord,const int coordZ,const Vec2 & fBounds,const Vec4 & result)1067*35238bceSAndroid Build Coastguard Worker static bool isLinearMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0,
1068*35238bceSAndroid Build Coastguard Worker                                                   const ConstPixelBufferAccess &level1, const Sampler &sampler,
1069*35238bceSAndroid Build Coastguard Worker                                                   const LookupPrecision &prec, const Vec2 &coord, const int coordZ,
1070*35238bceSAndroid Build Coastguard Worker                                                   const Vec2 &fBounds, const Vec4 &result)
1071*35238bceSAndroid Build Coastguard Worker {
1072*35238bceSAndroid Build Coastguard Worker     // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
1073*35238bceSAndroid Build Coastguard Worker     //                           Right now this allows pairing any two valid bilinear quads.
1074*35238bceSAndroid Build Coastguard Worker 
1075*35238bceSAndroid Build Coastguard Worker     const int w0 = level0.getWidth();
1076*35238bceSAndroid Build Coastguard Worker     const int w1 = level1.getWidth();
1077*35238bceSAndroid Build Coastguard Worker     const int h0 = level0.getHeight();
1078*35238bceSAndroid Build Coastguard Worker     const int h1 = level1.getHeight();
1079*35238bceSAndroid Build Coastguard Worker 
1080*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds0 =
1081*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1082*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds1 =
1083*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1084*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds0 =
1085*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
1086*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds1 =
1087*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
1088*35238bceSAndroid Build Coastguard Worker 
1089*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
1090*35238bceSAndroid Build Coastguard Worker     const int minI0 = deFloorFloatToInt32(uBounds0.x() - 0.5f);
1091*35238bceSAndroid Build Coastguard Worker     const int maxI0 = deFloorFloatToInt32(uBounds0.y() - 0.5f);
1092*35238bceSAndroid Build Coastguard Worker     const int minI1 = deFloorFloatToInt32(uBounds1.x() - 0.5f);
1093*35238bceSAndroid Build Coastguard Worker     const int maxI1 = deFloorFloatToInt32(uBounds1.y() - 0.5f);
1094*35238bceSAndroid Build Coastguard Worker     const int minJ0 = deFloorFloatToInt32(vBounds0.x() - 0.5f);
1095*35238bceSAndroid Build Coastguard Worker     const int maxJ0 = deFloorFloatToInt32(vBounds0.y() - 0.5f);
1096*35238bceSAndroid Build Coastguard Worker     const int minJ1 = deFloorFloatToInt32(vBounds1.x() - 0.5f);
1097*35238bceSAndroid Build Coastguard Worker     const int maxJ1 = deFloorFloatToInt32(vBounds1.y() - 0.5f);
1098*35238bceSAndroid Build Coastguard Worker 
1099*35238bceSAndroid Build Coastguard Worker     const TextureChannelClass texClass = getTextureChannelClass(level0.getFormat().type);
1100*35238bceSAndroid Build Coastguard Worker     const float cSearchStep            = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ?
1101*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForUnorm(prec) :
1102*35238bceSAndroid Build Coastguard Worker                                          texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ?
1103*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForSnorm(prec) :
1104*35238bceSAndroid Build Coastguard Worker                                              0.0f; // Step is computed for floating-point quads based on texel values.
1105*35238bceSAndroid Build Coastguard Worker 
1106*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
1107*35238bceSAndroid Build Coastguard Worker               texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || texClass == TEXTURECHANNELCLASS_FLOATING_POINT ||
1108*35238bceSAndroid Build Coastguard Worker               sampler.reductionMode != Sampler::WEIGHTED_AVERAGE);
1109*35238bceSAndroid Build Coastguard Worker 
1110*35238bceSAndroid Build Coastguard Worker     for (int j0 = minJ0; j0 <= maxJ0; j0++)
1111*35238bceSAndroid Build Coastguard Worker     {
1112*35238bceSAndroid Build Coastguard Worker         for (int i0 = minI0; i0 <= maxI0; i0++)
1113*35238bceSAndroid Build Coastguard Worker         {
1114*35238bceSAndroid Build Coastguard Worker             ColorQuad quad0;
1115*35238bceSAndroid Build Coastguard Worker             float searchStep0;
1116*35238bceSAndroid Build Coastguard Worker 
1117*35238bceSAndroid Build Coastguard Worker             {
1118*35238bceSAndroid Build Coastguard Worker                 const int x0 = wrap(sampler.wrapS, i0, w0);
1119*35238bceSAndroid Build Coastguard Worker                 const int x1 = wrap(sampler.wrapS, i0 + 1, w0);
1120*35238bceSAndroid Build Coastguard Worker                 const int y0 = wrap(sampler.wrapT, j0, h0);
1121*35238bceSAndroid Build Coastguard Worker                 const int y1 = wrap(sampler.wrapT, j0 + 1, h0);
1122*35238bceSAndroid Build Coastguard Worker                 lookupQuad(quad0, level0, sampler, x0, x1, y0, y1, coordZ);
1123*35238bceSAndroid Build Coastguard Worker 
1124*35238bceSAndroid Build Coastguard Worker                 if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1125*35238bceSAndroid Build Coastguard Worker                     searchStep0 = computeBilinearSearchStepFromFloatQuad(prec, quad0);
1126*35238bceSAndroid Build Coastguard Worker                 else
1127*35238bceSAndroid Build Coastguard Worker                     searchStep0 = cSearchStep;
1128*35238bceSAndroid Build Coastguard Worker             }
1129*35238bceSAndroid Build Coastguard Worker 
1130*35238bceSAndroid Build Coastguard Worker             const float minA0 = de::clamp((uBounds0.x() - 0.5f) - float(i0), 0.0f, 1.0f);
1131*35238bceSAndroid Build Coastguard Worker             const float maxA0 = de::clamp((uBounds0.y() - 0.5f) - float(i0), 0.0f, 1.0f);
1132*35238bceSAndroid Build Coastguard Worker             const float minB0 = de::clamp((vBounds0.x() - 0.5f) - float(j0), 0.0f, 1.0f);
1133*35238bceSAndroid Build Coastguard Worker             const float maxB0 = de::clamp((vBounds0.y() - 0.5f) - float(j0), 0.0f, 1.0f);
1134*35238bceSAndroid Build Coastguard Worker 
1135*35238bceSAndroid Build Coastguard Worker             for (int j1 = minJ1; j1 <= maxJ1; j1++)
1136*35238bceSAndroid Build Coastguard Worker             {
1137*35238bceSAndroid Build Coastguard Worker                 for (int i1 = minI1; i1 <= maxI1; i1++)
1138*35238bceSAndroid Build Coastguard Worker                 {
1139*35238bceSAndroid Build Coastguard Worker                     ColorQuad quad1;
1140*35238bceSAndroid Build Coastguard Worker                     float searchStep1;
1141*35238bceSAndroid Build Coastguard Worker 
1142*35238bceSAndroid Build Coastguard Worker                     {
1143*35238bceSAndroid Build Coastguard Worker                         const int x0 = wrap(sampler.wrapS, i1, w1);
1144*35238bceSAndroid Build Coastguard Worker                         const int x1 = wrap(sampler.wrapS, i1 + 1, w1);
1145*35238bceSAndroid Build Coastguard Worker                         const int y0 = wrap(sampler.wrapT, j1, h1);
1146*35238bceSAndroid Build Coastguard Worker                         const int y1 = wrap(sampler.wrapT, j1 + 1, h1);
1147*35238bceSAndroid Build Coastguard Worker                         lookupQuad(quad1, level1, sampler, x0, x1, y0, y1, coordZ);
1148*35238bceSAndroid Build Coastguard Worker 
1149*35238bceSAndroid Build Coastguard Worker                         if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1150*35238bceSAndroid Build Coastguard Worker                             searchStep1 = computeBilinearSearchStepFromFloatQuad(prec, quad1);
1151*35238bceSAndroid Build Coastguard Worker                         else
1152*35238bceSAndroid Build Coastguard Worker                             searchStep1 = cSearchStep;
1153*35238bceSAndroid Build Coastguard Worker                     }
1154*35238bceSAndroid Build Coastguard Worker 
1155*35238bceSAndroid Build Coastguard Worker                     const float minA1 = de::clamp((uBounds1.x() - 0.5f) - float(i1), 0.0f, 1.0f);
1156*35238bceSAndroid Build Coastguard Worker                     const float maxA1 = de::clamp((uBounds1.y() - 0.5f) - float(i1), 0.0f, 1.0f);
1157*35238bceSAndroid Build Coastguard Worker                     const float minB1 = de::clamp((vBounds1.x() - 0.5f) - float(j1), 0.0f, 1.0f);
1158*35238bceSAndroid Build Coastguard Worker                     const float maxB1 = de::clamp((vBounds1.y() - 0.5f) - float(j1), 0.0f, 1.0f);
1159*35238bceSAndroid Build Coastguard Worker 
1160*35238bceSAndroid Build Coastguard Worker                     if (is2DTrilinearFilterResultValid(prec, quad0, quad1, Vec2(minA0, maxA0), Vec2(minB0, maxB0),
1161*35238bceSAndroid Build Coastguard Worker                                                        Vec2(minA1, maxA1), Vec2(minB1, maxB1), fBounds,
1162*35238bceSAndroid Build Coastguard Worker                                                        de::min(searchStep0, searchStep1), result))
1163*35238bceSAndroid Build Coastguard Worker                         return true;
1164*35238bceSAndroid Build Coastguard Worker                 }
1165*35238bceSAndroid Build Coastguard Worker             }
1166*35238bceSAndroid Build Coastguard Worker         }
1167*35238bceSAndroid Build Coastguard Worker     }
1168*35238bceSAndroid Build Coastguard Worker 
1169*35238bceSAndroid Build Coastguard Worker     return false;
1170*35238bceSAndroid Build Coastguard Worker }
1171*35238bceSAndroid Build Coastguard Worker 
isLinearMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const LookupPrecision & prec,const Vec3 & coord,const Vec2 & fBounds,const Vec4 & result)1172*35238bceSAndroid Build Coastguard Worker static bool isLinearMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0,
1173*35238bceSAndroid Build Coastguard Worker                                                   const ConstPixelBufferAccess &level1, const Sampler &sampler,
1174*35238bceSAndroid Build Coastguard Worker                                                   const LookupPrecision &prec, const Vec3 &coord, const Vec2 &fBounds,
1175*35238bceSAndroid Build Coastguard Worker                                                   const Vec4 &result)
1176*35238bceSAndroid Build Coastguard Worker {
1177*35238bceSAndroid Build Coastguard Worker     // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
1178*35238bceSAndroid Build Coastguard Worker     //                           Right now this allows pairing any two valid bilinear quads.
1179*35238bceSAndroid Build Coastguard Worker 
1180*35238bceSAndroid Build Coastguard Worker     const int w0 = level0.getWidth();
1181*35238bceSAndroid Build Coastguard Worker     const int w1 = level1.getWidth();
1182*35238bceSAndroid Build Coastguard Worker     const int h0 = level0.getHeight();
1183*35238bceSAndroid Build Coastguard Worker     const int h1 = level1.getHeight();
1184*35238bceSAndroid Build Coastguard Worker     const int d0 = level0.getDepth();
1185*35238bceSAndroid Build Coastguard Worker     const int d1 = level1.getDepth();
1186*35238bceSAndroid Build Coastguard Worker 
1187*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds0 =
1188*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1189*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds1 =
1190*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1191*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds0 =
1192*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
1193*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds1 =
1194*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
1195*35238bceSAndroid Build Coastguard Worker     const Vec2 wBounds0 =
1196*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, d0, coord.z(), prec.coordBits.z(), prec.uvwBits.z());
1197*35238bceSAndroid Build Coastguard Worker     const Vec2 wBounds1 =
1198*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, d1, coord.z(), prec.coordBits.z(), prec.uvwBits.z());
1199*35238bceSAndroid Build Coastguard Worker 
1200*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
1201*35238bceSAndroid Build Coastguard Worker     const int minI0 = deFloorFloatToInt32(uBounds0.x() - 0.5f);
1202*35238bceSAndroid Build Coastguard Worker     const int maxI0 = deFloorFloatToInt32(uBounds0.y() - 0.5f);
1203*35238bceSAndroid Build Coastguard Worker     const int minI1 = deFloorFloatToInt32(uBounds1.x() - 0.5f);
1204*35238bceSAndroid Build Coastguard Worker     const int maxI1 = deFloorFloatToInt32(uBounds1.y() - 0.5f);
1205*35238bceSAndroid Build Coastguard Worker     const int minJ0 = deFloorFloatToInt32(vBounds0.x() - 0.5f);
1206*35238bceSAndroid Build Coastguard Worker     const int maxJ0 = deFloorFloatToInt32(vBounds0.y() - 0.5f);
1207*35238bceSAndroid Build Coastguard Worker     const int minJ1 = deFloorFloatToInt32(vBounds1.x() - 0.5f);
1208*35238bceSAndroid Build Coastguard Worker     const int maxJ1 = deFloorFloatToInt32(vBounds1.y() - 0.5f);
1209*35238bceSAndroid Build Coastguard Worker     const int minK0 = deFloorFloatToInt32(wBounds0.x() - 0.5f);
1210*35238bceSAndroid Build Coastguard Worker     const int maxK0 = deFloorFloatToInt32(wBounds0.y() - 0.5f);
1211*35238bceSAndroid Build Coastguard Worker     const int minK1 = deFloorFloatToInt32(wBounds1.x() - 0.5f);
1212*35238bceSAndroid Build Coastguard Worker     const int maxK1 = deFloorFloatToInt32(wBounds1.y() - 0.5f);
1213*35238bceSAndroid Build Coastguard Worker 
1214*35238bceSAndroid Build Coastguard Worker     const TextureChannelClass texClass = getTextureChannelClass(level0.getFormat().type);
1215*35238bceSAndroid Build Coastguard Worker     const float cSearchStep            = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ?
1216*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForUnorm(prec) :
1217*35238bceSAndroid Build Coastguard Worker                                          texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ?
1218*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForSnorm(prec) :
1219*35238bceSAndroid Build Coastguard Worker                                              0.0f; // Step is computed for floating-point quads based on texel values.
1220*35238bceSAndroid Build Coastguard Worker 
1221*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
1222*35238bceSAndroid Build Coastguard Worker               texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || texClass == TEXTURECHANNELCLASS_FLOATING_POINT ||
1223*35238bceSAndroid Build Coastguard Worker               sampler.reductionMode != Sampler::WEIGHTED_AVERAGE);
1224*35238bceSAndroid Build Coastguard Worker 
1225*35238bceSAndroid Build Coastguard Worker     for (int k0 = minK0; k0 <= maxK0; k0++)
1226*35238bceSAndroid Build Coastguard Worker     {
1227*35238bceSAndroid Build Coastguard Worker         for (int j0 = minJ0; j0 <= maxJ0; j0++)
1228*35238bceSAndroid Build Coastguard Worker         {
1229*35238bceSAndroid Build Coastguard Worker             for (int i0 = minI0; i0 <= maxI0; i0++)
1230*35238bceSAndroid Build Coastguard Worker             {
1231*35238bceSAndroid Build Coastguard Worker                 ColorQuad quad00, quad01;
1232*35238bceSAndroid Build Coastguard Worker                 float searchStep0;
1233*35238bceSAndroid Build Coastguard Worker 
1234*35238bceSAndroid Build Coastguard Worker                 {
1235*35238bceSAndroid Build Coastguard Worker                     const int x0 = wrap(sampler.wrapS, i0, w0);
1236*35238bceSAndroid Build Coastguard Worker                     const int x1 = wrap(sampler.wrapS, i0 + 1, w0);
1237*35238bceSAndroid Build Coastguard Worker                     const int y0 = wrap(sampler.wrapT, j0, h0);
1238*35238bceSAndroid Build Coastguard Worker                     const int y1 = wrap(sampler.wrapT, j0 + 1, h0);
1239*35238bceSAndroid Build Coastguard Worker                     const int z0 = wrap(sampler.wrapR, k0, d0);
1240*35238bceSAndroid Build Coastguard Worker                     const int z1 = wrap(sampler.wrapR, k0 + 1, d0);
1241*35238bceSAndroid Build Coastguard Worker                     lookupQuad(quad00, level0, sampler, x0, x1, y0, y1, z0);
1242*35238bceSAndroid Build Coastguard Worker                     lookupQuad(quad01, level0, sampler, x0, x1, y0, y1, z1);
1243*35238bceSAndroid Build Coastguard Worker 
1244*35238bceSAndroid Build Coastguard Worker                     if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1245*35238bceSAndroid Build Coastguard Worker                         searchStep0 = de::min(computeBilinearSearchStepFromFloatQuad(prec, quad00),
1246*35238bceSAndroid Build Coastguard Worker                                               computeBilinearSearchStepFromFloatQuad(prec, quad01));
1247*35238bceSAndroid Build Coastguard Worker                     else
1248*35238bceSAndroid Build Coastguard Worker                         searchStep0 = cSearchStep;
1249*35238bceSAndroid Build Coastguard Worker                 }
1250*35238bceSAndroid Build Coastguard Worker 
1251*35238bceSAndroid Build Coastguard Worker                 const float minA0 = de::clamp((uBounds0.x() - 0.5f) - float(i0), 0.0f, 1.0f);
1252*35238bceSAndroid Build Coastguard Worker                 const float maxA0 = de::clamp((uBounds0.y() - 0.5f) - float(i0), 0.0f, 1.0f);
1253*35238bceSAndroid Build Coastguard Worker                 const float minB0 = de::clamp((vBounds0.x() - 0.5f) - float(j0), 0.0f, 1.0f);
1254*35238bceSAndroid Build Coastguard Worker                 const float maxB0 = de::clamp((vBounds0.y() - 0.5f) - float(j0), 0.0f, 1.0f);
1255*35238bceSAndroid Build Coastguard Worker                 const float minC0 = de::clamp((wBounds0.x() - 0.5f) - float(k0), 0.0f, 1.0f);
1256*35238bceSAndroid Build Coastguard Worker                 const float maxC0 = de::clamp((wBounds0.y() - 0.5f) - float(k0), 0.0f, 1.0f);
1257*35238bceSAndroid Build Coastguard Worker 
1258*35238bceSAndroid Build Coastguard Worker                 for (int k1 = minK1; k1 <= maxK1; k1++)
1259*35238bceSAndroid Build Coastguard Worker                 {
1260*35238bceSAndroid Build Coastguard Worker                     for (int j1 = minJ1; j1 <= maxJ1; j1++)
1261*35238bceSAndroid Build Coastguard Worker                     {
1262*35238bceSAndroid Build Coastguard Worker                         for (int i1 = minI1; i1 <= maxI1; i1++)
1263*35238bceSAndroid Build Coastguard Worker                         {
1264*35238bceSAndroid Build Coastguard Worker                             ColorQuad quad10, quad11;
1265*35238bceSAndroid Build Coastguard Worker                             float searchStep1;
1266*35238bceSAndroid Build Coastguard Worker 
1267*35238bceSAndroid Build Coastguard Worker                             {
1268*35238bceSAndroid Build Coastguard Worker                                 const int x0 = wrap(sampler.wrapS, i1, w1);
1269*35238bceSAndroid Build Coastguard Worker                                 const int x1 = wrap(sampler.wrapS, i1 + 1, w1);
1270*35238bceSAndroid Build Coastguard Worker                                 const int y0 = wrap(sampler.wrapT, j1, h1);
1271*35238bceSAndroid Build Coastguard Worker                                 const int y1 = wrap(sampler.wrapT, j1 + 1, h1);
1272*35238bceSAndroid Build Coastguard Worker                                 const int z0 = wrap(sampler.wrapR, k1, d1);
1273*35238bceSAndroid Build Coastguard Worker                                 const int z1 = wrap(sampler.wrapR, k1 + 1, d1);
1274*35238bceSAndroid Build Coastguard Worker                                 lookupQuad(quad10, level1, sampler, x0, x1, y0, y1, z0);
1275*35238bceSAndroid Build Coastguard Worker                                 lookupQuad(quad11, level1, sampler, x0, x1, y0, y1, z1);
1276*35238bceSAndroid Build Coastguard Worker 
1277*35238bceSAndroid Build Coastguard Worker                                 if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1278*35238bceSAndroid Build Coastguard Worker                                     searchStep1 = de::min(computeBilinearSearchStepFromFloatQuad(prec, quad10),
1279*35238bceSAndroid Build Coastguard Worker                                                           computeBilinearSearchStepFromFloatQuad(prec, quad11));
1280*35238bceSAndroid Build Coastguard Worker                                 else
1281*35238bceSAndroid Build Coastguard Worker                                     searchStep1 = cSearchStep;
1282*35238bceSAndroid Build Coastguard Worker                             }
1283*35238bceSAndroid Build Coastguard Worker 
1284*35238bceSAndroid Build Coastguard Worker                             const float minA1 = de::clamp((uBounds1.x() - 0.5f) - float(i1), 0.0f, 1.0f);
1285*35238bceSAndroid Build Coastguard Worker                             const float maxA1 = de::clamp((uBounds1.y() - 0.5f) - float(i1), 0.0f, 1.0f);
1286*35238bceSAndroid Build Coastguard Worker                             const float minB1 = de::clamp((vBounds1.x() - 0.5f) - float(j1), 0.0f, 1.0f);
1287*35238bceSAndroid Build Coastguard Worker                             const float maxB1 = de::clamp((vBounds1.y() - 0.5f) - float(j1), 0.0f, 1.0f);
1288*35238bceSAndroid Build Coastguard Worker                             const float minC1 = de::clamp((wBounds1.x() - 0.5f) - float(k1), 0.0f, 1.0f);
1289*35238bceSAndroid Build Coastguard Worker                             const float maxC1 = de::clamp((wBounds1.y() - 0.5f) - float(k1), 0.0f, 1.0f);
1290*35238bceSAndroid Build Coastguard Worker 
1291*35238bceSAndroid Build Coastguard Worker                             if (is3DTrilinearFilterResultValid(
1292*35238bceSAndroid Build Coastguard Worker                                     prec, quad00, quad01, quad10, quad11, Vec2(minA0, maxA0), Vec2(minB0, maxB0),
1293*35238bceSAndroid Build Coastguard Worker                                     Vec2(minC0, maxC0), Vec2(minA1, maxA1), Vec2(minB1, maxB1), Vec2(minC1, maxC1),
1294*35238bceSAndroid Build Coastguard Worker                                     fBounds, de::min(searchStep0, searchStep1), result))
1295*35238bceSAndroid Build Coastguard Worker                                 return true;
1296*35238bceSAndroid Build Coastguard Worker                         }
1297*35238bceSAndroid Build Coastguard Worker                     }
1298*35238bceSAndroid Build Coastguard Worker                 }
1299*35238bceSAndroid Build Coastguard Worker             }
1300*35238bceSAndroid Build Coastguard Worker         }
1301*35238bceSAndroid Build Coastguard Worker     }
1302*35238bceSAndroid Build Coastguard Worker 
1303*35238bceSAndroid Build Coastguard Worker     return false;
1304*35238bceSAndroid Build Coastguard Worker }
1305*35238bceSAndroid Build Coastguard Worker 
isLevelSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const Sampler::FilterMode filterMode,const LookupPrecision & prec,const float coordX,const int coordY,const Vec4 & result)1306*35238bceSAndroid Build Coastguard Worker static bool isLevelSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler,
1307*35238bceSAndroid Build Coastguard Worker                                      const Sampler::FilterMode filterMode, const LookupPrecision &prec,
1308*35238bceSAndroid Build Coastguard Worker                                      const float coordX, const int coordY, const Vec4 &result)
1309*35238bceSAndroid Build Coastguard Worker {
1310*35238bceSAndroid Build Coastguard Worker     if (filterMode == Sampler::LINEAR)
1311*35238bceSAndroid Build Coastguard Worker         return isLinearSampleResultValid(level, sampler, prec, coordX, coordY, result);
1312*35238bceSAndroid Build Coastguard Worker     else
1313*35238bceSAndroid Build Coastguard Worker         return isNearestSampleResultValid(level, sampler, prec, coordX, coordY, result);
1314*35238bceSAndroid Build Coastguard Worker }
1315*35238bceSAndroid Build Coastguard Worker 
isLevelSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const Sampler::FilterMode filterMode,const LookupPrecision & prec,const Vec2 & coord,const int coordZ,const Vec4 & result)1316*35238bceSAndroid Build Coastguard Worker static bool isLevelSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler,
1317*35238bceSAndroid Build Coastguard Worker                                      const Sampler::FilterMode filterMode, const LookupPrecision &prec,
1318*35238bceSAndroid Build Coastguard Worker                                      const Vec2 &coord, const int coordZ, const Vec4 &result)
1319*35238bceSAndroid Build Coastguard Worker {
1320*35238bceSAndroid Build Coastguard Worker     if (filterMode == Sampler::LINEAR)
1321*35238bceSAndroid Build Coastguard Worker         return isLinearSampleResultValid(level, sampler, prec, coord, coordZ, result);
1322*35238bceSAndroid Build Coastguard Worker     else
1323*35238bceSAndroid Build Coastguard Worker         return isNearestSampleResultValid(level, sampler, prec, coord, coordZ, result);
1324*35238bceSAndroid Build Coastguard Worker }
1325*35238bceSAndroid Build Coastguard Worker 
isMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const Sampler::FilterMode levelFilter,const LookupPrecision & prec,const float coordX,const int coordY,const Vec2 & fBounds,const Vec4 & result)1326*35238bceSAndroid Build Coastguard Worker static bool isMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0, const ConstPixelBufferAccess &level1,
1327*35238bceSAndroid Build Coastguard Worker                                             const Sampler &sampler, const Sampler::FilterMode levelFilter,
1328*35238bceSAndroid Build Coastguard Worker                                             const LookupPrecision &prec, const float coordX, const int coordY,
1329*35238bceSAndroid Build Coastguard Worker                                             const Vec2 &fBounds, const Vec4 &result)
1330*35238bceSAndroid Build Coastguard Worker {
1331*35238bceSAndroid Build Coastguard Worker     if (levelFilter == Sampler::LINEAR)
1332*35238bceSAndroid Build Coastguard Worker         return isLinearMipmapLinearSampleResultValid(level0, level1, sampler, prec, coordX, coordY, fBounds, result);
1333*35238bceSAndroid Build Coastguard Worker     else
1334*35238bceSAndroid Build Coastguard Worker         return isNearestMipmapLinearSampleResultValid(level0, level1, sampler, prec, coordX, coordY, fBounds, result);
1335*35238bceSAndroid Build Coastguard Worker }
1336*35238bceSAndroid Build Coastguard Worker 
isMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const Sampler::FilterMode levelFilter,const LookupPrecision & prec,const Vec2 & coord,const int coordZ,const Vec2 & fBounds,const Vec4 & result)1337*35238bceSAndroid Build Coastguard Worker static bool isMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0, const ConstPixelBufferAccess &level1,
1338*35238bceSAndroid Build Coastguard Worker                                             const Sampler &sampler, const Sampler::FilterMode levelFilter,
1339*35238bceSAndroid Build Coastguard Worker                                             const LookupPrecision &prec, const Vec2 &coord, const int coordZ,
1340*35238bceSAndroid Build Coastguard Worker                                             const Vec2 &fBounds, const Vec4 &result)
1341*35238bceSAndroid Build Coastguard Worker {
1342*35238bceSAndroid Build Coastguard Worker     if (levelFilter == Sampler::LINEAR)
1343*35238bceSAndroid Build Coastguard Worker         return isLinearMipmapLinearSampleResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, result);
1344*35238bceSAndroid Build Coastguard Worker     else
1345*35238bceSAndroid Build Coastguard Worker         return isNearestMipmapLinearSampleResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, result);
1346*35238bceSAndroid Build Coastguard Worker }
1347*35238bceSAndroid Build Coastguard Worker 
isLookupResultValid(const Texture2DView & texture,const Sampler & sampler,const LookupPrecision & prec,const Vec2 & coord,const Vec2 & lodBounds,const Vec4 & result)1348*35238bceSAndroid Build Coastguard Worker bool isLookupResultValid(const Texture2DView &texture, const Sampler &sampler, const LookupPrecision &prec,
1349*35238bceSAndroid Build Coastguard Worker                          const Vec2 &coord, const Vec2 &lodBounds, const Vec4 &result)
1350*35238bceSAndroid Build Coastguard Worker {
1351*35238bceSAndroid Build Coastguard Worker     const float minLod        = lodBounds.x();
1352*35238bceSAndroid Build Coastguard Worker     const float maxLod        = lodBounds.y();
1353*35238bceSAndroid Build Coastguard Worker     const bool canBeMagnified = minLod <= sampler.lodThreshold;
1354*35238bceSAndroid Build Coastguard Worker     const bool canBeMinified  = maxLod > sampler.lodThreshold;
1355*35238bceSAndroid Build Coastguard Worker 
1356*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(isSamplerSupported(sampler));
1357*35238bceSAndroid Build Coastguard Worker 
1358*35238bceSAndroid Build Coastguard Worker     if (canBeMagnified)
1359*35238bceSAndroid Build Coastguard Worker     {
1360*35238bceSAndroid Build Coastguard Worker         if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, result))
1361*35238bceSAndroid Build Coastguard Worker             return true;
1362*35238bceSAndroid Build Coastguard Worker     }
1363*35238bceSAndroid Build Coastguard Worker 
1364*35238bceSAndroid Build Coastguard Worker     if (canBeMinified)
1365*35238bceSAndroid Build Coastguard Worker     {
1366*35238bceSAndroid Build Coastguard Worker         const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1367*35238bceSAndroid Build Coastguard Worker         const bool isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1368*35238bceSAndroid Build Coastguard Worker         const int minTexLevel      = 0;
1369*35238bceSAndroid Build Coastguard Worker         const int maxTexLevel      = texture.getNumLevels() - 1;
1370*35238bceSAndroid Build Coastguard Worker 
1371*35238bceSAndroid Build Coastguard Worker         DE_ASSERT(minTexLevel <= maxTexLevel);
1372*35238bceSAndroid Build Coastguard Worker 
1373*35238bceSAndroid Build Coastguard Worker         if (isLinearMipmap && minTexLevel < maxTexLevel)
1374*35238bceSAndroid Build Coastguard Worker         {
1375*35238bceSAndroid Build Coastguard Worker             const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel - 1);
1376*35238bceSAndroid Build Coastguard Worker             const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel - 1);
1377*35238bceSAndroid Build Coastguard Worker 
1378*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minLevel <= maxLevel);
1379*35238bceSAndroid Build Coastguard Worker 
1380*35238bceSAndroid Build Coastguard Worker             for (int level = minLevel; level <= maxLevel; level++)
1381*35238bceSAndroid Build Coastguard Worker             {
1382*35238bceSAndroid Build Coastguard Worker                 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1383*35238bceSAndroid Build Coastguard Worker                 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1384*35238bceSAndroid Build Coastguard Worker 
1385*35238bceSAndroid Build Coastguard Worker                 if (isMipmapLinearSampleResultValid(texture.getLevel(level), texture.getLevel(level + 1), sampler,
1386*35238bceSAndroid Build Coastguard Worker                                                     getLevelFilter(sampler.minFilter), prec, coord, 0, Vec2(minF, maxF),
1387*35238bceSAndroid Build Coastguard Worker                                                     result))
1388*35238bceSAndroid Build Coastguard Worker                     return true;
1389*35238bceSAndroid Build Coastguard Worker             }
1390*35238bceSAndroid Build Coastguard Worker         }
1391*35238bceSAndroid Build Coastguard Worker         else if (isNearestMipmap)
1392*35238bceSAndroid Build Coastguard Worker         {
1393*35238bceSAndroid Build Coastguard Worker             // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1394*35238bceSAndroid Build Coastguard Worker             //         decision to allow floor(lod + 0.5) as well.
1395*35238bceSAndroid Build Coastguard Worker             const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1396*35238bceSAndroid Build Coastguard Worker             const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1397*35238bceSAndroid Build Coastguard Worker 
1398*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minLevel <= maxLevel);
1399*35238bceSAndroid Build Coastguard Worker 
1400*35238bceSAndroid Build Coastguard Worker             for (int level = minLevel; level <= maxLevel; level++)
1401*35238bceSAndroid Build Coastguard Worker             {
1402*35238bceSAndroid Build Coastguard Worker                 if (isLevelSampleResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec,
1403*35238bceSAndroid Build Coastguard Worker                                              coord, 0, result))
1404*35238bceSAndroid Build Coastguard Worker                     return true;
1405*35238bceSAndroid Build Coastguard Worker             }
1406*35238bceSAndroid Build Coastguard Worker         }
1407*35238bceSAndroid Build Coastguard Worker         else
1408*35238bceSAndroid Build Coastguard Worker         {
1409*35238bceSAndroid Build Coastguard Worker             if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, result))
1410*35238bceSAndroid Build Coastguard Worker                 return true;
1411*35238bceSAndroid Build Coastguard Worker         }
1412*35238bceSAndroid Build Coastguard Worker     }
1413*35238bceSAndroid Build Coastguard Worker 
1414*35238bceSAndroid Build Coastguard Worker     return false;
1415*35238bceSAndroid Build Coastguard Worker }
1416*35238bceSAndroid Build Coastguard Worker 
isLookupResultValid(const Texture1DView & texture,const Sampler & sampler,const LookupPrecision & prec,const float coord,const Vec2 & lodBounds,const Vec4 & result)1417*35238bceSAndroid Build Coastguard Worker bool isLookupResultValid(const Texture1DView &texture, const Sampler &sampler, const LookupPrecision &prec,
1418*35238bceSAndroid Build Coastguard Worker                          const float coord, const Vec2 &lodBounds, const Vec4 &result)
1419*35238bceSAndroid Build Coastguard Worker {
1420*35238bceSAndroid Build Coastguard Worker     const float minLod        = lodBounds.x();
1421*35238bceSAndroid Build Coastguard Worker     const float maxLod        = lodBounds.y();
1422*35238bceSAndroid Build Coastguard Worker     const bool canBeMagnified = minLod <= sampler.lodThreshold;
1423*35238bceSAndroid Build Coastguard Worker     const bool canBeMinified  = maxLod > sampler.lodThreshold;
1424*35238bceSAndroid Build Coastguard Worker 
1425*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(isSamplerSupported(sampler));
1426*35238bceSAndroid Build Coastguard Worker 
1427*35238bceSAndroid Build Coastguard Worker     if (canBeMagnified)
1428*35238bceSAndroid Build Coastguard Worker     {
1429*35238bceSAndroid Build Coastguard Worker         if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, result))
1430*35238bceSAndroid Build Coastguard Worker             return true;
1431*35238bceSAndroid Build Coastguard Worker     }
1432*35238bceSAndroid Build Coastguard Worker 
1433*35238bceSAndroid Build Coastguard Worker     if (canBeMinified)
1434*35238bceSAndroid Build Coastguard Worker     {
1435*35238bceSAndroid Build Coastguard Worker         const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1436*35238bceSAndroid Build Coastguard Worker         const bool isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1437*35238bceSAndroid Build Coastguard Worker         const int minTexLevel      = 0;
1438*35238bceSAndroid Build Coastguard Worker         const int maxTexLevel      = texture.getNumLevels() - 1;
1439*35238bceSAndroid Build Coastguard Worker 
1440*35238bceSAndroid Build Coastguard Worker         DE_ASSERT(minTexLevel <= maxTexLevel);
1441*35238bceSAndroid Build Coastguard Worker 
1442*35238bceSAndroid Build Coastguard Worker         if (isLinearMipmap && minTexLevel < maxTexLevel)
1443*35238bceSAndroid Build Coastguard Worker         {
1444*35238bceSAndroid Build Coastguard Worker             const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel - 1);
1445*35238bceSAndroid Build Coastguard Worker             const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel - 1);
1446*35238bceSAndroid Build Coastguard Worker 
1447*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minLevel <= maxLevel);
1448*35238bceSAndroid Build Coastguard Worker 
1449*35238bceSAndroid Build Coastguard Worker             for (int level = minLevel; level <= maxLevel; level++)
1450*35238bceSAndroid Build Coastguard Worker             {
1451*35238bceSAndroid Build Coastguard Worker                 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1452*35238bceSAndroid Build Coastguard Worker                 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1453*35238bceSAndroid Build Coastguard Worker 
1454*35238bceSAndroid Build Coastguard Worker                 if (isMipmapLinearSampleResultValid(texture.getLevel(level), texture.getLevel(level + 1), sampler,
1455*35238bceSAndroid Build Coastguard Worker                                                     getLevelFilter(sampler.minFilter), prec, coord, 0, Vec2(minF, maxF),
1456*35238bceSAndroid Build Coastguard Worker                                                     result))
1457*35238bceSAndroid Build Coastguard Worker                     return true;
1458*35238bceSAndroid Build Coastguard Worker             }
1459*35238bceSAndroid Build Coastguard Worker         }
1460*35238bceSAndroid Build Coastguard Worker         else if (isNearestMipmap)
1461*35238bceSAndroid Build Coastguard Worker         {
1462*35238bceSAndroid Build Coastguard Worker             // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1463*35238bceSAndroid Build Coastguard Worker             //         decision to allow floor(lod + 0.5) as well.
1464*35238bceSAndroid Build Coastguard Worker             const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1465*35238bceSAndroid Build Coastguard Worker             const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1466*35238bceSAndroid Build Coastguard Worker 
1467*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minLevel <= maxLevel);
1468*35238bceSAndroid Build Coastguard Worker 
1469*35238bceSAndroid Build Coastguard Worker             for (int level = minLevel; level <= maxLevel; level++)
1470*35238bceSAndroid Build Coastguard Worker             {
1471*35238bceSAndroid Build Coastguard Worker                 if (isLevelSampleResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec,
1472*35238bceSAndroid Build Coastguard Worker                                              coord, 0, result))
1473*35238bceSAndroid Build Coastguard Worker                     return true;
1474*35238bceSAndroid Build Coastguard Worker             }
1475*35238bceSAndroid Build Coastguard Worker         }
1476*35238bceSAndroid Build Coastguard Worker         else
1477*35238bceSAndroid Build Coastguard Worker         {
1478*35238bceSAndroid Build Coastguard Worker             if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, result))
1479*35238bceSAndroid Build Coastguard Worker                 return true;
1480*35238bceSAndroid Build Coastguard Worker         }
1481*35238bceSAndroid Build Coastguard Worker     }
1482*35238bceSAndroid Build Coastguard Worker 
1483*35238bceSAndroid Build Coastguard Worker     return false;
1484*35238bceSAndroid Build Coastguard Worker }
1485*35238bceSAndroid Build Coastguard Worker 
isSeamlessLinearSampleResultValid(const ConstPixelBufferAccess (& faces)[CUBEFACE_LAST],const Sampler & sampler,const LookupPrecision & prec,const CubeFaceFloatCoords & coords,const Vec4 & result)1486*35238bceSAndroid Build Coastguard Worker static bool isSeamlessLinearSampleResultValid(const ConstPixelBufferAccess (&faces)[CUBEFACE_LAST],
1487*35238bceSAndroid Build Coastguard Worker                                               const Sampler &sampler, const LookupPrecision &prec,
1488*35238bceSAndroid Build Coastguard Worker                                               const CubeFaceFloatCoords &coords, const Vec4 &result)
1489*35238bceSAndroid Build Coastguard Worker {
1490*35238bceSAndroid Build Coastguard Worker     const int size = faces[coords.face].getWidth();
1491*35238bceSAndroid Build Coastguard Worker 
1492*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds =
1493*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1494*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds =
1495*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1496*35238bceSAndroid Build Coastguard Worker 
1497*35238bceSAndroid Build Coastguard Worker     // Integer coordinate bounds for (x0,y0) - without wrap mode
1498*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x() - 0.5f);
1499*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y() - 0.5f);
1500*35238bceSAndroid Build Coastguard Worker     const int minJ = deFloorFloatToInt32(vBounds.x() - 0.5f);
1501*35238bceSAndroid Build Coastguard Worker     const int maxJ = deFloorFloatToInt32(vBounds.y() - 0.5f);
1502*35238bceSAndroid Build Coastguard Worker 
1503*35238bceSAndroid Build Coastguard Worker     const TextureChannelClass texClass = getTextureChannelClass(faces[coords.face].getFormat().type);
1504*35238bceSAndroid Build Coastguard Worker     float searchStep                   = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ?
1505*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForUnorm(prec) :
1506*35238bceSAndroid Build Coastguard Worker                                          texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ?
1507*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForSnorm(prec) :
1508*35238bceSAndroid Build Coastguard Worker                                              0.0f; // Step is computed for floating-point quads based on texel values.
1509*35238bceSAndroid Build Coastguard Worker 
1510*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
1511*35238bceSAndroid Build Coastguard Worker               texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || texClass == TEXTURECHANNELCLASS_FLOATING_POINT ||
1512*35238bceSAndroid Build Coastguard Worker               sampler.reductionMode != Sampler::WEIGHTED_AVERAGE);
1513*35238bceSAndroid Build Coastguard Worker 
1514*35238bceSAndroid Build Coastguard Worker     for (int j = minJ; j <= maxJ; j++)
1515*35238bceSAndroid Build Coastguard Worker     {
1516*35238bceSAndroid Build Coastguard Worker         for (int i = minI; i <= maxI; i++)
1517*35238bceSAndroid Build Coastguard Worker         {
1518*35238bceSAndroid Build Coastguard Worker             const CubeFaceIntCoords c00 =
1519*35238bceSAndroid Build Coastguard Worker                 remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i + 0, j + 0)), size);
1520*35238bceSAndroid Build Coastguard Worker             const CubeFaceIntCoords c10 =
1521*35238bceSAndroid Build Coastguard Worker                 remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i + 1, j + 0)), size);
1522*35238bceSAndroid Build Coastguard Worker             const CubeFaceIntCoords c01 =
1523*35238bceSAndroid Build Coastguard Worker                 remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i + 0, j + 1)), size);
1524*35238bceSAndroid Build Coastguard Worker             const CubeFaceIntCoords c11 =
1525*35238bceSAndroid Build Coastguard Worker                 remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i + 1, j + 1)), size);
1526*35238bceSAndroid Build Coastguard Worker 
1527*35238bceSAndroid Build Coastguard Worker             // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1528*35238bceSAndroid Build Coastguard Worker             // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
1529*35238bceSAndroid Build Coastguard Worker             if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST ||
1530*35238bceSAndroid Build Coastguard Worker                 c11.face == CUBEFACE_LAST)
1531*35238bceSAndroid Build Coastguard Worker                 return true;
1532*35238bceSAndroid Build Coastguard Worker 
1533*35238bceSAndroid Build Coastguard Worker             // Bounds for filtering factors
1534*35238bceSAndroid Build Coastguard Worker             const float minA = de::clamp((uBounds.x() - 0.5f) - float(i), 0.0f, 1.0f);
1535*35238bceSAndroid Build Coastguard Worker             const float maxA = de::clamp((uBounds.y() - 0.5f) - float(i), 0.0f, 1.0f);
1536*35238bceSAndroid Build Coastguard Worker             const float minB = de::clamp((vBounds.x() - 0.5f) - float(j), 0.0f, 1.0f);
1537*35238bceSAndroid Build Coastguard Worker             const float maxB = de::clamp((vBounds.y() - 0.5f) - float(j), 0.0f, 1.0f);
1538*35238bceSAndroid Build Coastguard Worker 
1539*35238bceSAndroid Build Coastguard Worker             ColorQuad quad;
1540*35238bceSAndroid Build Coastguard Worker             quad.p00 = lookup<float>(faces[c00.face], sampler, c00.s, c00.t, 0);
1541*35238bceSAndroid Build Coastguard Worker             quad.p10 = lookup<float>(faces[c10.face], sampler, c10.s, c10.t, 0);
1542*35238bceSAndroid Build Coastguard Worker             quad.p01 = lookup<float>(faces[c01.face], sampler, c01.s, c01.t, 0);
1543*35238bceSAndroid Build Coastguard Worker             quad.p11 = lookup<float>(faces[c11.face], sampler, c11.s, c11.t, 0);
1544*35238bceSAndroid Build Coastguard Worker 
1545*35238bceSAndroid Build Coastguard Worker             if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1546*35238bceSAndroid Build Coastguard Worker                 searchStep = computeBilinearSearchStepFromFloatQuad(prec, quad);
1547*35238bceSAndroid Build Coastguard Worker 
1548*35238bceSAndroid Build Coastguard Worker             if (sampler.reductionMode == Sampler::WEIGHTED_AVERAGE)
1549*35238bceSAndroid Build Coastguard Worker             {
1550*35238bceSAndroid Build Coastguard Worker                 if (isBilinearRangeValid(prec, quad, Vec2(minA, maxA), Vec2(minB, maxB), searchStep, result))
1551*35238bceSAndroid Build Coastguard Worker                     return true;
1552*35238bceSAndroid Build Coastguard Worker             }
1553*35238bceSAndroid Build Coastguard Worker             else
1554*35238bceSAndroid Build Coastguard Worker             {
1555*35238bceSAndroid Build Coastguard Worker                 if (isReductionValid(prec, quad, sampler.reductionMode, result))
1556*35238bceSAndroid Build Coastguard Worker                     return true;
1557*35238bceSAndroid Build Coastguard Worker             }
1558*35238bceSAndroid Build Coastguard Worker         }
1559*35238bceSAndroid Build Coastguard Worker     }
1560*35238bceSAndroid Build Coastguard Worker 
1561*35238bceSAndroid Build Coastguard Worker     return false;
1562*35238bceSAndroid Build Coastguard Worker }
1563*35238bceSAndroid Build Coastguard Worker 
isSeamplessLinearMipmapLinearSampleResultValid(const ConstPixelBufferAccess (& faces0)[CUBEFACE_LAST],const ConstPixelBufferAccess (& faces1)[CUBEFACE_LAST],const Sampler & sampler,const LookupPrecision & prec,const CubeFaceFloatCoords & coords,const Vec2 & fBounds,const Vec4 & result)1564*35238bceSAndroid Build Coastguard Worker static bool isSeamplessLinearMipmapLinearSampleResultValid(const ConstPixelBufferAccess (&faces0)[CUBEFACE_LAST],
1565*35238bceSAndroid Build Coastguard Worker                                                            const ConstPixelBufferAccess (&faces1)[CUBEFACE_LAST],
1566*35238bceSAndroid Build Coastguard Worker                                                            const Sampler &sampler, const LookupPrecision &prec,
1567*35238bceSAndroid Build Coastguard Worker                                                            const CubeFaceFloatCoords &coords, const Vec2 &fBounds,
1568*35238bceSAndroid Build Coastguard Worker                                                            const Vec4 &result)
1569*35238bceSAndroid Build Coastguard Worker {
1570*35238bceSAndroid Build Coastguard Worker     // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
1571*35238bceSAndroid Build Coastguard Worker     //                           Right now this allows pairing any two valid bilinear quads.
1572*35238bceSAndroid Build Coastguard Worker 
1573*35238bceSAndroid Build Coastguard Worker     const int size0 = faces0[coords.face].getWidth();
1574*35238bceSAndroid Build Coastguard Worker     const int size1 = faces1[coords.face].getWidth();
1575*35238bceSAndroid Build Coastguard Worker 
1576*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.s, prec.coordBits.x(),
1577*35238bceSAndroid Build Coastguard Worker                                                           prec.uvwBits.x());
1578*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.s, prec.coordBits.x(),
1579*35238bceSAndroid Build Coastguard Worker                                                           prec.uvwBits.x());
1580*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.t, prec.coordBits.y(),
1581*35238bceSAndroid Build Coastguard Worker                                                           prec.uvwBits.y());
1582*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.t, prec.coordBits.y(),
1583*35238bceSAndroid Build Coastguard Worker                                                           prec.uvwBits.y());
1584*35238bceSAndroid Build Coastguard Worker 
1585*35238bceSAndroid Build Coastguard Worker     // Integer coordinates - without wrap mode
1586*35238bceSAndroid Build Coastguard Worker     const int minI0 = deFloorFloatToInt32(uBounds0.x() - 0.5f);
1587*35238bceSAndroid Build Coastguard Worker     const int maxI0 = deFloorFloatToInt32(uBounds0.y() - 0.5f);
1588*35238bceSAndroid Build Coastguard Worker     const int minI1 = deFloorFloatToInt32(uBounds1.x() - 0.5f);
1589*35238bceSAndroid Build Coastguard Worker     const int maxI1 = deFloorFloatToInt32(uBounds1.y() - 0.5f);
1590*35238bceSAndroid Build Coastguard Worker     const int minJ0 = deFloorFloatToInt32(vBounds0.x() - 0.5f);
1591*35238bceSAndroid Build Coastguard Worker     const int maxJ0 = deFloorFloatToInt32(vBounds0.y() - 0.5f);
1592*35238bceSAndroid Build Coastguard Worker     const int minJ1 = deFloorFloatToInt32(vBounds1.x() - 0.5f);
1593*35238bceSAndroid Build Coastguard Worker     const int maxJ1 = deFloorFloatToInt32(vBounds1.y() - 0.5f);
1594*35238bceSAndroid Build Coastguard Worker 
1595*35238bceSAndroid Build Coastguard Worker     const TextureChannelClass texClass = getTextureChannelClass(faces0[coords.face].getFormat().type);
1596*35238bceSAndroid Build Coastguard Worker     const float cSearchStep            = texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ?
1597*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForUnorm(prec) :
1598*35238bceSAndroid Build Coastguard Worker                                          texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ?
1599*35238bceSAndroid Build Coastguard Worker                                              computeBilinearSearchStepForSnorm(prec) :
1600*35238bceSAndroid Build Coastguard Worker                                              0.0f; // Step is computed for floating-point quads based on texel values.
1601*35238bceSAndroid Build Coastguard Worker 
1602*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(texClass == TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
1603*35238bceSAndroid Build Coastguard Worker               texClass == TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || texClass == TEXTURECHANNELCLASS_FLOATING_POINT ||
1604*35238bceSAndroid Build Coastguard Worker               sampler.reductionMode != Sampler::WEIGHTED_AVERAGE);
1605*35238bceSAndroid Build Coastguard Worker 
1606*35238bceSAndroid Build Coastguard Worker     for (int j0 = minJ0; j0 <= maxJ0; j0++)
1607*35238bceSAndroid Build Coastguard Worker     {
1608*35238bceSAndroid Build Coastguard Worker         for (int i0 = minI0; i0 <= maxI0; i0++)
1609*35238bceSAndroid Build Coastguard Worker         {
1610*35238bceSAndroid Build Coastguard Worker             ColorQuad quad0;
1611*35238bceSAndroid Build Coastguard Worker             float searchStep0;
1612*35238bceSAndroid Build Coastguard Worker 
1613*35238bceSAndroid Build Coastguard Worker             {
1614*35238bceSAndroid Build Coastguard Worker                 const CubeFaceIntCoords c00 =
1615*35238bceSAndroid Build Coastguard Worker                     remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0 + 0, j0 + 0)), size0);
1616*35238bceSAndroid Build Coastguard Worker                 const CubeFaceIntCoords c10 =
1617*35238bceSAndroid Build Coastguard Worker                     remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0 + 1, j0 + 0)), size0);
1618*35238bceSAndroid Build Coastguard Worker                 const CubeFaceIntCoords c01 =
1619*35238bceSAndroid Build Coastguard Worker                     remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0 + 0, j0 + 1)), size0);
1620*35238bceSAndroid Build Coastguard Worker                 const CubeFaceIntCoords c11 =
1621*35238bceSAndroid Build Coastguard Worker                     remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0 + 1, j0 + 1)), size0);
1622*35238bceSAndroid Build Coastguard Worker 
1623*35238bceSAndroid Build Coastguard Worker                 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1624*35238bceSAndroid Build Coastguard Worker                 // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
1625*35238bceSAndroid Build Coastguard Worker                 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST ||
1626*35238bceSAndroid Build Coastguard Worker                     c11.face == CUBEFACE_LAST)
1627*35238bceSAndroid Build Coastguard Worker                     return true;
1628*35238bceSAndroid Build Coastguard Worker 
1629*35238bceSAndroid Build Coastguard Worker                 quad0.p00 = lookup<float>(faces0[c00.face], sampler, c00.s, c00.t, 0);
1630*35238bceSAndroid Build Coastguard Worker                 quad0.p10 = lookup<float>(faces0[c10.face], sampler, c10.s, c10.t, 0);
1631*35238bceSAndroid Build Coastguard Worker                 quad0.p01 = lookup<float>(faces0[c01.face], sampler, c01.s, c01.t, 0);
1632*35238bceSAndroid Build Coastguard Worker                 quad0.p11 = lookup<float>(faces0[c11.face], sampler, c11.s, c11.t, 0);
1633*35238bceSAndroid Build Coastguard Worker 
1634*35238bceSAndroid Build Coastguard Worker                 if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1635*35238bceSAndroid Build Coastguard Worker                     searchStep0 = computeBilinearSearchStepFromFloatQuad(prec, quad0);
1636*35238bceSAndroid Build Coastguard Worker                 else
1637*35238bceSAndroid Build Coastguard Worker                     searchStep0 = cSearchStep;
1638*35238bceSAndroid Build Coastguard Worker             }
1639*35238bceSAndroid Build Coastguard Worker 
1640*35238bceSAndroid Build Coastguard Worker             const float minA0 = de::clamp((uBounds0.x() - 0.5f) - float(i0), 0.0f, 1.0f);
1641*35238bceSAndroid Build Coastguard Worker             const float maxA0 = de::clamp((uBounds0.y() - 0.5f) - float(i0), 0.0f, 1.0f);
1642*35238bceSAndroid Build Coastguard Worker             const float minB0 = de::clamp((vBounds0.x() - 0.5f) - float(j0), 0.0f, 1.0f);
1643*35238bceSAndroid Build Coastguard Worker             const float maxB0 = de::clamp((vBounds0.y() - 0.5f) - float(j0), 0.0f, 1.0f);
1644*35238bceSAndroid Build Coastguard Worker 
1645*35238bceSAndroid Build Coastguard Worker             for (int j1 = minJ1; j1 <= maxJ1; j1++)
1646*35238bceSAndroid Build Coastguard Worker             {
1647*35238bceSAndroid Build Coastguard Worker                 for (int i1 = minI1; i1 <= maxI1; i1++)
1648*35238bceSAndroid Build Coastguard Worker                 {
1649*35238bceSAndroid Build Coastguard Worker                     ColorQuad quad1;
1650*35238bceSAndroid Build Coastguard Worker                     float searchStep1;
1651*35238bceSAndroid Build Coastguard Worker 
1652*35238bceSAndroid Build Coastguard Worker                     {
1653*35238bceSAndroid Build Coastguard Worker                         const CubeFaceIntCoords c00 =
1654*35238bceSAndroid Build Coastguard Worker                             remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1 + 0, j1 + 0)), size1);
1655*35238bceSAndroid Build Coastguard Worker                         const CubeFaceIntCoords c10 =
1656*35238bceSAndroid Build Coastguard Worker                             remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1 + 1, j1 + 0)), size1);
1657*35238bceSAndroid Build Coastguard Worker                         const CubeFaceIntCoords c01 =
1658*35238bceSAndroid Build Coastguard Worker                             remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1 + 0, j1 + 1)), size1);
1659*35238bceSAndroid Build Coastguard Worker                         const CubeFaceIntCoords c11 =
1660*35238bceSAndroid Build Coastguard Worker                             remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1 + 1, j1 + 1)), size1);
1661*35238bceSAndroid Build Coastguard Worker 
1662*35238bceSAndroid Build Coastguard Worker                         if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST ||
1663*35238bceSAndroid Build Coastguard Worker                             c11.face == CUBEFACE_LAST)
1664*35238bceSAndroid Build Coastguard Worker                             return true;
1665*35238bceSAndroid Build Coastguard Worker 
1666*35238bceSAndroid Build Coastguard Worker                         quad1.p00 = lookup<float>(faces1[c00.face], sampler, c00.s, c00.t, 0);
1667*35238bceSAndroid Build Coastguard Worker                         quad1.p10 = lookup<float>(faces1[c10.face], sampler, c10.s, c10.t, 0);
1668*35238bceSAndroid Build Coastguard Worker                         quad1.p01 = lookup<float>(faces1[c01.face], sampler, c01.s, c01.t, 0);
1669*35238bceSAndroid Build Coastguard Worker                         quad1.p11 = lookup<float>(faces1[c11.face], sampler, c11.s, c11.t, 0);
1670*35238bceSAndroid Build Coastguard Worker 
1671*35238bceSAndroid Build Coastguard Worker                         if (texClass == TEXTURECHANNELCLASS_FLOATING_POINT)
1672*35238bceSAndroid Build Coastguard Worker                             searchStep1 = computeBilinearSearchStepFromFloatQuad(prec, quad1);
1673*35238bceSAndroid Build Coastguard Worker                         else
1674*35238bceSAndroid Build Coastguard Worker                             searchStep1 = cSearchStep;
1675*35238bceSAndroid Build Coastguard Worker                     }
1676*35238bceSAndroid Build Coastguard Worker 
1677*35238bceSAndroid Build Coastguard Worker                     const float minA1 = de::clamp((uBounds1.x() - 0.5f) - float(i1), 0.0f, 1.0f);
1678*35238bceSAndroid Build Coastguard Worker                     const float maxA1 = de::clamp((uBounds1.y() - 0.5f) - float(i1), 0.0f, 1.0f);
1679*35238bceSAndroid Build Coastguard Worker                     const float minB1 = de::clamp((vBounds1.x() - 0.5f) - float(j1), 0.0f, 1.0f);
1680*35238bceSAndroid Build Coastguard Worker                     const float maxB1 = de::clamp((vBounds1.y() - 0.5f) - float(j1), 0.0f, 1.0f);
1681*35238bceSAndroid Build Coastguard Worker 
1682*35238bceSAndroid Build Coastguard Worker                     if (is2DTrilinearFilterResultValid(prec, quad0, quad1, Vec2(minA0, maxA0), Vec2(minB0, maxB0),
1683*35238bceSAndroid Build Coastguard Worker                                                        Vec2(minA1, maxA1), Vec2(minB1, maxB1), fBounds,
1684*35238bceSAndroid Build Coastguard Worker                                                        de::min(searchStep0, searchStep1), result))
1685*35238bceSAndroid Build Coastguard Worker                         return true;
1686*35238bceSAndroid Build Coastguard Worker                 }
1687*35238bceSAndroid Build Coastguard Worker             }
1688*35238bceSAndroid Build Coastguard Worker         }
1689*35238bceSAndroid Build Coastguard Worker     }
1690*35238bceSAndroid Build Coastguard Worker 
1691*35238bceSAndroid Build Coastguard Worker     return false;
1692*35238bceSAndroid Build Coastguard Worker }
1693*35238bceSAndroid Build Coastguard Worker 
isCubeLevelSampleResultValid(const ConstPixelBufferAccess (& level)[CUBEFACE_LAST],const Sampler & sampler,const Sampler::FilterMode filterMode,const LookupPrecision & prec,const CubeFaceFloatCoords & coords,const Vec4 & result)1694*35238bceSAndroid Build Coastguard Worker static bool isCubeLevelSampleResultValid(const ConstPixelBufferAccess (&level)[CUBEFACE_LAST], const Sampler &sampler,
1695*35238bceSAndroid Build Coastguard Worker                                          const Sampler::FilterMode filterMode, const LookupPrecision &prec,
1696*35238bceSAndroid Build Coastguard Worker                                          const CubeFaceFloatCoords &coords, const Vec4 &result)
1697*35238bceSAndroid Build Coastguard Worker {
1698*35238bceSAndroid Build Coastguard Worker     if (filterMode == Sampler::LINEAR)
1699*35238bceSAndroid Build Coastguard Worker     {
1700*35238bceSAndroid Build Coastguard Worker         if (sampler.seamlessCubeMap)
1701*35238bceSAndroid Build Coastguard Worker             return isSeamlessLinearSampleResultValid(level, sampler, prec, coords, result);
1702*35238bceSAndroid Build Coastguard Worker         else
1703*35238bceSAndroid Build Coastguard Worker             return isLinearSampleResultValid(level[coords.face], sampler, prec, Vec2(coords.s, coords.t), 0, result);
1704*35238bceSAndroid Build Coastguard Worker     }
1705*35238bceSAndroid Build Coastguard Worker     else
1706*35238bceSAndroid Build Coastguard Worker         return isNearestSampleResultValid(level[coords.face], sampler, prec, Vec2(coords.s, coords.t), 0, result);
1707*35238bceSAndroid Build Coastguard Worker }
1708*35238bceSAndroid Build Coastguard Worker 
isCubeMipmapLinearSampleResultValid(const ConstPixelBufferAccess (& faces0)[CUBEFACE_LAST],const ConstPixelBufferAccess (& faces1)[CUBEFACE_LAST],const Sampler & sampler,const Sampler::FilterMode levelFilter,const LookupPrecision & prec,const CubeFaceFloatCoords & coords,const Vec2 & fBounds,const Vec4 & result)1709*35238bceSAndroid Build Coastguard Worker static bool isCubeMipmapLinearSampleResultValid(const ConstPixelBufferAccess (&faces0)[CUBEFACE_LAST],
1710*35238bceSAndroid Build Coastguard Worker                                                 const ConstPixelBufferAccess (&faces1)[CUBEFACE_LAST],
1711*35238bceSAndroid Build Coastguard Worker                                                 const Sampler &sampler, const Sampler::FilterMode levelFilter,
1712*35238bceSAndroid Build Coastguard Worker                                                 const LookupPrecision &prec, const CubeFaceFloatCoords &coords,
1713*35238bceSAndroid Build Coastguard Worker                                                 const Vec2 &fBounds, const Vec4 &result)
1714*35238bceSAndroid Build Coastguard Worker {
1715*35238bceSAndroid Build Coastguard Worker     if (levelFilter == Sampler::LINEAR)
1716*35238bceSAndroid Build Coastguard Worker     {
1717*35238bceSAndroid Build Coastguard Worker         if (sampler.seamlessCubeMap)
1718*35238bceSAndroid Build Coastguard Worker             return isSeamplessLinearMipmapLinearSampleResultValid(faces0, faces1, sampler, prec, coords, fBounds,
1719*35238bceSAndroid Build Coastguard Worker                                                                   result);
1720*35238bceSAndroid Build Coastguard Worker         else
1721*35238bceSAndroid Build Coastguard Worker             return isLinearMipmapLinearSampleResultValid(faces0[coords.face], faces1[coords.face], sampler, prec,
1722*35238bceSAndroid Build Coastguard Worker                                                          Vec2(coords.s, coords.t), 0, fBounds, result);
1723*35238bceSAndroid Build Coastguard Worker     }
1724*35238bceSAndroid Build Coastguard Worker     else
1725*35238bceSAndroid Build Coastguard Worker         return isNearestMipmapLinearSampleResultValid(faces0[coords.face], faces1[coords.face], sampler, prec,
1726*35238bceSAndroid Build Coastguard Worker                                                       Vec2(coords.s, coords.t), 0, fBounds, result);
1727*35238bceSAndroid Build Coastguard Worker }
1728*35238bceSAndroid Build Coastguard Worker 
getCubeLevelFaces(const TextureCubeView & texture,const int levelNdx,ConstPixelBufferAccess (& out)[CUBEFACE_LAST])1729*35238bceSAndroid Build Coastguard Worker static void getCubeLevelFaces(const TextureCubeView &texture, const int levelNdx,
1730*35238bceSAndroid Build Coastguard Worker                               ConstPixelBufferAccess (&out)[CUBEFACE_LAST])
1731*35238bceSAndroid Build Coastguard Worker {
1732*35238bceSAndroid Build Coastguard Worker     for (int faceNdx = 0; faceNdx < CUBEFACE_LAST; faceNdx++)
1733*35238bceSAndroid Build Coastguard Worker         out[faceNdx] = texture.getLevelFace(levelNdx, (CubeFace)faceNdx);
1734*35238bceSAndroid Build Coastguard Worker }
1735*35238bceSAndroid Build Coastguard Worker 
isLookupResultValid(const TextureCubeView & texture,const Sampler & sampler,const LookupPrecision & prec,const Vec3 & coord,const Vec2 & lodBounds,const Vec4 & result)1736*35238bceSAndroid Build Coastguard Worker bool isLookupResultValid(const TextureCubeView &texture, const Sampler &sampler, const LookupPrecision &prec,
1737*35238bceSAndroid Build Coastguard Worker                          const Vec3 &coord, const Vec2 &lodBounds, const Vec4 &result)
1738*35238bceSAndroid Build Coastguard Worker {
1739*35238bceSAndroid Build Coastguard Worker     int numPossibleFaces = 0;
1740*35238bceSAndroid Build Coastguard Worker     CubeFace possibleFaces[CUBEFACE_LAST];
1741*35238bceSAndroid Build Coastguard Worker 
1742*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(isSamplerSupported(sampler));
1743*35238bceSAndroid Build Coastguard Worker 
1744*35238bceSAndroid Build Coastguard Worker     getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1745*35238bceSAndroid Build Coastguard Worker 
1746*35238bceSAndroid Build Coastguard Worker     if (numPossibleFaces == 0)
1747*35238bceSAndroid Build Coastguard Worker         return true; // Result is undefined.
1748*35238bceSAndroid Build Coastguard Worker 
1749*35238bceSAndroid Build Coastguard Worker     for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1750*35238bceSAndroid Build Coastguard Worker     {
1751*35238bceSAndroid Build Coastguard Worker         const CubeFaceFloatCoords faceCoords(possibleFaces[tryFaceNdx],
1752*35238bceSAndroid Build Coastguard Worker                                              projectToFace(possibleFaces[tryFaceNdx], coord));
1753*35238bceSAndroid Build Coastguard Worker         const float minLod        = lodBounds.x();
1754*35238bceSAndroid Build Coastguard Worker         const float maxLod        = lodBounds.y();
1755*35238bceSAndroid Build Coastguard Worker         const bool canBeMagnified = minLod <= sampler.lodThreshold;
1756*35238bceSAndroid Build Coastguard Worker         const bool canBeMinified  = maxLod > sampler.lodThreshold;
1757*35238bceSAndroid Build Coastguard Worker 
1758*35238bceSAndroid Build Coastguard Worker         if (canBeMagnified)
1759*35238bceSAndroid Build Coastguard Worker         {
1760*35238bceSAndroid Build Coastguard Worker             ConstPixelBufferAccess faces[CUBEFACE_LAST];
1761*35238bceSAndroid Build Coastguard Worker             getCubeLevelFaces(texture, 0, faces);
1762*35238bceSAndroid Build Coastguard Worker 
1763*35238bceSAndroid Build Coastguard Worker             if (isCubeLevelSampleResultValid(faces, sampler, sampler.magFilter, prec, faceCoords, result))
1764*35238bceSAndroid Build Coastguard Worker                 return true;
1765*35238bceSAndroid Build Coastguard Worker         }
1766*35238bceSAndroid Build Coastguard Worker 
1767*35238bceSAndroid Build Coastguard Worker         if (canBeMinified)
1768*35238bceSAndroid Build Coastguard Worker         {
1769*35238bceSAndroid Build Coastguard Worker             const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1770*35238bceSAndroid Build Coastguard Worker             const bool isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1771*35238bceSAndroid Build Coastguard Worker             const int minTexLevel      = 0;
1772*35238bceSAndroid Build Coastguard Worker             const int maxTexLevel      = texture.getNumLevels() - 1;
1773*35238bceSAndroid Build Coastguard Worker 
1774*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minTexLevel <= maxTexLevel);
1775*35238bceSAndroid Build Coastguard Worker 
1776*35238bceSAndroid Build Coastguard Worker             if (isLinearMipmap && minTexLevel < maxTexLevel)
1777*35238bceSAndroid Build Coastguard Worker             {
1778*35238bceSAndroid Build Coastguard Worker                 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel - 1);
1779*35238bceSAndroid Build Coastguard Worker                 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel - 1);
1780*35238bceSAndroid Build Coastguard Worker 
1781*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(minLevel <= maxLevel);
1782*35238bceSAndroid Build Coastguard Worker 
1783*35238bceSAndroid Build Coastguard Worker                 for (int levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++)
1784*35238bceSAndroid Build Coastguard Worker                 {
1785*35238bceSAndroid Build Coastguard Worker                     const float minF = de::clamp(minLod - float(levelNdx), 0.0f, 1.0f);
1786*35238bceSAndroid Build Coastguard Worker                     const float maxF = de::clamp(maxLod - float(levelNdx), 0.0f, 1.0f);
1787*35238bceSAndroid Build Coastguard Worker 
1788*35238bceSAndroid Build Coastguard Worker                     ConstPixelBufferAccess faces0[CUBEFACE_LAST];
1789*35238bceSAndroid Build Coastguard Worker                     ConstPixelBufferAccess faces1[CUBEFACE_LAST];
1790*35238bceSAndroid Build Coastguard Worker 
1791*35238bceSAndroid Build Coastguard Worker                     getCubeLevelFaces(texture, levelNdx, faces0);
1792*35238bceSAndroid Build Coastguard Worker                     getCubeLevelFaces(texture, levelNdx + 1, faces1);
1793*35238bceSAndroid Build Coastguard Worker 
1794*35238bceSAndroid Build Coastguard Worker                     if (isCubeMipmapLinearSampleResultValid(faces0, faces1, sampler, getLevelFilter(sampler.minFilter),
1795*35238bceSAndroid Build Coastguard Worker                                                             prec, faceCoords, Vec2(minF, maxF), result))
1796*35238bceSAndroid Build Coastguard Worker                         return true;
1797*35238bceSAndroid Build Coastguard Worker                 }
1798*35238bceSAndroid Build Coastguard Worker             }
1799*35238bceSAndroid Build Coastguard Worker             else if (isNearestMipmap)
1800*35238bceSAndroid Build Coastguard Worker             {
1801*35238bceSAndroid Build Coastguard Worker                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1802*35238bceSAndroid Build Coastguard Worker                 //         decision to allow floor(lod + 0.5) as well.
1803*35238bceSAndroid Build Coastguard Worker                 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1804*35238bceSAndroid Build Coastguard Worker                 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1805*35238bceSAndroid Build Coastguard Worker 
1806*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(minLevel <= maxLevel);
1807*35238bceSAndroid Build Coastguard Worker 
1808*35238bceSAndroid Build Coastguard Worker                 for (int levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++)
1809*35238bceSAndroid Build Coastguard Worker                 {
1810*35238bceSAndroid Build Coastguard Worker                     ConstPixelBufferAccess faces[CUBEFACE_LAST];
1811*35238bceSAndroid Build Coastguard Worker                     getCubeLevelFaces(texture, levelNdx, faces);
1812*35238bceSAndroid Build Coastguard Worker 
1813*35238bceSAndroid Build Coastguard Worker                     if (isCubeLevelSampleResultValid(faces, sampler, getLevelFilter(sampler.minFilter), prec,
1814*35238bceSAndroid Build Coastguard Worker                                                      faceCoords, result))
1815*35238bceSAndroid Build Coastguard Worker                         return true;
1816*35238bceSAndroid Build Coastguard Worker                 }
1817*35238bceSAndroid Build Coastguard Worker             }
1818*35238bceSAndroid Build Coastguard Worker             else
1819*35238bceSAndroid Build Coastguard Worker             {
1820*35238bceSAndroid Build Coastguard Worker                 ConstPixelBufferAccess faces[CUBEFACE_LAST];
1821*35238bceSAndroid Build Coastguard Worker                 getCubeLevelFaces(texture, 0, faces);
1822*35238bceSAndroid Build Coastguard Worker 
1823*35238bceSAndroid Build Coastguard Worker                 if (isCubeLevelSampleResultValid(faces, sampler, sampler.minFilter, prec, faceCoords, result))
1824*35238bceSAndroid Build Coastguard Worker                     return true;
1825*35238bceSAndroid Build Coastguard Worker             }
1826*35238bceSAndroid Build Coastguard Worker         }
1827*35238bceSAndroid Build Coastguard Worker     }
1828*35238bceSAndroid Build Coastguard Worker 
1829*35238bceSAndroid Build Coastguard Worker     return false;
1830*35238bceSAndroid Build Coastguard Worker }
1831*35238bceSAndroid Build Coastguard Worker 
computeLayerRange(int numLayers,int numCoordBits,float layerCoord)1832*35238bceSAndroid Build Coastguard Worker static inline IVec2 computeLayerRange(int numLayers, int numCoordBits, float layerCoord)
1833*35238bceSAndroid Build Coastguard Worker {
1834*35238bceSAndroid Build Coastguard Worker     const float err = computeFloatingPointError(layerCoord, numCoordBits);
1835*35238bceSAndroid Build Coastguard Worker     const int minL  = (int)deFloatFloor(layerCoord - err + 0.5f);    // Round down
1836*35238bceSAndroid Build Coastguard Worker     const int maxL  = (int)deFloatCeil(layerCoord + err + 0.5f) - 1; // Round up
1837*35238bceSAndroid Build Coastguard Worker 
1838*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minL <= maxL);
1839*35238bceSAndroid Build Coastguard Worker 
1840*35238bceSAndroid Build Coastguard Worker     return IVec2(de::clamp(minL, 0, numLayers - 1), de::clamp(maxL, 0, numLayers - 1));
1841*35238bceSAndroid Build Coastguard Worker }
1842*35238bceSAndroid Build Coastguard Worker 
isLookupResultValid(const Texture1DArrayView & texture,const Sampler & sampler,const LookupPrecision & prec,const Vec2 & coord,const Vec2 & lodBounds,const Vec4 & result)1843*35238bceSAndroid Build Coastguard Worker bool isLookupResultValid(const Texture1DArrayView &texture, const Sampler &sampler, const LookupPrecision &prec,
1844*35238bceSAndroid Build Coastguard Worker                          const Vec2 &coord, const Vec2 &lodBounds, const Vec4 &result)
1845*35238bceSAndroid Build Coastguard Worker {
1846*35238bceSAndroid Build Coastguard Worker     const IVec2 layerRange    = computeLayerRange(texture.getNumLayers(), prec.coordBits.y(), coord.y());
1847*35238bceSAndroid Build Coastguard Worker     const float coordX        = coord.x();
1848*35238bceSAndroid Build Coastguard Worker     const float minLod        = lodBounds.x();
1849*35238bceSAndroid Build Coastguard Worker     const float maxLod        = lodBounds.y();
1850*35238bceSAndroid Build Coastguard Worker     const bool canBeMagnified = minLod <= sampler.lodThreshold;
1851*35238bceSAndroid Build Coastguard Worker     const bool canBeMinified  = maxLod > sampler.lodThreshold;
1852*35238bceSAndroid Build Coastguard Worker 
1853*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(isSamplerSupported(sampler));
1854*35238bceSAndroid Build Coastguard Worker 
1855*35238bceSAndroid Build Coastguard Worker     for (int layer = layerRange.x(); layer <= layerRange.y(); layer++)
1856*35238bceSAndroid Build Coastguard Worker     {
1857*35238bceSAndroid Build Coastguard Worker         if (canBeMagnified)
1858*35238bceSAndroid Build Coastguard Worker         {
1859*35238bceSAndroid Build Coastguard Worker             if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coordX, layer, result))
1860*35238bceSAndroid Build Coastguard Worker                 return true;
1861*35238bceSAndroid Build Coastguard Worker         }
1862*35238bceSAndroid Build Coastguard Worker 
1863*35238bceSAndroid Build Coastguard Worker         if (canBeMinified)
1864*35238bceSAndroid Build Coastguard Worker         {
1865*35238bceSAndroid Build Coastguard Worker             const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1866*35238bceSAndroid Build Coastguard Worker             const bool isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1867*35238bceSAndroid Build Coastguard Worker             const int minTexLevel      = 0;
1868*35238bceSAndroid Build Coastguard Worker             const int maxTexLevel      = texture.getNumLevels() - 1;
1869*35238bceSAndroid Build Coastguard Worker 
1870*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minTexLevel <= maxTexLevel);
1871*35238bceSAndroid Build Coastguard Worker 
1872*35238bceSAndroid Build Coastguard Worker             if (isLinearMipmap && minTexLevel < maxTexLevel)
1873*35238bceSAndroid Build Coastguard Worker             {
1874*35238bceSAndroid Build Coastguard Worker                 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel - 1);
1875*35238bceSAndroid Build Coastguard Worker                 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel - 1);
1876*35238bceSAndroid Build Coastguard Worker 
1877*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(minLevel <= maxLevel);
1878*35238bceSAndroid Build Coastguard Worker 
1879*35238bceSAndroid Build Coastguard Worker                 for (int level = minLevel; level <= maxLevel; level++)
1880*35238bceSAndroid Build Coastguard Worker                 {
1881*35238bceSAndroid Build Coastguard Worker                     const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1882*35238bceSAndroid Build Coastguard Worker                     const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1883*35238bceSAndroid Build Coastguard Worker 
1884*35238bceSAndroid Build Coastguard Worker                     if (isMipmapLinearSampleResultValid(texture.getLevel(level), texture.getLevel(level + 1), sampler,
1885*35238bceSAndroid Build Coastguard Worker                                                         getLevelFilter(sampler.minFilter), prec, coordX, layer,
1886*35238bceSAndroid Build Coastguard Worker                                                         Vec2(minF, maxF), result))
1887*35238bceSAndroid Build Coastguard Worker                         return true;
1888*35238bceSAndroid Build Coastguard Worker                 }
1889*35238bceSAndroid Build Coastguard Worker             }
1890*35238bceSAndroid Build Coastguard Worker             else if (isNearestMipmap)
1891*35238bceSAndroid Build Coastguard Worker             {
1892*35238bceSAndroid Build Coastguard Worker                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1893*35238bceSAndroid Build Coastguard Worker                 //         decision to allow floor(lod + 0.5) as well.
1894*35238bceSAndroid Build Coastguard Worker                 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1895*35238bceSAndroid Build Coastguard Worker                 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1896*35238bceSAndroid Build Coastguard Worker 
1897*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(minLevel <= maxLevel);
1898*35238bceSAndroid Build Coastguard Worker 
1899*35238bceSAndroid Build Coastguard Worker                 for (int level = minLevel; level <= maxLevel; level++)
1900*35238bceSAndroid Build Coastguard Worker                 {
1901*35238bceSAndroid Build Coastguard Worker                     if (isLevelSampleResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter),
1902*35238bceSAndroid Build Coastguard Worker                                                  prec, coordX, layer, result))
1903*35238bceSAndroid Build Coastguard Worker                         return true;
1904*35238bceSAndroid Build Coastguard Worker                 }
1905*35238bceSAndroid Build Coastguard Worker             }
1906*35238bceSAndroid Build Coastguard Worker             else
1907*35238bceSAndroid Build Coastguard Worker             {
1908*35238bceSAndroid Build Coastguard Worker                 if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coordX, layer,
1909*35238bceSAndroid Build Coastguard Worker                                              result))
1910*35238bceSAndroid Build Coastguard Worker                     return true;
1911*35238bceSAndroid Build Coastguard Worker             }
1912*35238bceSAndroid Build Coastguard Worker         }
1913*35238bceSAndroid Build Coastguard Worker     }
1914*35238bceSAndroid Build Coastguard Worker 
1915*35238bceSAndroid Build Coastguard Worker     return false;
1916*35238bceSAndroid Build Coastguard Worker }
1917*35238bceSAndroid Build Coastguard Worker 
isLookupResultValid(const Texture2DArrayView & texture,const Sampler & sampler,const LookupPrecision & prec,const Vec3 & coord,const Vec2 & lodBounds,const Vec4 & result)1918*35238bceSAndroid Build Coastguard Worker bool isLookupResultValid(const Texture2DArrayView &texture, const Sampler &sampler, const LookupPrecision &prec,
1919*35238bceSAndroid Build Coastguard Worker                          const Vec3 &coord, const Vec2 &lodBounds, const Vec4 &result)
1920*35238bceSAndroid Build Coastguard Worker {
1921*35238bceSAndroid Build Coastguard Worker     const IVec2 layerRange    = computeLayerRange(texture.getNumLayers(), prec.coordBits.z(), coord.z());
1922*35238bceSAndroid Build Coastguard Worker     const Vec2 coordXY        = coord.swizzle(0, 1);
1923*35238bceSAndroid Build Coastguard Worker     const float minLod        = lodBounds.x();
1924*35238bceSAndroid Build Coastguard Worker     const float maxLod        = lodBounds.y();
1925*35238bceSAndroid Build Coastguard Worker     const bool canBeMagnified = minLod <= sampler.lodThreshold;
1926*35238bceSAndroid Build Coastguard Worker     const bool canBeMinified  = maxLod > sampler.lodThreshold;
1927*35238bceSAndroid Build Coastguard Worker 
1928*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(isSamplerSupported(sampler));
1929*35238bceSAndroid Build Coastguard Worker 
1930*35238bceSAndroid Build Coastguard Worker     for (int layer = layerRange.x(); layer <= layerRange.y(); layer++)
1931*35238bceSAndroid Build Coastguard Worker     {
1932*35238bceSAndroid Build Coastguard Worker         if (canBeMagnified)
1933*35238bceSAndroid Build Coastguard Worker         {
1934*35238bceSAndroid Build Coastguard Worker             if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coordXY, layer, result))
1935*35238bceSAndroid Build Coastguard Worker                 return true;
1936*35238bceSAndroid Build Coastguard Worker         }
1937*35238bceSAndroid Build Coastguard Worker 
1938*35238bceSAndroid Build Coastguard Worker         if (canBeMinified)
1939*35238bceSAndroid Build Coastguard Worker         {
1940*35238bceSAndroid Build Coastguard Worker             const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1941*35238bceSAndroid Build Coastguard Worker             const bool isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1942*35238bceSAndroid Build Coastguard Worker             const int minTexLevel      = 0;
1943*35238bceSAndroid Build Coastguard Worker             const int maxTexLevel      = texture.getNumLevels() - 1;
1944*35238bceSAndroid Build Coastguard Worker 
1945*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minTexLevel <= maxTexLevel);
1946*35238bceSAndroid Build Coastguard Worker 
1947*35238bceSAndroid Build Coastguard Worker             if (isLinearMipmap && minTexLevel < maxTexLevel)
1948*35238bceSAndroid Build Coastguard Worker             {
1949*35238bceSAndroid Build Coastguard Worker                 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel - 1);
1950*35238bceSAndroid Build Coastguard Worker                 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel - 1);
1951*35238bceSAndroid Build Coastguard Worker 
1952*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(minLevel <= maxLevel);
1953*35238bceSAndroid Build Coastguard Worker 
1954*35238bceSAndroid Build Coastguard Worker                 for (int level = minLevel; level <= maxLevel; level++)
1955*35238bceSAndroid Build Coastguard Worker                 {
1956*35238bceSAndroid Build Coastguard Worker                     const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1957*35238bceSAndroid Build Coastguard Worker                     const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1958*35238bceSAndroid Build Coastguard Worker 
1959*35238bceSAndroid Build Coastguard Worker                     if (isMipmapLinearSampleResultValid(texture.getLevel(level), texture.getLevel(level + 1), sampler,
1960*35238bceSAndroid Build Coastguard Worker                                                         getLevelFilter(sampler.minFilter), prec, coordXY, layer,
1961*35238bceSAndroid Build Coastguard Worker                                                         Vec2(minF, maxF), result))
1962*35238bceSAndroid Build Coastguard Worker                         return true;
1963*35238bceSAndroid Build Coastguard Worker                 }
1964*35238bceSAndroid Build Coastguard Worker             }
1965*35238bceSAndroid Build Coastguard Worker             else if (isNearestMipmap)
1966*35238bceSAndroid Build Coastguard Worker             {
1967*35238bceSAndroid Build Coastguard Worker                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1968*35238bceSAndroid Build Coastguard Worker                 //         decision to allow floor(lod + 0.5) as well.
1969*35238bceSAndroid Build Coastguard Worker                 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1970*35238bceSAndroid Build Coastguard Worker                 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1971*35238bceSAndroid Build Coastguard Worker 
1972*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(minLevel <= maxLevel);
1973*35238bceSAndroid Build Coastguard Worker 
1974*35238bceSAndroid Build Coastguard Worker                 for (int level = minLevel; level <= maxLevel; level++)
1975*35238bceSAndroid Build Coastguard Worker                 {
1976*35238bceSAndroid Build Coastguard Worker                     if (isLevelSampleResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter),
1977*35238bceSAndroid Build Coastguard Worker                                                  prec, coordXY, layer, result))
1978*35238bceSAndroid Build Coastguard Worker                         return true;
1979*35238bceSAndroid Build Coastguard Worker                 }
1980*35238bceSAndroid Build Coastguard Worker             }
1981*35238bceSAndroid Build Coastguard Worker             else
1982*35238bceSAndroid Build Coastguard Worker             {
1983*35238bceSAndroid Build Coastguard Worker                 if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coordXY, layer,
1984*35238bceSAndroid Build Coastguard Worker                                              result))
1985*35238bceSAndroid Build Coastguard Worker                     return true;
1986*35238bceSAndroid Build Coastguard Worker             }
1987*35238bceSAndroid Build Coastguard Worker         }
1988*35238bceSAndroid Build Coastguard Worker     }
1989*35238bceSAndroid Build Coastguard Worker 
1990*35238bceSAndroid Build Coastguard Worker     return false;
1991*35238bceSAndroid Build Coastguard Worker }
1992*35238bceSAndroid Build Coastguard Worker 
isLevelSampleResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const Sampler::FilterMode filterMode,const LookupPrecision & prec,const Vec3 & coord,const Vec4 & result)1993*35238bceSAndroid Build Coastguard Worker static bool isLevelSampleResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler,
1994*35238bceSAndroid Build Coastguard Worker                                      const Sampler::FilterMode filterMode, const LookupPrecision &prec,
1995*35238bceSAndroid Build Coastguard Worker                                      const Vec3 &coord, const Vec4 &result)
1996*35238bceSAndroid Build Coastguard Worker {
1997*35238bceSAndroid Build Coastguard Worker     if (filterMode == Sampler::LINEAR)
1998*35238bceSAndroid Build Coastguard Worker         return isLinearSampleResultValid(level, sampler, prec, coord, result);
1999*35238bceSAndroid Build Coastguard Worker     else
2000*35238bceSAndroid Build Coastguard Worker         return isNearestSampleResultValid(level, sampler, prec, coord, result);
2001*35238bceSAndroid Build Coastguard Worker }
2002*35238bceSAndroid Build Coastguard Worker 
isMipmapLinearSampleResultValid(const ConstPixelBufferAccess & level0,const ConstPixelBufferAccess & level1,const Sampler & sampler,const Sampler::FilterMode levelFilter,const LookupPrecision & prec,const Vec3 & coord,const Vec2 & fBounds,const Vec4 & result)2003*35238bceSAndroid Build Coastguard Worker static bool isMipmapLinearSampleResultValid(const ConstPixelBufferAccess &level0, const ConstPixelBufferAccess &level1,
2004*35238bceSAndroid Build Coastguard Worker                                             const Sampler &sampler, const Sampler::FilterMode levelFilter,
2005*35238bceSAndroid Build Coastguard Worker                                             const LookupPrecision &prec, const Vec3 &coord, const Vec2 &fBounds,
2006*35238bceSAndroid Build Coastguard Worker                                             const Vec4 &result)
2007*35238bceSAndroid Build Coastguard Worker {
2008*35238bceSAndroid Build Coastguard Worker     if (levelFilter == Sampler::LINEAR)
2009*35238bceSAndroid Build Coastguard Worker         return isLinearMipmapLinearSampleResultValid(level0, level1, sampler, prec, coord, fBounds, result);
2010*35238bceSAndroid Build Coastguard Worker     else
2011*35238bceSAndroid Build Coastguard Worker         return isNearestMipmapLinearSampleResultValid(level0, level1, sampler, prec, coord, fBounds, result);
2012*35238bceSAndroid Build Coastguard Worker }
2013*35238bceSAndroid Build Coastguard Worker 
isLookupResultValid(const Texture3DView & texture,const Sampler & sampler,const LookupPrecision & prec,const Vec3 & coord,const Vec2 & lodBounds,const Vec4 & result)2014*35238bceSAndroid Build Coastguard Worker bool isLookupResultValid(const Texture3DView &texture, const Sampler &sampler, const LookupPrecision &prec,
2015*35238bceSAndroid Build Coastguard Worker                          const Vec3 &coord, const Vec2 &lodBounds, const Vec4 &result)
2016*35238bceSAndroid Build Coastguard Worker {
2017*35238bceSAndroid Build Coastguard Worker     const float minLod        = lodBounds.x();
2018*35238bceSAndroid Build Coastguard Worker     const float maxLod        = lodBounds.y();
2019*35238bceSAndroid Build Coastguard Worker     const bool canBeMagnified = minLod <= sampler.lodThreshold;
2020*35238bceSAndroid Build Coastguard Worker     const bool canBeMinified  = maxLod > sampler.lodThreshold;
2021*35238bceSAndroid Build Coastguard Worker 
2022*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(isSamplerSupported(sampler));
2023*35238bceSAndroid Build Coastguard Worker 
2024*35238bceSAndroid Build Coastguard Worker     if (canBeMagnified)
2025*35238bceSAndroid Build Coastguard Worker     {
2026*35238bceSAndroid Build Coastguard Worker         if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, result))
2027*35238bceSAndroid Build Coastguard Worker             return true;
2028*35238bceSAndroid Build Coastguard Worker     }
2029*35238bceSAndroid Build Coastguard Worker 
2030*35238bceSAndroid Build Coastguard Worker     if (canBeMinified)
2031*35238bceSAndroid Build Coastguard Worker     {
2032*35238bceSAndroid Build Coastguard Worker         const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
2033*35238bceSAndroid Build Coastguard Worker         const bool isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
2034*35238bceSAndroid Build Coastguard Worker         const int minTexLevel      = 0;
2035*35238bceSAndroid Build Coastguard Worker         const int maxTexLevel      = texture.getNumLevels() - 1;
2036*35238bceSAndroid Build Coastguard Worker 
2037*35238bceSAndroid Build Coastguard Worker         DE_ASSERT(minTexLevel <= maxTexLevel);
2038*35238bceSAndroid Build Coastguard Worker 
2039*35238bceSAndroid Build Coastguard Worker         if (isLinearMipmap && minTexLevel < maxTexLevel)
2040*35238bceSAndroid Build Coastguard Worker         {
2041*35238bceSAndroid Build Coastguard Worker             const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel - 1);
2042*35238bceSAndroid Build Coastguard Worker             const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel - 1);
2043*35238bceSAndroid Build Coastguard Worker 
2044*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minLevel <= maxLevel);
2045*35238bceSAndroid Build Coastguard Worker 
2046*35238bceSAndroid Build Coastguard Worker             for (int level = minLevel; level <= maxLevel; level++)
2047*35238bceSAndroid Build Coastguard Worker             {
2048*35238bceSAndroid Build Coastguard Worker                 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
2049*35238bceSAndroid Build Coastguard Worker                 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
2050*35238bceSAndroid Build Coastguard Worker 
2051*35238bceSAndroid Build Coastguard Worker                 if (isMipmapLinearSampleResultValid(texture.getLevel(level), texture.getLevel(level + 1), sampler,
2052*35238bceSAndroid Build Coastguard Worker                                                     getLevelFilter(sampler.minFilter), prec, coord, Vec2(minF, maxF),
2053*35238bceSAndroid Build Coastguard Worker                                                     result))
2054*35238bceSAndroid Build Coastguard Worker                     return true;
2055*35238bceSAndroid Build Coastguard Worker             }
2056*35238bceSAndroid Build Coastguard Worker         }
2057*35238bceSAndroid Build Coastguard Worker         else if (isNearestMipmap)
2058*35238bceSAndroid Build Coastguard Worker         {
2059*35238bceSAndroid Build Coastguard Worker             // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
2060*35238bceSAndroid Build Coastguard Worker             //         decision to allow floor(lod + 0.5) as well.
2061*35238bceSAndroid Build Coastguard Worker             const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
2062*35238bceSAndroid Build Coastguard Worker             const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
2063*35238bceSAndroid Build Coastguard Worker 
2064*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(minLevel <= maxLevel);
2065*35238bceSAndroid Build Coastguard Worker 
2066*35238bceSAndroid Build Coastguard Worker             for (int level = minLevel; level <= maxLevel; level++)
2067*35238bceSAndroid Build Coastguard Worker             {
2068*35238bceSAndroid Build Coastguard Worker                 if (isLevelSampleResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec,
2069*35238bceSAndroid Build Coastguard Worker                                              coord, result))
2070*35238bceSAndroid Build Coastguard Worker                     return true;
2071*35238bceSAndroid Build Coastguard Worker             }
2072*35238bceSAndroid Build Coastguard Worker         }
2073*35238bceSAndroid Build Coastguard Worker         else
2074*35238bceSAndroid Build Coastguard Worker         {
2075*35238bceSAndroid Build Coastguard Worker             if (isLevelSampleResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, result))
2076*35238bceSAndroid Build Coastguard Worker                 return true;
2077*35238bceSAndroid Build Coastguard Worker         }
2078*35238bceSAndroid Build Coastguard Worker     }
2079*35238bceSAndroid Build Coastguard Worker 
2080*35238bceSAndroid Build Coastguard Worker     return false;
2081*35238bceSAndroid Build Coastguard Worker }
2082*35238bceSAndroid Build Coastguard Worker 
getCubeArrayLevelFaces(const TextureCubeArrayView & texture,const int levelNdx,const int layerNdx,ConstPixelBufferAccess (& out)[CUBEFACE_LAST])2083*35238bceSAndroid Build Coastguard Worker static void getCubeArrayLevelFaces(const TextureCubeArrayView &texture, const int levelNdx, const int layerNdx,
2084*35238bceSAndroid Build Coastguard Worker                                    ConstPixelBufferAccess (&out)[CUBEFACE_LAST])
2085*35238bceSAndroid Build Coastguard Worker {
2086*35238bceSAndroid Build Coastguard Worker     const ConstPixelBufferAccess &level = texture.getLevel(levelNdx);
2087*35238bceSAndroid Build Coastguard Worker     const int layerDepth                = layerNdx * 6;
2088*35238bceSAndroid Build Coastguard Worker 
2089*35238bceSAndroid Build Coastguard Worker     for (int faceNdx = 0; faceNdx < CUBEFACE_LAST; faceNdx++)
2090*35238bceSAndroid Build Coastguard Worker     {
2091*35238bceSAndroid Build Coastguard Worker         const CubeFace face = (CubeFace)faceNdx;
2092*35238bceSAndroid Build Coastguard Worker         out[faceNdx] =
2093*35238bceSAndroid Build Coastguard Worker             getSubregion(level, 0, 0, layerDepth + getCubeArrayFaceIndex(face), level.getWidth(), level.getHeight(), 1);
2094*35238bceSAndroid Build Coastguard Worker     }
2095*35238bceSAndroid Build Coastguard Worker }
2096*35238bceSAndroid Build Coastguard Worker 
isLookupResultValid(const TextureCubeArrayView & texture,const Sampler & sampler,const LookupPrecision & prec,const IVec4 & coordBits,const Vec4 & coord,const Vec2 & lodBounds,const Vec4 & result)2097*35238bceSAndroid Build Coastguard Worker bool isLookupResultValid(const TextureCubeArrayView &texture, const Sampler &sampler, const LookupPrecision &prec,
2098*35238bceSAndroid Build Coastguard Worker                          const IVec4 &coordBits, const Vec4 &coord, const Vec2 &lodBounds, const Vec4 &result)
2099*35238bceSAndroid Build Coastguard Worker {
2100*35238bceSAndroid Build Coastguard Worker     const IVec2 layerRange = computeLayerRange(texture.getNumLayers(), coordBits.w(), coord.w());
2101*35238bceSAndroid Build Coastguard Worker     const Vec3 layerCoord  = coord.toWidth<3>();
2102*35238bceSAndroid Build Coastguard Worker     int numPossibleFaces   = 0;
2103*35238bceSAndroid Build Coastguard Worker     CubeFace possibleFaces[CUBEFACE_LAST];
2104*35238bceSAndroid Build Coastguard Worker 
2105*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(isSamplerSupported(sampler));
2106*35238bceSAndroid Build Coastguard Worker 
2107*35238bceSAndroid Build Coastguard Worker     getPossibleCubeFaces(layerCoord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
2108*35238bceSAndroid Build Coastguard Worker 
2109*35238bceSAndroid Build Coastguard Worker     if (numPossibleFaces == 0)
2110*35238bceSAndroid Build Coastguard Worker         return true; // Result is undefined.
2111*35238bceSAndroid Build Coastguard Worker 
2112*35238bceSAndroid Build Coastguard Worker     for (int layerNdx = layerRange.x(); layerNdx <= layerRange.y(); layerNdx++)
2113*35238bceSAndroid Build Coastguard Worker     {
2114*35238bceSAndroid Build Coastguard Worker         for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
2115*35238bceSAndroid Build Coastguard Worker         {
2116*35238bceSAndroid Build Coastguard Worker             const CubeFaceFloatCoords faceCoords(possibleFaces[tryFaceNdx],
2117*35238bceSAndroid Build Coastguard Worker                                                  projectToFace(possibleFaces[tryFaceNdx], layerCoord));
2118*35238bceSAndroid Build Coastguard Worker             const float minLod        = lodBounds.x();
2119*35238bceSAndroid Build Coastguard Worker             const float maxLod        = lodBounds.y();
2120*35238bceSAndroid Build Coastguard Worker             const bool canBeMagnified = minLod <= sampler.lodThreshold;
2121*35238bceSAndroid Build Coastguard Worker             const bool canBeMinified  = maxLod > sampler.lodThreshold;
2122*35238bceSAndroid Build Coastguard Worker 
2123*35238bceSAndroid Build Coastguard Worker             if (canBeMagnified)
2124*35238bceSAndroid Build Coastguard Worker             {
2125*35238bceSAndroid Build Coastguard Worker                 ConstPixelBufferAccess faces[CUBEFACE_LAST];
2126*35238bceSAndroid Build Coastguard Worker                 getCubeArrayLevelFaces(texture, 0, layerNdx, faces);
2127*35238bceSAndroid Build Coastguard Worker 
2128*35238bceSAndroid Build Coastguard Worker                 if (isCubeLevelSampleResultValid(faces, sampler, sampler.magFilter, prec, faceCoords, result))
2129*35238bceSAndroid Build Coastguard Worker                     return true;
2130*35238bceSAndroid Build Coastguard Worker             }
2131*35238bceSAndroid Build Coastguard Worker 
2132*35238bceSAndroid Build Coastguard Worker             if (canBeMinified)
2133*35238bceSAndroid Build Coastguard Worker             {
2134*35238bceSAndroid Build Coastguard Worker                 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
2135*35238bceSAndroid Build Coastguard Worker                 const bool isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
2136*35238bceSAndroid Build Coastguard Worker                 const int minTexLevel      = 0;
2137*35238bceSAndroid Build Coastguard Worker                 const int maxTexLevel      = texture.getNumLevels() - 1;
2138*35238bceSAndroid Build Coastguard Worker 
2139*35238bceSAndroid Build Coastguard Worker                 DE_ASSERT(minTexLevel <= maxTexLevel);
2140*35238bceSAndroid Build Coastguard Worker 
2141*35238bceSAndroid Build Coastguard Worker                 if (isLinearMipmap && minTexLevel < maxTexLevel)
2142*35238bceSAndroid Build Coastguard Worker                 {
2143*35238bceSAndroid Build Coastguard Worker                     const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel - 1);
2144*35238bceSAndroid Build Coastguard Worker                     const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel - 1);
2145*35238bceSAndroid Build Coastguard Worker 
2146*35238bceSAndroid Build Coastguard Worker                     DE_ASSERT(minLevel <= maxLevel);
2147*35238bceSAndroid Build Coastguard Worker 
2148*35238bceSAndroid Build Coastguard Worker                     for (int levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++)
2149*35238bceSAndroid Build Coastguard Worker                     {
2150*35238bceSAndroid Build Coastguard Worker                         const float minF = de::clamp(minLod - float(levelNdx), 0.0f, 1.0f);
2151*35238bceSAndroid Build Coastguard Worker                         const float maxF = de::clamp(maxLod - float(levelNdx), 0.0f, 1.0f);
2152*35238bceSAndroid Build Coastguard Worker 
2153*35238bceSAndroid Build Coastguard Worker                         ConstPixelBufferAccess faces0[CUBEFACE_LAST];
2154*35238bceSAndroid Build Coastguard Worker                         ConstPixelBufferAccess faces1[CUBEFACE_LAST];
2155*35238bceSAndroid Build Coastguard Worker 
2156*35238bceSAndroid Build Coastguard Worker                         getCubeArrayLevelFaces(texture, levelNdx, layerNdx, faces0);
2157*35238bceSAndroid Build Coastguard Worker                         getCubeArrayLevelFaces(texture, levelNdx + 1, layerNdx, faces1);
2158*35238bceSAndroid Build Coastguard Worker 
2159*35238bceSAndroid Build Coastguard Worker                         if (isCubeMipmapLinearSampleResultValid(faces0, faces1, sampler,
2160*35238bceSAndroid Build Coastguard Worker                                                                 getLevelFilter(sampler.minFilter), prec, faceCoords,
2161*35238bceSAndroid Build Coastguard Worker                                                                 Vec2(minF, maxF), result))
2162*35238bceSAndroid Build Coastguard Worker                             return true;
2163*35238bceSAndroid Build Coastguard Worker                     }
2164*35238bceSAndroid Build Coastguard Worker                 }
2165*35238bceSAndroid Build Coastguard Worker                 else if (isNearestMipmap)
2166*35238bceSAndroid Build Coastguard Worker                 {
2167*35238bceSAndroid Build Coastguard Worker                     // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
2168*35238bceSAndroid Build Coastguard Worker                     //         decision to allow floor(lod + 0.5) as well.
2169*35238bceSAndroid Build Coastguard Worker                     const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
2170*35238bceSAndroid Build Coastguard Worker                     const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
2171*35238bceSAndroid Build Coastguard Worker 
2172*35238bceSAndroid Build Coastguard Worker                     DE_ASSERT(minLevel <= maxLevel);
2173*35238bceSAndroid Build Coastguard Worker 
2174*35238bceSAndroid Build Coastguard Worker                     for (int levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++)
2175*35238bceSAndroid Build Coastguard Worker                     {
2176*35238bceSAndroid Build Coastguard Worker                         ConstPixelBufferAccess faces[CUBEFACE_LAST];
2177*35238bceSAndroid Build Coastguard Worker                         getCubeArrayLevelFaces(texture, levelNdx, layerNdx, faces);
2178*35238bceSAndroid Build Coastguard Worker 
2179*35238bceSAndroid Build Coastguard Worker                         if (isCubeLevelSampleResultValid(faces, sampler, getLevelFilter(sampler.minFilter), prec,
2180*35238bceSAndroid Build Coastguard Worker                                                          faceCoords, result))
2181*35238bceSAndroid Build Coastguard Worker                             return true;
2182*35238bceSAndroid Build Coastguard Worker                     }
2183*35238bceSAndroid Build Coastguard Worker                 }
2184*35238bceSAndroid Build Coastguard Worker                 else
2185*35238bceSAndroid Build Coastguard Worker                 {
2186*35238bceSAndroid Build Coastguard Worker                     ConstPixelBufferAccess faces[CUBEFACE_LAST];
2187*35238bceSAndroid Build Coastguard Worker                     getCubeArrayLevelFaces(texture, 0, layerNdx, faces);
2188*35238bceSAndroid Build Coastguard Worker 
2189*35238bceSAndroid Build Coastguard Worker                     if (isCubeLevelSampleResultValid(faces, sampler, sampler.minFilter, prec, faceCoords, result))
2190*35238bceSAndroid Build Coastguard Worker                         return true;
2191*35238bceSAndroid Build Coastguard Worker                 }
2192*35238bceSAndroid Build Coastguard Worker             }
2193*35238bceSAndroid Build Coastguard Worker         }
2194*35238bceSAndroid Build Coastguard Worker     }
2195*35238bceSAndroid Build Coastguard Worker 
2196*35238bceSAndroid Build Coastguard Worker     return false;
2197*35238bceSAndroid Build Coastguard Worker }
2198*35238bceSAndroid Build Coastguard Worker 
computeFixedPointThreshold(const IVec4 & bits)2199*35238bceSAndroid Build Coastguard Worker Vec4 computeFixedPointThreshold(const IVec4 &bits)
2200*35238bceSAndroid Build Coastguard Worker {
2201*35238bceSAndroid Build Coastguard Worker     return computeFixedPointError(bits);
2202*35238bceSAndroid Build Coastguard Worker }
2203*35238bceSAndroid Build Coastguard Worker 
computeFloatingPointThreshold(const IVec4 & bits,const Vec4 & value)2204*35238bceSAndroid Build Coastguard Worker Vec4 computeFloatingPointThreshold(const IVec4 &bits, const Vec4 &value)
2205*35238bceSAndroid Build Coastguard Worker {
2206*35238bceSAndroid Build Coastguard Worker     return computeFloatingPointError(value, bits);
2207*35238bceSAndroid Build Coastguard Worker }
2208*35238bceSAndroid Build Coastguard Worker 
computeColorBitsThreshold(const IVec4 & bits,const IVec4 & numAccurateBits)2209*35238bceSAndroid Build Coastguard Worker Vec4 computeColorBitsThreshold(const IVec4 &bits, const IVec4 &numAccurateBits)
2210*35238bceSAndroid Build Coastguard Worker {
2211*35238bceSAndroid Build Coastguard Worker     return computeColorBitsError(bits, numAccurateBits);
2212*35238bceSAndroid Build Coastguard Worker }
2213*35238bceSAndroid Build Coastguard Worker 
computeLodBoundsFromDerivates(const float dudx,const float dvdx,const float dwdx,const float dudy,const float dvdy,const float dwdy,const LodPrecision & prec)2214*35238bceSAndroid Build Coastguard Worker Vec2 computeLodBoundsFromDerivates(const float dudx, const float dvdx, const float dwdx, const float dudy,
2215*35238bceSAndroid Build Coastguard Worker                                    const float dvdy, const float dwdy, const LodPrecision &prec)
2216*35238bceSAndroid Build Coastguard Worker {
2217*35238bceSAndroid Build Coastguard Worker     const float mux = deFloatAbs(dudx);
2218*35238bceSAndroid Build Coastguard Worker     const float mvx = deFloatAbs(dvdx);
2219*35238bceSAndroid Build Coastguard Worker     const float mwx = deFloatAbs(dwdx);
2220*35238bceSAndroid Build Coastguard Worker     const float muy = deFloatAbs(dudy);
2221*35238bceSAndroid Build Coastguard Worker     const float mvy = deFloatAbs(dvdy);
2222*35238bceSAndroid Build Coastguard Worker     const float mwy = deFloatAbs(dwdy);
2223*35238bceSAndroid Build Coastguard Worker 
2224*35238bceSAndroid Build Coastguard Worker     // Ideal:
2225*35238bceSAndroid Build Coastguard Worker     // px = deFloatSqrt2(mux*mux + mvx*mvx + mwx*mwx);
2226*35238bceSAndroid Build Coastguard Worker     // py = deFloatSqrt2(muy*muy + mvy*mvy + mwy*mwy);
2227*35238bceSAndroid Build Coastguard Worker 
2228*35238bceSAndroid Build Coastguard Worker     // fx, fy estimate lower bounds
2229*35238bceSAndroid Build Coastguard Worker     const float fxMin = de::max(de::max(mux, mvx), mwx);
2230*35238bceSAndroid Build Coastguard Worker     const float fyMin = de::max(de::max(muy, mvy), mwy);
2231*35238bceSAndroid Build Coastguard Worker 
2232*35238bceSAndroid Build Coastguard Worker     // fx, fy estimate upper bounds
2233*35238bceSAndroid Build Coastguard Worker     const float sqrt2 = deFloatSqrt(2.0f);
2234*35238bceSAndroid Build Coastguard Worker     const float fxMax = sqrt2 * (mux + mvx + mwx);
2235*35238bceSAndroid Build Coastguard Worker     const float fyMax = sqrt2 * (muy + mvy + mwy);
2236*35238bceSAndroid Build Coastguard Worker 
2237*35238bceSAndroid Build Coastguard Worker     // p = max(px, py) (isotropic filtering)
2238*35238bceSAndroid Build Coastguard Worker     const float pMin = de::max(fxMin, fyMin);
2239*35238bceSAndroid Build Coastguard Worker     const float pMax = de::max(fxMax, fyMax);
2240*35238bceSAndroid Build Coastguard Worker 
2241*35238bceSAndroid Build Coastguard Worker     // error terms
2242*35238bceSAndroid Build Coastguard Worker     const float pMinErr = computeFloatingPointError(pMin, prec.derivateBits);
2243*35238bceSAndroid Build Coastguard Worker     const float pMaxErr = computeFloatingPointError(pMax, prec.derivateBits);
2244*35238bceSAndroid Build Coastguard Worker 
2245*35238bceSAndroid Build Coastguard Worker     const float minLod = deFloatLog2(pMin - pMinErr);
2246*35238bceSAndroid Build Coastguard Worker     const float maxLod = deFloatLog2(pMax + pMaxErr);
2247*35238bceSAndroid Build Coastguard Worker     const float lodErr = computeFixedPointError(prec.lodBits);
2248*35238bceSAndroid Build Coastguard Worker 
2249*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(minLod <= maxLod);
2250*35238bceSAndroid Build Coastguard Worker     return Vec2(minLod - lodErr, maxLod + lodErr);
2251*35238bceSAndroid Build Coastguard Worker }
2252*35238bceSAndroid Build Coastguard Worker 
computeLodBoundsFromDerivates(const float dudx,const float dvdx,const float dudy,const float dvdy,const LodPrecision & prec)2253*35238bceSAndroid Build Coastguard Worker Vec2 computeLodBoundsFromDerivates(const float dudx, const float dvdx, const float dudy, const float dvdy,
2254*35238bceSAndroid Build Coastguard Worker                                    const LodPrecision &prec)
2255*35238bceSAndroid Build Coastguard Worker {
2256*35238bceSAndroid Build Coastguard Worker     return computeLodBoundsFromDerivates(dudx, dvdx, 0.0f, dudy, dvdy, 0.0f, prec);
2257*35238bceSAndroid Build Coastguard Worker }
2258*35238bceSAndroid Build Coastguard Worker 
computeLodBoundsFromDerivates(const float dudx,const float dudy,const LodPrecision & prec)2259*35238bceSAndroid Build Coastguard Worker Vec2 computeLodBoundsFromDerivates(const float dudx, const float dudy, const LodPrecision &prec)
2260*35238bceSAndroid Build Coastguard Worker {
2261*35238bceSAndroid Build Coastguard Worker     return computeLodBoundsFromDerivates(dudx, 0.0f, 0.0f, dudy, 0.0f, 0.0f, prec);
2262*35238bceSAndroid Build Coastguard Worker }
2263*35238bceSAndroid Build Coastguard Worker 
computeCubeLodBoundsFromDerivates(const Vec3 & coord,const Vec3 & coordDx,const Vec3 & coordDy,const int faceSize,const LodPrecision & prec)2264*35238bceSAndroid Build Coastguard Worker Vec2 computeCubeLodBoundsFromDerivates(const Vec3 &coord, const Vec3 &coordDx, const Vec3 &coordDy, const int faceSize,
2265*35238bceSAndroid Build Coastguard Worker                                        const LodPrecision &prec)
2266*35238bceSAndroid Build Coastguard Worker {
2267*35238bceSAndroid Build Coastguard Worker     const bool allowBrokenEdgeDerivate = false;
2268*35238bceSAndroid Build Coastguard Worker     const CubeFace face                = selectCubeFace(coord);
2269*35238bceSAndroid Build Coastguard Worker     int maNdx                          = 0;
2270*35238bceSAndroid Build Coastguard Worker     int sNdx                           = 0;
2271*35238bceSAndroid Build Coastguard Worker     int tNdx                           = 0;
2272*35238bceSAndroid Build Coastguard Worker 
2273*35238bceSAndroid Build Coastguard Worker     // \note Derivate signs don't matter when computing lod
2274*35238bceSAndroid Build Coastguard Worker     switch (face)
2275*35238bceSAndroid Build Coastguard Worker     {
2276*35238bceSAndroid Build Coastguard Worker     case CUBEFACE_NEGATIVE_X:
2277*35238bceSAndroid Build Coastguard Worker     case CUBEFACE_POSITIVE_X:
2278*35238bceSAndroid Build Coastguard Worker         maNdx = 0;
2279*35238bceSAndroid Build Coastguard Worker         sNdx  = 2;
2280*35238bceSAndroid Build Coastguard Worker         tNdx  = 1;
2281*35238bceSAndroid Build Coastguard Worker         break;
2282*35238bceSAndroid Build Coastguard Worker     case CUBEFACE_NEGATIVE_Y:
2283*35238bceSAndroid Build Coastguard Worker     case CUBEFACE_POSITIVE_Y:
2284*35238bceSAndroid Build Coastguard Worker         maNdx = 1;
2285*35238bceSAndroid Build Coastguard Worker         sNdx  = 0;
2286*35238bceSAndroid Build Coastguard Worker         tNdx  = 2;
2287*35238bceSAndroid Build Coastguard Worker         break;
2288*35238bceSAndroid Build Coastguard Worker     case CUBEFACE_NEGATIVE_Z:
2289*35238bceSAndroid Build Coastguard Worker     case CUBEFACE_POSITIVE_Z:
2290*35238bceSAndroid Build Coastguard Worker         maNdx = 2;
2291*35238bceSAndroid Build Coastguard Worker         sNdx  = 0;
2292*35238bceSAndroid Build Coastguard Worker         tNdx  = 1;
2293*35238bceSAndroid Build Coastguard Worker         break;
2294*35238bceSAndroid Build Coastguard Worker     default:
2295*35238bceSAndroid Build Coastguard Worker         DE_ASSERT(false);
2296*35238bceSAndroid Build Coastguard Worker     }
2297*35238bceSAndroid Build Coastguard Worker 
2298*35238bceSAndroid Build Coastguard Worker     {
2299*35238bceSAndroid Build Coastguard Worker         const float sc    = coord[sNdx];
2300*35238bceSAndroid Build Coastguard Worker         const float tc    = coord[tNdx];
2301*35238bceSAndroid Build Coastguard Worker         const float ma    = de::abs(coord[maNdx]);
2302*35238bceSAndroid Build Coastguard Worker         const float scdx  = coordDx[sNdx];
2303*35238bceSAndroid Build Coastguard Worker         const float tcdx  = coordDx[tNdx];
2304*35238bceSAndroid Build Coastguard Worker         const float madx  = de::abs(coordDx[maNdx]);
2305*35238bceSAndroid Build Coastguard Worker         const float scdy  = coordDy[sNdx];
2306*35238bceSAndroid Build Coastguard Worker         const float tcdy  = coordDy[tNdx];
2307*35238bceSAndroid Build Coastguard Worker         const float mady  = de::abs(coordDy[maNdx]);
2308*35238bceSAndroid Build Coastguard Worker         const float dudx  = float(faceSize) * 0.5f * (scdx * ma - sc * madx) / (ma * ma);
2309*35238bceSAndroid Build Coastguard Worker         const float dvdx  = float(faceSize) * 0.5f * (tcdx * ma - tc * madx) / (ma * ma);
2310*35238bceSAndroid Build Coastguard Worker         const float dudy  = float(faceSize) * 0.5f * (scdy * ma - sc * mady) / (ma * ma);
2311*35238bceSAndroid Build Coastguard Worker         const float dvdy  = float(faceSize) * 0.5f * (tcdy * ma - tc * mady) / (ma * ma);
2312*35238bceSAndroid Build Coastguard Worker         const Vec2 bounds = computeLodBoundsFromDerivates(dudx, dvdx, dudy, dvdy, prec);
2313*35238bceSAndroid Build Coastguard Worker 
2314*35238bceSAndroid Build Coastguard Worker         // Implementations may compute derivate from projected (s, t) resulting in incorrect values at edges.
2315*35238bceSAndroid Build Coastguard Worker         if (allowBrokenEdgeDerivate)
2316*35238bceSAndroid Build Coastguard Worker         {
2317*35238bceSAndroid Build Coastguard Worker             const Vec3 dxErr = computeFloatingPointError(coordDx, IVec3(prec.derivateBits));
2318*35238bceSAndroid Build Coastguard Worker             const Vec3 dyErr = computeFloatingPointError(coordDy, IVec3(prec.derivateBits));
2319*35238bceSAndroid Build Coastguard Worker             const Vec3 xoffs = abs(coordDx) + dxErr;
2320*35238bceSAndroid Build Coastguard Worker             const Vec3 yoffs = abs(coordDy) + dyErr;
2321*35238bceSAndroid Build Coastguard Worker 
2322*35238bceSAndroid Build Coastguard Worker             if (selectCubeFace(coord + xoffs) != face || selectCubeFace(coord - xoffs) != face ||
2323*35238bceSAndroid Build Coastguard Worker                 selectCubeFace(coord + yoffs) != face || selectCubeFace(coord - yoffs) != face)
2324*35238bceSAndroid Build Coastguard Worker             {
2325*35238bceSAndroid Build Coastguard Worker                 return Vec2(bounds.x(), 1000.0f);
2326*35238bceSAndroid Build Coastguard Worker             }
2327*35238bceSAndroid Build Coastguard Worker         }
2328*35238bceSAndroid Build Coastguard Worker 
2329*35238bceSAndroid Build Coastguard Worker         return bounds;
2330*35238bceSAndroid Build Coastguard Worker     }
2331*35238bceSAndroid Build Coastguard Worker }
2332*35238bceSAndroid Build Coastguard Worker 
clampLodBounds(const Vec2 & lodBounds,const Vec2 & lodMinMax,const LodPrecision & prec)2333*35238bceSAndroid Build Coastguard Worker Vec2 clampLodBounds(const Vec2 &lodBounds, const Vec2 &lodMinMax, const LodPrecision &prec)
2334*35238bceSAndroid Build Coastguard Worker {
2335*35238bceSAndroid Build Coastguard Worker     const float lodErr = computeFixedPointError(prec.lodBits);
2336*35238bceSAndroid Build Coastguard Worker     const float a      = lodMinMax.x();
2337*35238bceSAndroid Build Coastguard Worker     const float b      = lodMinMax.y();
2338*35238bceSAndroid Build Coastguard Worker     return Vec2(de::clamp(lodBounds.x(), a - lodErr, b - lodErr), de::clamp(lodBounds.y(), a + lodErr, b + lodErr));
2339*35238bceSAndroid Build Coastguard Worker }
2340*35238bceSAndroid Build Coastguard Worker 
isLevel1DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const LookupPrecision & prec,const float coordX,const int coordY,const Vec4 & result)2341*35238bceSAndroid Build Coastguard Worker bool isLevel1DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2342*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const LookupPrecision &prec, const float coordX,
2343*35238bceSAndroid Build Coastguard Worker                                 const int coordY, const Vec4 &result)
2344*35238bceSAndroid Build Coastguard Worker {
2345*35238bceSAndroid Build Coastguard Worker     const Sampler::FilterMode filterMode =
2346*35238bceSAndroid Build Coastguard Worker         scaleMode == TEX_LOOKUP_SCALE_MAGNIFY ? sampler.magFilter : sampler.minFilter;
2347*35238bceSAndroid Build Coastguard Worker     return isLevelSampleResultValid(access, sampler, filterMode, prec, coordX, coordY, result);
2348*35238bceSAndroid Build Coastguard Worker }
2349*35238bceSAndroid Build Coastguard Worker 
isLevel1DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const IntLookupPrecision & prec,const float coordX,const int coordY,const IVec4 & result)2350*35238bceSAndroid Build Coastguard Worker bool isLevel1DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2351*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const IntLookupPrecision &prec, const float coordX,
2352*35238bceSAndroid Build Coastguard Worker                                 const int coordY, const IVec4 &result)
2353*35238bceSAndroid Build Coastguard Worker {
2354*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(sampler.minFilter == Sampler::NEAREST && sampler.magFilter == Sampler::NEAREST);
2355*35238bceSAndroid Build Coastguard Worker     DE_UNREF(scaleMode);
2356*35238bceSAndroid Build Coastguard Worker     return isNearestSampleResultValid(access, sampler, prec, coordX, coordY, result);
2357*35238bceSAndroid Build Coastguard Worker }
2358*35238bceSAndroid Build Coastguard Worker 
isLevel1DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const IntLookupPrecision & prec,const float coordX,const int coordY,const UVec4 & result)2359*35238bceSAndroid Build Coastguard Worker bool isLevel1DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2360*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const IntLookupPrecision &prec, const float coordX,
2361*35238bceSAndroid Build Coastguard Worker                                 const int coordY, const UVec4 &result)
2362*35238bceSAndroid Build Coastguard Worker {
2363*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(sampler.minFilter == Sampler::NEAREST && sampler.magFilter == Sampler::NEAREST);
2364*35238bceSAndroid Build Coastguard Worker     DE_UNREF(scaleMode);
2365*35238bceSAndroid Build Coastguard Worker     return isNearestSampleResultValid(access, sampler, prec, coordX, coordY, result);
2366*35238bceSAndroid Build Coastguard Worker }
2367*35238bceSAndroid Build Coastguard Worker 
isLevel2DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const LookupPrecision & prec,const Vec2 & coord,const int coordZ,const Vec4 & result)2368*35238bceSAndroid Build Coastguard Worker bool isLevel2DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2369*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const LookupPrecision &prec, const Vec2 &coord,
2370*35238bceSAndroid Build Coastguard Worker                                 const int coordZ, const Vec4 &result)
2371*35238bceSAndroid Build Coastguard Worker {
2372*35238bceSAndroid Build Coastguard Worker     const Sampler::FilterMode filterMode =
2373*35238bceSAndroid Build Coastguard Worker         scaleMode == TEX_LOOKUP_SCALE_MAGNIFY ? sampler.magFilter : sampler.minFilter;
2374*35238bceSAndroid Build Coastguard Worker     return isLevelSampleResultValid(access, sampler, filterMode, prec, coord, coordZ, result);
2375*35238bceSAndroid Build Coastguard Worker }
2376*35238bceSAndroid Build Coastguard Worker 
isLevel2DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const IntLookupPrecision & prec,const Vec2 & coord,const int coordZ,const IVec4 & result)2377*35238bceSAndroid Build Coastguard Worker bool isLevel2DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2378*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const IntLookupPrecision &prec, const Vec2 &coord,
2379*35238bceSAndroid Build Coastguard Worker                                 const int coordZ, const IVec4 &result)
2380*35238bceSAndroid Build Coastguard Worker {
2381*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(sampler.minFilter == Sampler::NEAREST && sampler.magFilter == Sampler::NEAREST);
2382*35238bceSAndroid Build Coastguard Worker     DE_UNREF(scaleMode);
2383*35238bceSAndroid Build Coastguard Worker     return isNearestSampleResultValid(access, sampler, prec, coord, coordZ, result);
2384*35238bceSAndroid Build Coastguard Worker }
2385*35238bceSAndroid Build Coastguard Worker 
isLevel2DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const IntLookupPrecision & prec,const Vec2 & coord,const int coordZ,const UVec4 & result)2386*35238bceSAndroid Build Coastguard Worker bool isLevel2DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2387*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const IntLookupPrecision &prec, const Vec2 &coord,
2388*35238bceSAndroid Build Coastguard Worker                                 const int coordZ, const UVec4 &result)
2389*35238bceSAndroid Build Coastguard Worker {
2390*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(sampler.minFilter == Sampler::NEAREST && sampler.magFilter == Sampler::NEAREST);
2391*35238bceSAndroid Build Coastguard Worker     DE_UNREF(scaleMode);
2392*35238bceSAndroid Build Coastguard Worker     return isNearestSampleResultValid(access, sampler, prec, coord, coordZ, result);
2393*35238bceSAndroid Build Coastguard Worker }
2394*35238bceSAndroid Build Coastguard Worker 
isLevel3DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const LookupPrecision & prec,const Vec3 & coord,const Vec4 & result)2395*35238bceSAndroid Build Coastguard Worker bool isLevel3DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2396*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const LookupPrecision &prec, const Vec3 &coord,
2397*35238bceSAndroid Build Coastguard Worker                                 const Vec4 &result)
2398*35238bceSAndroid Build Coastguard Worker {
2399*35238bceSAndroid Build Coastguard Worker     const tcu::Sampler::FilterMode filterMode =
2400*35238bceSAndroid Build Coastguard Worker         scaleMode == TEX_LOOKUP_SCALE_MAGNIFY ? sampler.magFilter : sampler.minFilter;
2401*35238bceSAndroid Build Coastguard Worker     return isLevelSampleResultValid(access, sampler, filterMode, prec, coord, result);
2402*35238bceSAndroid Build Coastguard Worker }
2403*35238bceSAndroid Build Coastguard Worker 
isLevel3DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const IntLookupPrecision & prec,const Vec3 & coord,const IVec4 & result)2404*35238bceSAndroid Build Coastguard Worker bool isLevel3DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2405*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const IntLookupPrecision &prec, const Vec3 &coord,
2406*35238bceSAndroid Build Coastguard Worker                                 const IVec4 &result)
2407*35238bceSAndroid Build Coastguard Worker {
2408*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(sampler.minFilter == Sampler::NEAREST && sampler.magFilter == Sampler::NEAREST);
2409*35238bceSAndroid Build Coastguard Worker     DE_UNREF(scaleMode);
2410*35238bceSAndroid Build Coastguard Worker     return isNearestSampleResultValid(access, sampler, prec, coord, result);
2411*35238bceSAndroid Build Coastguard Worker }
2412*35238bceSAndroid Build Coastguard Worker 
isLevel3DLookupResultValid(const ConstPixelBufferAccess & access,const Sampler & sampler,TexLookupScaleMode scaleMode,const IntLookupPrecision & prec,const Vec3 & coord,const UVec4 & result)2413*35238bceSAndroid Build Coastguard Worker bool isLevel3DLookupResultValid(const ConstPixelBufferAccess &access, const Sampler &sampler,
2414*35238bceSAndroid Build Coastguard Worker                                 TexLookupScaleMode scaleMode, const IntLookupPrecision &prec, const Vec3 &coord,
2415*35238bceSAndroid Build Coastguard Worker                                 const UVec4 &result)
2416*35238bceSAndroid Build Coastguard Worker {
2417*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(sampler.minFilter == Sampler::NEAREST && sampler.magFilter == Sampler::NEAREST);
2418*35238bceSAndroid Build Coastguard Worker     DE_UNREF(scaleMode);
2419*35238bceSAndroid Build Coastguard Worker     return isNearestSampleResultValid(access, sampler, prec, coord, result);
2420*35238bceSAndroid Build Coastguard Worker }
2421*35238bceSAndroid Build Coastguard Worker 
2422*35238bceSAndroid Build Coastguard Worker template <typename PrecType, typename ScalarType>
isGatherOffsetsResultValid(const ConstPixelBufferAccess & level,const Sampler & sampler,const PrecType & prec,const Vec2 & coord,int coordZ,int componentNdx,const IVec2 (& offsets)[4],const Vector<ScalarType,4> & result)2423*35238bceSAndroid Build Coastguard Worker static bool isGatherOffsetsResultValid(const ConstPixelBufferAccess &level, const Sampler &sampler,
2424*35238bceSAndroid Build Coastguard Worker                                        const PrecType &prec, const Vec2 &coord, int coordZ, int componentNdx,
2425*35238bceSAndroid Build Coastguard Worker                                        const IVec2 (&offsets)[4], const Vector<ScalarType, 4> &result)
2426*35238bceSAndroid Build Coastguard Worker {
2427*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(),
2428*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.x(), prec.uvwBits.x());
2429*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(),
2430*35238bceSAndroid Build Coastguard Worker                                                          prec.coordBits.y(), prec.uvwBits.y());
2431*35238bceSAndroid Build Coastguard Worker 
2432*35238bceSAndroid Build Coastguard Worker     // Integer coordinate bounds for (x0, y0) - without wrap mode
2433*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x() - 0.5f);
2434*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y() - 0.5f);
2435*35238bceSAndroid Build Coastguard Worker     const int minJ = deFloorFloatToInt32(vBounds.x() - 0.5f);
2436*35238bceSAndroid Build Coastguard Worker     const int maxJ = deFloorFloatToInt32(vBounds.y() - 0.5f);
2437*35238bceSAndroid Build Coastguard Worker 
2438*35238bceSAndroid Build Coastguard Worker     const int w = level.getWidth();
2439*35238bceSAndroid Build Coastguard Worker     const int h = level.getHeight();
2440*35238bceSAndroid Build Coastguard Worker 
2441*35238bceSAndroid Build Coastguard Worker     for (int j = minJ; j <= maxJ; j++)
2442*35238bceSAndroid Build Coastguard Worker     {
2443*35238bceSAndroid Build Coastguard Worker         for (int i = minI; i <= maxI; i++)
2444*35238bceSAndroid Build Coastguard Worker         {
2445*35238bceSAndroid Build Coastguard Worker             Vector<ScalarType, 4> color;
2446*35238bceSAndroid Build Coastguard Worker             for (int offNdx = 0; offNdx < 4; offNdx++)
2447*35238bceSAndroid Build Coastguard Worker             {
2448*35238bceSAndroid Build Coastguard Worker                 // offNdx-th coordinate offset and then wrapped.
2449*35238bceSAndroid Build Coastguard Worker                 const int x   = wrap(sampler.wrapS, i + offsets[offNdx].x(), w);
2450*35238bceSAndroid Build Coastguard Worker                 const int y   = wrap(sampler.wrapT, j + offsets[offNdx].y(), h);
2451*35238bceSAndroid Build Coastguard Worker                 color[offNdx] = lookup<ScalarType>(level, sampler, x, y, coordZ)[componentNdx];
2452*35238bceSAndroid Build Coastguard Worker             }
2453*35238bceSAndroid Build Coastguard Worker 
2454*35238bceSAndroid Build Coastguard Worker             if (isColorValid(prec, color, result))
2455*35238bceSAndroid Build Coastguard Worker                 return true;
2456*35238bceSAndroid Build Coastguard Worker         }
2457*35238bceSAndroid Build Coastguard Worker     }
2458*35238bceSAndroid Build Coastguard Worker 
2459*35238bceSAndroid Build Coastguard Worker     return false;
2460*35238bceSAndroid Build Coastguard Worker }
2461*35238bceSAndroid Build Coastguard Worker 
isGatherOffsetsResultValid(const Texture2DView & texture,const Sampler & sampler,const LookupPrecision & prec,const Vec2 & coord,int componentNdx,const IVec2 (& offsets)[4],const Vec4 & result)2462*35238bceSAndroid Build Coastguard Worker bool isGatherOffsetsResultValid(const Texture2DView &texture, const Sampler &sampler, const LookupPrecision &prec,
2463*35238bceSAndroid Build Coastguard Worker                                 const Vec2 &coord, int componentNdx, const IVec2 (&offsets)[4], const Vec4 &result)
2464*35238bceSAndroid Build Coastguard Worker {
2465*35238bceSAndroid Build Coastguard Worker     return isGatherOffsetsResultValid(texture.getLevel(0), sampler, prec, coord, 0, componentNdx, offsets, result);
2466*35238bceSAndroid Build Coastguard Worker }
2467*35238bceSAndroid Build Coastguard Worker 
isGatherOffsetsResultValid(const Texture2DView & texture,const Sampler & sampler,const IntLookupPrecision & prec,const Vec2 & coord,int componentNdx,const IVec2 (& offsets)[4],const IVec4 & result)2468*35238bceSAndroid Build Coastguard Worker bool isGatherOffsetsResultValid(const Texture2DView &texture, const Sampler &sampler, const IntLookupPrecision &prec,
2469*35238bceSAndroid Build Coastguard Worker                                 const Vec2 &coord, int componentNdx, const IVec2 (&offsets)[4], const IVec4 &result)
2470*35238bceSAndroid Build Coastguard Worker {
2471*35238bceSAndroid Build Coastguard Worker     return isGatherOffsetsResultValid(texture.getLevel(0), sampler, prec, coord, 0, componentNdx, offsets, result);
2472*35238bceSAndroid Build Coastguard Worker }
2473*35238bceSAndroid Build Coastguard Worker 
isGatherOffsetsResultValid(const Texture2DView & texture,const Sampler & sampler,const IntLookupPrecision & prec,const Vec2 & coord,int componentNdx,const IVec2 (& offsets)[4],const UVec4 & result)2474*35238bceSAndroid Build Coastguard Worker bool isGatherOffsetsResultValid(const Texture2DView &texture, const Sampler &sampler, const IntLookupPrecision &prec,
2475*35238bceSAndroid Build Coastguard Worker                                 const Vec2 &coord, int componentNdx, const IVec2 (&offsets)[4], const UVec4 &result)
2476*35238bceSAndroid Build Coastguard Worker {
2477*35238bceSAndroid Build Coastguard Worker     return isGatherOffsetsResultValid(texture.getLevel(0), sampler, prec, coord, 0, componentNdx, offsets, result);
2478*35238bceSAndroid Build Coastguard Worker }
2479*35238bceSAndroid Build Coastguard Worker 
2480*35238bceSAndroid Build Coastguard Worker template <typename PrecType, typename ScalarType>
is2DArrayGatherOffsetsResultValid(const Texture2DArrayView & texture,const Sampler & sampler,const PrecType & prec,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4],const Vector<ScalarType,4> & result)2481*35238bceSAndroid Build Coastguard Worker static bool is2DArrayGatherOffsetsResultValid(const Texture2DArrayView &texture, const Sampler &sampler,
2482*35238bceSAndroid Build Coastguard Worker                                               const PrecType &prec, const Vec3 &coord, int componentNdx,
2483*35238bceSAndroid Build Coastguard Worker                                               const IVec2 (&offsets)[4], const Vector<ScalarType, 4> &result)
2484*35238bceSAndroid Build Coastguard Worker {
2485*35238bceSAndroid Build Coastguard Worker     const IVec2 layerRange = computeLayerRange(texture.getNumLayers(), prec.coordBits.z(), coord.z());
2486*35238bceSAndroid Build Coastguard Worker     for (int layer = layerRange.x(); layer <= layerRange.y(); layer++)
2487*35238bceSAndroid Build Coastguard Worker     {
2488*35238bceSAndroid Build Coastguard Worker         if (isGatherOffsetsResultValid(texture.getLevel(0), sampler, prec, coord.swizzle(0, 1), layer, componentNdx,
2489*35238bceSAndroid Build Coastguard Worker                                        offsets, result))
2490*35238bceSAndroid Build Coastguard Worker             return true;
2491*35238bceSAndroid Build Coastguard Worker     }
2492*35238bceSAndroid Build Coastguard Worker     return false;
2493*35238bceSAndroid Build Coastguard Worker }
2494*35238bceSAndroid Build Coastguard Worker 
isGatherOffsetsResultValid(const Texture2DArrayView & texture,const Sampler & sampler,const LookupPrecision & prec,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4],const Vec4 & result)2495*35238bceSAndroid Build Coastguard Worker bool isGatherOffsetsResultValid(const Texture2DArrayView &texture, const Sampler &sampler, const LookupPrecision &prec,
2496*35238bceSAndroid Build Coastguard Worker                                 const Vec3 &coord, int componentNdx, const IVec2 (&offsets)[4], const Vec4 &result)
2497*35238bceSAndroid Build Coastguard Worker {
2498*35238bceSAndroid Build Coastguard Worker     return is2DArrayGatherOffsetsResultValid(texture, sampler, prec, coord, componentNdx, offsets, result);
2499*35238bceSAndroid Build Coastguard Worker }
2500*35238bceSAndroid Build Coastguard Worker 
isGatherOffsetsResultValid(const Texture2DArrayView & texture,const Sampler & sampler,const IntLookupPrecision & prec,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4],const IVec4 & result)2501*35238bceSAndroid Build Coastguard Worker bool isGatherOffsetsResultValid(const Texture2DArrayView &texture, const Sampler &sampler,
2502*35238bceSAndroid Build Coastguard Worker                                 const IntLookupPrecision &prec, const Vec3 &coord, int componentNdx,
2503*35238bceSAndroid Build Coastguard Worker                                 const IVec2 (&offsets)[4], const IVec4 &result)
2504*35238bceSAndroid Build Coastguard Worker {
2505*35238bceSAndroid Build Coastguard Worker     return is2DArrayGatherOffsetsResultValid(texture, sampler, prec, coord, componentNdx, offsets, result);
2506*35238bceSAndroid Build Coastguard Worker }
2507*35238bceSAndroid Build Coastguard Worker 
isGatherOffsetsResultValid(const Texture2DArrayView & texture,const Sampler & sampler,const IntLookupPrecision & prec,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4],const UVec4 & result)2508*35238bceSAndroid Build Coastguard Worker bool isGatherOffsetsResultValid(const Texture2DArrayView &texture, const Sampler &sampler,
2509*35238bceSAndroid Build Coastguard Worker                                 const IntLookupPrecision &prec, const Vec3 &coord, int componentNdx,
2510*35238bceSAndroid Build Coastguard Worker                                 const IVec2 (&offsets)[4], const UVec4 &result)
2511*35238bceSAndroid Build Coastguard Worker {
2512*35238bceSAndroid Build Coastguard Worker     return is2DArrayGatherOffsetsResultValid(texture, sampler, prec, coord, componentNdx, offsets, result);
2513*35238bceSAndroid Build Coastguard Worker }
2514*35238bceSAndroid Build Coastguard Worker 
2515*35238bceSAndroid Build Coastguard Worker template <typename PrecType, typename ScalarType>
isGatherResultValid(const TextureCubeView & texture,const Sampler & sampler,const PrecType & prec,const CubeFaceFloatCoords & coords,int componentNdx,const Vector<ScalarType,4> & result)2516*35238bceSAndroid Build Coastguard Worker static bool isGatherResultValid(const TextureCubeView &texture, const Sampler &sampler, const PrecType &prec,
2517*35238bceSAndroid Build Coastguard Worker                                 const CubeFaceFloatCoords &coords, int componentNdx,
2518*35238bceSAndroid Build Coastguard Worker                                 const Vector<ScalarType, 4> &result)
2519*35238bceSAndroid Build Coastguard Worker {
2520*35238bceSAndroid Build Coastguard Worker     const int size = texture.getLevelFace(0, coords.face).getWidth();
2521*35238bceSAndroid Build Coastguard Worker 
2522*35238bceSAndroid Build Coastguard Worker     const Vec2 uBounds =
2523*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
2524*35238bceSAndroid Build Coastguard Worker     const Vec2 vBounds =
2525*35238bceSAndroid Build Coastguard Worker         computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
2526*35238bceSAndroid Build Coastguard Worker 
2527*35238bceSAndroid Build Coastguard Worker     // Integer coordinate bounds for (x0,y0) - without wrap mode
2528*35238bceSAndroid Build Coastguard Worker     const int minI = deFloorFloatToInt32(uBounds.x() - 0.5f);
2529*35238bceSAndroid Build Coastguard Worker     const int maxI = deFloorFloatToInt32(uBounds.y() - 0.5f);
2530*35238bceSAndroid Build Coastguard Worker     const int minJ = deFloorFloatToInt32(vBounds.x() - 0.5f);
2531*35238bceSAndroid Build Coastguard Worker     const int maxJ = deFloorFloatToInt32(vBounds.y() - 0.5f);
2532*35238bceSAndroid Build Coastguard Worker 
2533*35238bceSAndroid Build Coastguard Worker     // Face accesses
2534*35238bceSAndroid Build Coastguard Worker     ConstPixelBufferAccess faces[CUBEFACE_LAST];
2535*35238bceSAndroid Build Coastguard Worker     for (int face = 0; face < CUBEFACE_LAST; face++)
2536*35238bceSAndroid Build Coastguard Worker         faces[face] = texture.getLevelFace(0, CubeFace(face));
2537*35238bceSAndroid Build Coastguard Worker 
2538*35238bceSAndroid Build Coastguard Worker     for (int j = minJ; j <= maxJ; j++)
2539*35238bceSAndroid Build Coastguard Worker     {
2540*35238bceSAndroid Build Coastguard Worker         for (int i = minI; i <= maxI; i++)
2541*35238bceSAndroid Build Coastguard Worker         {
2542*35238bceSAndroid Build Coastguard Worker             static const IVec2 offsets[4] = {IVec2(0, 1), IVec2(1, 1), IVec2(1, 0), IVec2(0, 0)};
2543*35238bceSAndroid Build Coastguard Worker 
2544*35238bceSAndroid Build Coastguard Worker             Vector<ScalarType, 4> color;
2545*35238bceSAndroid Build Coastguard Worker             for (int offNdx = 0; offNdx < 4; offNdx++)
2546*35238bceSAndroid Build Coastguard Worker             {
2547*35238bceSAndroid Build Coastguard Worker                 const CubeFaceIntCoords c = remapCubeEdgeCoords(
2548*35238bceSAndroid Build Coastguard Worker                     CubeFaceIntCoords(coords.face, i + offsets[offNdx].x(), j + offsets[offNdx].y()), size);
2549*35238bceSAndroid Build Coastguard Worker                 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
2550*35238bceSAndroid Build Coastguard Worker                 // \todo [2014-06-05 nuutti] Test the special case where all corner pixels have exactly the same color.
2551*35238bceSAndroid Build Coastguard Worker                 //                             See also isSeamlessLinearSampleResultValid and similar.
2552*35238bceSAndroid Build Coastguard Worker                 if (c.face == CUBEFACE_LAST)
2553*35238bceSAndroid Build Coastguard Worker                     return true;
2554*35238bceSAndroid Build Coastguard Worker 
2555*35238bceSAndroid Build Coastguard Worker                 color[offNdx] = lookup<ScalarType>(faces[c.face], sampler, c.s, c.t, 0)[componentNdx];
2556*35238bceSAndroid Build Coastguard Worker             }
2557*35238bceSAndroid Build Coastguard Worker 
2558*35238bceSAndroid Build Coastguard Worker             if (isColorValid(prec, color, result))
2559*35238bceSAndroid Build Coastguard Worker                 return true;
2560*35238bceSAndroid Build Coastguard Worker         }
2561*35238bceSAndroid Build Coastguard Worker     }
2562*35238bceSAndroid Build Coastguard Worker 
2563*35238bceSAndroid Build Coastguard Worker     return false;
2564*35238bceSAndroid Build Coastguard Worker }
2565*35238bceSAndroid Build Coastguard Worker 
2566*35238bceSAndroid Build Coastguard Worker template <typename PrecType, typename ScalarType>
isCubeGatherResultValid(const TextureCubeView & texture,const Sampler & sampler,const PrecType & prec,const Vec3 & coord,int componentNdx,const Vector<ScalarType,4> & result)2567*35238bceSAndroid Build Coastguard Worker static bool isCubeGatherResultValid(const TextureCubeView &texture, const Sampler &sampler, const PrecType &prec,
2568*35238bceSAndroid Build Coastguard Worker                                     const Vec3 &coord, int componentNdx, const Vector<ScalarType, 4> &result)
2569*35238bceSAndroid Build Coastguard Worker {
2570*35238bceSAndroid Build Coastguard Worker     int numPossibleFaces = 0;
2571*35238bceSAndroid Build Coastguard Worker     CubeFace possibleFaces[CUBEFACE_LAST];
2572*35238bceSAndroid Build Coastguard Worker 
2573*35238bceSAndroid Build Coastguard Worker     getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
2574*35238bceSAndroid Build Coastguard Worker 
2575*35238bceSAndroid Build Coastguard Worker     if (numPossibleFaces == 0)
2576*35238bceSAndroid Build Coastguard Worker         return true; // Result is undefined.
2577*35238bceSAndroid Build Coastguard Worker 
2578*35238bceSAndroid Build Coastguard Worker     for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
2579*35238bceSAndroid Build Coastguard Worker     {
2580*35238bceSAndroid Build Coastguard Worker         const CubeFaceFloatCoords faceCoords(possibleFaces[tryFaceNdx],
2581*35238bceSAndroid Build Coastguard Worker                                              projectToFace(possibleFaces[tryFaceNdx], coord));
2582*35238bceSAndroid Build Coastguard Worker 
2583*35238bceSAndroid Build Coastguard Worker         if (isGatherResultValid(texture, sampler, prec, faceCoords, componentNdx, result))
2584*35238bceSAndroid Build Coastguard Worker             return true;
2585*35238bceSAndroid Build Coastguard Worker     }
2586*35238bceSAndroid Build Coastguard Worker 
2587*35238bceSAndroid Build Coastguard Worker     return false;
2588*35238bceSAndroid Build Coastguard Worker }
2589*35238bceSAndroid Build Coastguard Worker 
isGatherResultValid(const TextureCubeView & texture,const Sampler & sampler,const LookupPrecision & prec,const Vec3 & coord,int componentNdx,const Vec4 & result)2590*35238bceSAndroid Build Coastguard Worker bool isGatherResultValid(const TextureCubeView &texture, const Sampler &sampler, const LookupPrecision &prec,
2591*35238bceSAndroid Build Coastguard Worker                          const Vec3 &coord, int componentNdx, const Vec4 &result)
2592*35238bceSAndroid Build Coastguard Worker {
2593*35238bceSAndroid Build Coastguard Worker     return isCubeGatherResultValid(texture, sampler, prec, coord, componentNdx, result);
2594*35238bceSAndroid Build Coastguard Worker }
2595*35238bceSAndroid Build Coastguard Worker 
isGatherResultValid(const TextureCubeView & texture,const Sampler & sampler,const IntLookupPrecision & prec,const Vec3 & coord,int componentNdx,const IVec4 & result)2596*35238bceSAndroid Build Coastguard Worker bool isGatherResultValid(const TextureCubeView &texture, const Sampler &sampler, const IntLookupPrecision &prec,
2597*35238bceSAndroid Build Coastguard Worker                          const Vec3 &coord, int componentNdx, const IVec4 &result)
2598*35238bceSAndroid Build Coastguard Worker {
2599*35238bceSAndroid Build Coastguard Worker     return isCubeGatherResultValid(texture, sampler, prec, coord, componentNdx, result);
2600*35238bceSAndroid Build Coastguard Worker }
2601*35238bceSAndroid Build Coastguard Worker 
isGatherResultValid(const TextureCubeView & texture,const Sampler & sampler,const IntLookupPrecision & prec,const Vec3 & coord,int componentNdx,const UVec4 & result)2602*35238bceSAndroid Build Coastguard Worker bool isGatherResultValid(const TextureCubeView &texture, const Sampler &sampler, const IntLookupPrecision &prec,
2603*35238bceSAndroid Build Coastguard Worker                          const Vec3 &coord, int componentNdx, const UVec4 &result)
2604*35238bceSAndroid Build Coastguard Worker {
2605*35238bceSAndroid Build Coastguard Worker     return isCubeGatherResultValid(texture, sampler, prec, coord, componentNdx, result);
2606*35238bceSAndroid Build Coastguard Worker }
2607*35238bceSAndroid Build Coastguard Worker 
2608*35238bceSAndroid Build Coastguard Worker } // namespace tcu
2609