Fix texturecubelod test
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / functional / es2fShaderTextureFunctionTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Texture access function tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es2fShaderTextureFunctionTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "glsShaderLibrary.hpp"
27 #include "glsTextureTestUtil.hpp"
28 #include "gluTexture.hpp"
29 #include "gluTextureUtil.hpp"
30 #include "tcuTextureUtil.hpp"
31 #include "tcuMatrix.hpp"
32 #include "tcuMatrixUtil.hpp"
33
34 #include <sstream>
35
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38
39 namespace deqp
40 {
41 namespace gles2
42 {
43 namespace Functional
44 {
45
46 namespace
47 {
48
49 enum Function
50 {
51         FUNCTION_TEXTURE = 0,           //!< texture(), textureOffset()
52         FUNCTION_TEXTUREPROJ,           //!< textureProj(), textureProjOffset()
53         FUNCTION_TEXTUREPROJ3,          //!< textureProj(sampler2D, vec3)
54         FUNCTION_TEXTURELOD,            // ...
55         FUNCTION_TEXTUREPROJLOD,
56         FUNCTION_TEXTUREPROJLOD3,       //!< textureProjLod(sampler2D, vec3)
57
58         FUNCTION_LAST
59 };
60
61 inline bool functionHasProj (Function function)
62 {
63         return function == FUNCTION_TEXTUREPROJ         ||
64                    function == FUNCTION_TEXTUREPROJ3    ||
65                    function == FUNCTION_TEXTUREPROJLOD  ||
66                    function == FUNCTION_TEXTUREPROJLOD3;
67 }
68
69 inline bool functionHasLod (Function function)
70 {
71         return function == FUNCTION_TEXTURELOD          ||
72                    function == FUNCTION_TEXTUREPROJLOD  ||
73                    function == FUNCTION_TEXTUREPROJLOD3;
74 }
75
76 struct TextureLookupSpec
77 {
78         Function                function;
79
80         tcu::Vec4               minCoord;
81         tcu::Vec4               maxCoord;
82
83         // Bias
84         bool                    useBias;
85
86         // Bias or Lod for *Lod* functions
87         float                   minLodBias;
88         float                   maxLodBias;
89
90         TextureLookupSpec (void)
91                 : function              (FUNCTION_LAST)
92                 , minCoord              (0.0f)
93                 , maxCoord              (1.0f)
94                 , useBias               (false)
95                 , minLodBias    (0.0f)
96                 , maxLodBias    (0.0f)
97         {
98         }
99
100         TextureLookupSpec (Function                             function_,
101                                            const tcu::Vec4&             minCoord_,
102                                            const tcu::Vec4&             maxCoord_,
103                                            bool                                 useBias_,
104                                            float                                minLodBias_,
105                                            float                                maxLodBias_)
106                 : function              (function_)
107                 , minCoord              (minCoord_)
108                 , maxCoord              (maxCoord_)
109                 , useBias               (useBias_)
110                 , minLodBias    (minLodBias_)
111                 , maxLodBias    (maxLodBias_)
112         {
113         }
114 };
115
116 enum TextureType
117 {
118         TEXTURETYPE_2D,
119         TEXTURETYPE_CUBE_MAP,
120
121         TEXTURETYPE_LAST
122 };
123
124 struct TextureSpec
125 {
126         TextureType                     type;           //!< Texture type (2D, cubemap, ...)
127         deUint32                        format;
128         deUint32                        dataType;
129         int                                     width;
130         int                                     height;
131         int                                     numLevels;
132         tcu::Sampler            sampler;
133
134         TextureSpec (void)
135                 : type                  (TEXTURETYPE_LAST)
136                 , format                (GL_NONE)
137                 , dataType              (GL_NONE)
138                 , width                 (0)
139                 , height                (0)
140                 , numLevels             (0)
141         {
142         }
143
144         TextureSpec (TextureType                        type_,
145                                  deUint32                               format_,
146                                  deUint32                               dataType_,
147                                  int                                    width_,
148                                  int                                    height_,
149                                  int                                    numLevels_,
150                                  const tcu::Sampler&    sampler_)
151                 : type                  (type_)
152                 , format                (format_)
153                 , dataType              (dataType_)
154                 , width                 (width_)
155                 , height                (height_)
156                 , numLevels             (numLevels_)
157                 , sampler               (sampler_)
158         {
159         }
160 };
161
162 struct TexLookupParams
163 {
164         float                           lod;
165         tcu::Vec4                       scale;
166         tcu::Vec4                       bias;
167
168         TexLookupParams (void)
169                 : lod           (0.0f)
170                 , scale         (1.0f)
171                 , bias          (0.0f)
172         {
173         }
174 };
175
176 } // anonymous
177
178 using tcu::Vec2;
179 using tcu::Vec3;
180 using tcu::Vec4;
181 using tcu::IVec2;
182 using tcu::IVec3;
183 using tcu::IVec4;
184
185 typedef void (*TexEvalFunc) (gls::ShaderEvalContext& c, const TexLookupParams& lookupParams);
186
187 inline Vec4 texture2D           (const gls::ShaderEvalContext& c, float s, float t, float lod)                  { return c.textures[0].tex2D->sample(c.textures[0].sampler, s, t, lod);                 }
188 inline Vec4 textureCube         (const gls::ShaderEvalContext& c, float s, float t, float r, float lod) { return c.textures[0].texCube->sample(c.textures[0].sampler, s, t, r, lod);    }
189
190 // Eval functions.
191 static void             evalTexture2D                   (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x(), c.in[0].y(), p.lod)*p.scale + p.bias; }
192 static void             evalTextureCube                 (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = textureCube(c, c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod)*p.scale + p.bias; }
193
194 static void             evalTexture2DBias               (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x(), c.in[0].y(), p.lod+c.in[1].x())*p.scale + p.bias; }
195 static void             evalTextureCubeBias             (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = textureCube(c, c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod+c.in[1].x())*p.scale + p.bias; }
196
197 static void             evalTexture2DProj3              (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x()/c.in[0].z(), c.in[0].y()/c.in[0].z(), p.lod)*p.scale + p.bias; }
198 static void             evalTexture2DProj3Bias  (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x()/c.in[0].z(), c.in[0].y()/c.in[0].z(), p.lod+c.in[1].x())*p.scale + p.bias; }
199 static void             evalTexture2DProj               (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x()/c.in[0].w(), c.in[0].y()/c.in[0].w(), p.lod)*p.scale + p.bias; }
200 static void             evalTexture2DProjBias   (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x()/c.in[0].w(), c.in[0].y()/c.in[0].w(), p.lod+c.in[1].x())*p.scale + p.bias; }
201
202 static void             evalTexture2DLod                (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x(), c.in[0].y(), c.in[1].x())*p.scale + p.bias; }
203 static void             evalTextureCubeLod              (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = textureCube(c, c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[1].x())*p.scale + p.bias; }
204
205 static void             evalTexture2DProjLod3   (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x()/c.in[0].z(), c.in[0].y()/c.in[0].z(), c.in[1].x())*p.scale + p.bias; }
206 static void             evalTexture2DProjLod    (gls::ShaderEvalContext& c, const TexLookupParams& p)   { c.color = texture2D(c, c.in[0].x()/c.in[0].w(), c.in[0].y()/c.in[0].w(), c.in[1].x())*p.scale + p.bias; }
207
208 class TexLookupEvaluator : public gls::ShaderEvaluator
209 {
210 public:
211                                                         TexLookupEvaluator              (TexEvalFunc evalFunc, const TexLookupParams& lookupParams) : m_evalFunc(evalFunc), m_lookupParams(lookupParams) {}
212
213         virtual void                    evaluate                                (gls::ShaderEvalContext& ctx) { m_evalFunc(ctx, m_lookupParams); }
214
215 private:
216         TexEvalFunc                             m_evalFunc;
217         const TexLookupParams&  m_lookupParams;
218 };
219
220 class ShaderTextureFunctionCase : public gls::ShaderRenderCase
221 {
222 public:
223                                                         ShaderTextureFunctionCase               (Context& context, const char* name, const char* desc, const TextureLookupSpec& lookup, const TextureSpec& texture, TexEvalFunc evalFunc, bool isVertexCase);
224                                                         ~ShaderTextureFunctionCase              (void);
225
226         void                                    init                                                    (void);
227         void                                    deinit                                                  (void);
228
229 protected:
230         void                                    setupUniforms                                   (int programID, const tcu::Vec4& constCoords);
231
232 private:
233         void                                    initTexture                                             (void);
234         void                                    initShaderSources                               (void);
235
236         TextureLookupSpec               m_lookupSpec;
237         TextureSpec                             m_textureSpec;
238
239         TexLookupParams                 m_lookupParams;
240         TexLookupEvaluator              m_evaluator;
241
242         glu::Texture2D*                 m_texture2D;
243         glu::TextureCube*               m_textureCube;
244 };
245
246 ShaderTextureFunctionCase::ShaderTextureFunctionCase (Context& context, const char* name, const char* desc, const TextureLookupSpec& lookup, const TextureSpec& texture, TexEvalFunc evalFunc, bool isVertexCase)
247         : gls::ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, m_evaluator)
248         , m_lookupSpec                  (lookup)
249         , m_textureSpec                 (texture)
250         , m_evaluator                   (evalFunc, m_lookupParams)
251         , m_texture2D                   (DE_NULL)
252         , m_textureCube                 (DE_NULL)
253 {
254 }
255
256 ShaderTextureFunctionCase::~ShaderTextureFunctionCase (void)
257 {
258         delete m_texture2D;
259         delete m_textureCube;
260 }
261
262 void ShaderTextureFunctionCase::init (void)
263 {
264         if (m_isVertexCase)
265         {
266                 const glw::Functions& gl = m_renderCtx.getFunctions();
267                 int numVertexUnits = 0;
268                 gl.getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &numVertexUnits);
269                 if (numVertexUnits < 1)
270                         throw tcu::NotSupportedError("Vertex shader texture access is not supported");
271         }
272
273         {
274                 // Base coord scale & bias
275                 Vec4 s = m_lookupSpec.maxCoord-m_lookupSpec.minCoord;
276                 Vec4 b = m_lookupSpec.minCoord;
277
278                 float baseCoordTrans[] =
279                 {
280                         s.x(),          0.0f,           0.f,    b.x(),
281                         0.f,            s.y(),          0.f,    b.y(),
282                         s.z()/2.f,      -s.z()/2.f,     0.f,    s.z()/2.f + b.z(),
283                         -s.w()/2.f,     s.w()/2.f,      0.f,    s.w()/2.f + b.w()
284                 };
285
286                 m_userAttribTransforms.push_back(tcu::Mat4(baseCoordTrans));
287         }
288
289         if (functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias)
290         {
291                 float s = m_lookupSpec.maxLodBias-m_lookupSpec.minLodBias;
292                 float b = m_lookupSpec.minLodBias;
293                 float lodCoordTrans[] =
294                 {
295                         s/2.0f,         s/2.0f,         0.f,    b,
296                         0.0f,           0.0f,           0.0f,   0.0f,
297                         0.0f,           0.0f,           0.0f,   0.0f,
298                         0.0f,           0.0f,           0.0f,   0.0f
299                 };
300
301                 m_userAttribTransforms.push_back(tcu::Mat4(lodCoordTrans));
302         }
303
304         initShaderSources();
305         initTexture();
306
307         gls::ShaderRenderCase::init();
308 }
309
310 void ShaderTextureFunctionCase::initTexture (void)
311 {
312         static const IVec4 texCubeSwz[] =
313         {
314                 IVec4(0,0,1,1),
315                 IVec4(1,1,0,0),
316                 IVec4(0,1,0,1),
317                 IVec4(1,0,1,0),
318                 IVec4(0,1,1,0),
319                 IVec4(1,0,0,1)
320         };
321         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(texCubeSwz) == tcu::CUBEFACE_LAST);
322
323         tcu::TextureFormat              texFmt                  = glu::mapGLTransferFormat(m_textureSpec.format, m_textureSpec.dataType);
324         tcu::TextureFormatInfo  fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
325         tcu::IVec2                              viewportSize    = getViewportSize();
326         bool                                    isProj                  = functionHasProj(m_lookupSpec.function);
327         float                                   proj                    = isProj ? 1.0f/m_lookupSpec.minCoord[m_lookupSpec.function == FUNCTION_TEXTUREPROJ3 ? 2 : 3] : 1.0f;
328
329         switch (m_textureSpec.type)
330         {
331                 case TEXTURETYPE_2D:
332                 {
333                         float   cStep                   = 1.0f / (float)de::max(1, m_textureSpec.numLevels-1);
334                         Vec4    cScale                  = fmtInfo.valueMax-fmtInfo.valueMin;
335                         Vec4    cBias                   = fmtInfo.valueMin;
336                         int             baseCellSize    = de::min(m_textureSpec.width/4, m_textureSpec.height/4);
337
338                         m_texture2D = new glu::Texture2D(m_renderCtx, m_textureSpec.format, m_textureSpec.dataType, m_textureSpec.width, m_textureSpec.height);
339                         for (int level = 0; level < m_textureSpec.numLevels; level++)
340                         {
341                                 float   fA              = float(level)*cStep;
342                                 float   fB              = 1.0f-fA;
343                                 Vec4    colorA  = cBias + cScale*Vec4(fA, fB, fA, fB);
344                                 Vec4    colorB  = cBias + cScale*Vec4(fB, fA, fB, fA);
345
346                                 m_texture2D->getRefTexture().allocLevel(level);
347                                 tcu::fillWithGrid(m_texture2D->getRefTexture().getLevel(level), de::max(1, baseCellSize>>level), colorA, colorB);
348                         }
349                         m_texture2D->upload();
350
351                         // Compute LOD.
352                         float dudx = (m_lookupSpec.maxCoord[0]-m_lookupSpec.minCoord[0])*proj*(float)m_textureSpec.width        / (float)viewportSize[0];
353                         float dvdy = (m_lookupSpec.maxCoord[1]-m_lookupSpec.minCoord[1])*proj*(float)m_textureSpec.height       / (float)viewportSize[1];
354                         m_lookupParams.lod = glu::TextureTestUtil::computeLodFromDerivates(glu::TextureTestUtil::LODMODE_EXACT, dudx, 0.0f, 0.0f, dvdy);
355
356                         // Append to texture list.
357                         m_textures.push_back(gls::TextureBinding(m_texture2D, m_textureSpec.sampler));
358                         break;
359                 }
360
361                 case TEXTURETYPE_CUBE_MAP:
362                 {
363                         float   cStep                   = 1.0f / (float)de::max(1, m_textureSpec.numLevels-1);
364                         Vec4    cScale                  = fmtInfo.valueMax-fmtInfo.valueMin;
365                         Vec4    cBias                   = fmtInfo.valueMin;
366                         int             baseCellSize    = de::min(m_textureSpec.width/4, m_textureSpec.height/4);
367
368                         DE_ASSERT(m_textureSpec.width == m_textureSpec.height);
369                         m_textureCube = new glu::TextureCube(m_renderCtx, m_textureSpec.format, m_textureSpec.dataType, m_textureSpec.width);
370                         for (int level = 0; level < m_textureSpec.numLevels; level++)
371                         {
372                                 float   fA              = float(level)*cStep;
373                                 float   fB              = 1.0f-fA;
374                                 Vec2    f               (fA, fB);
375
376                                 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
377                                 {
378                                         const IVec4&    swzA    = texCubeSwz[face];
379                                         IVec4                   swzB    = 1-swzA;
380                                         Vec4                    colorA  = cBias + cScale*f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]);
381                                         Vec4                    colorB  = cBias + cScale*f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]);
382
383                                         m_textureCube->getRefTexture().allocLevel((tcu::CubeFace)face, level);
384                                         tcu::fillWithGrid(m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face), de::max(1, baseCellSize>>level), colorA, colorB);
385                                 }
386                         }
387                         m_textureCube->upload();
388
389                         // Compute LOD \note Assumes that only single side is accessed and R is constant major axis.
390                         DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005);
391                         DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) && de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2]));
392                         DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) && de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2]));
393
394                         tcu::CubeFaceFloatCoords        c00             = tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0]*proj, m_lookupSpec.minCoord[1]*proj, m_lookupSpec.minCoord[2]*proj));
395                         tcu::CubeFaceFloatCoords        c10             = tcu::getCubeFaceCoords(Vec3(m_lookupSpec.maxCoord[0]*proj, m_lookupSpec.minCoord[1]*proj, m_lookupSpec.minCoord[2]*proj));
396                         tcu::CubeFaceFloatCoords        c01             = tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0]*proj, m_lookupSpec.maxCoord[1]*proj, m_lookupSpec.minCoord[2]*proj));
397                         float                                           dudx    = (c10.s - c00.s)*(float)m_textureSpec.width    / (float)viewportSize[0];
398                         float                                           dvdy    = (c01.t - c00.t)*(float)m_textureSpec.height   / (float)viewportSize[1];
399
400                         m_lookupParams.lod = glu::TextureTestUtil::computeLodFromDerivates(glu::TextureTestUtil::LODMODE_EXACT, dudx, 0.0f, 0.0f, dvdy);
401
402                         m_textures.push_back(gls::TextureBinding(m_textureCube, m_textureSpec.sampler));
403                         break;
404                 }
405
406                 default:
407                         DE_ASSERT(DE_FALSE);
408         }
409
410         // Set lookup scale & bias
411         m_lookupParams.scale    = fmtInfo.lookupScale;
412         m_lookupParams.bias             = fmtInfo.lookupBias;
413 }
414
415 void ShaderTextureFunctionCase::initShaderSources (void)
416 {
417         Function                        function                        = m_lookupSpec.function;
418         bool                            isVtxCase                       = m_isVertexCase;
419         bool                            isProj                          = functionHasProj(function);
420         bool                            is2DProj4                       = m_textureSpec.type == TEXTURETYPE_2D && (function == FUNCTION_TEXTUREPROJ || function == FUNCTION_TEXTUREPROJLOD);
421         bool                            hasLodBias                      = functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias;
422         int                                     texCoordComps           = m_textureSpec.type == TEXTURETYPE_2D ? 2 : 3;
423         int                                     extraCoordComps         = isProj ? (is2DProj4 ? 2 : 1) : 0;
424         glu::DataType           coordType                       = glu::getDataTypeFloatVec(texCoordComps+extraCoordComps);
425         glu::Precision          coordPrec                       = glu::PRECISION_MEDIUMP;
426         const char*                     coordTypeName           = glu::getDataTypeName(coordType);
427         const char*                     coordPrecName           = glu::getPrecisionName(coordPrec);
428         tcu::TextureFormat      texFmt                          = glu::mapGLTransferFormat(m_textureSpec.format, m_textureSpec.dataType);
429         glu::DataType           samplerType                     = glu::TYPE_LAST;
430         const char*                     baseFuncName            = m_textureSpec.type == TEXTURETYPE_2D ? "texture2D" : "textureCube";
431         const char*                     funcExt                         = DE_NULL;
432
433         switch (m_textureSpec.type)
434         {
435                 case TEXTURETYPE_2D:            samplerType = glu::getSampler2DType(texFmt);            break;
436                 case TEXTURETYPE_CUBE_MAP:      samplerType = glu::getSamplerCubeType(texFmt);          break;
437                 default:
438                         DE_ASSERT(DE_FALSE);
439         }
440
441         switch (m_lookupSpec.function)
442         {
443                 case FUNCTION_TEXTURE:                  funcExt = "";                   break;
444                 case FUNCTION_TEXTUREPROJ:              funcExt = "Proj";               break;
445                 case FUNCTION_TEXTUREPROJ3:             funcExt = "Proj";               break;
446                 case FUNCTION_TEXTURELOD:               funcExt = "Lod";                break;
447                 case FUNCTION_TEXTUREPROJLOD:   funcExt = "ProjLod";    break;
448                 case FUNCTION_TEXTUREPROJLOD3:  funcExt = "ProjLod";    break;
449                 default:
450                         DE_ASSERT(DE_FALSE);
451         }
452
453         std::ostringstream      vert;
454         std::ostringstream      frag;
455         std::ostringstream&     op              = isVtxCase ? vert : frag;
456
457         vert << "attribute highp vec4 a_position;\n"
458                  << "attribute " << coordPrecName << " " << coordTypeName << " a_in0;\n";
459
460         if (hasLodBias)
461                 vert << "attribute " << coordPrecName << " float a_in1;\n";
462
463         if (isVtxCase)
464         {
465                 vert << "varying mediump vec4 v_color;\n";
466                 frag << "varying mediump vec4 v_color;\n";
467         }
468         else
469         {
470                 vert << "varying " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
471                 frag << "varying " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
472
473                 if (hasLodBias)
474                 {
475                         vert << "varying " << coordPrecName << " float v_lodBias;\n";
476                         frag << "varying " << coordPrecName << " float v_lodBias;\n";
477                 }
478         }
479
480         // Uniforms
481         op << "uniform lowp " << glu::getDataTypeName(samplerType) << " u_sampler;\n";
482
483         vert << "\nvoid main()\n{\n"
484                  << "\tgl_Position = a_position;\n";
485         frag << "\nvoid main()\n{\n";
486
487         if (isVtxCase)
488                 vert << "\tv_color = ";
489         else
490                 frag << "\tgl_FragColor = ";
491
492         // Op.
493         {
494                 const char*     texCoord        = isVtxCase ? "a_in0" : "v_texCoord";
495                 const char*     lodBias         = isVtxCase ? "a_in1" : "v_lodBias";
496
497                 op << baseFuncName << funcExt;
498                 op << "(u_sampler, " << texCoord;
499
500                 if (functionHasLod(function) || m_lookupSpec.useBias)
501                         op << ", " << lodBias;
502
503                 op << ");\n";
504         }
505
506         if (isVtxCase)
507                 frag << "\tgl_FragColor = v_color;\n";
508         else
509         {
510                 vert << "\tv_texCoord = a_in0;\n";
511
512                 if (hasLodBias)
513                         vert << "\tv_lodBias = a_in1;\n";
514         }
515
516         vert << "}\n";
517         frag << "}\n";
518
519         m_vertShaderSource = vert.str();
520         m_fragShaderSource = frag.str();
521 }
522
523 void ShaderTextureFunctionCase::deinit (void)
524 {
525         gls::ShaderRenderCase::deinit();
526
527         delete m_texture2D;
528         delete m_textureCube;
529
530         m_texture2D                     = DE_NULL;
531         m_textureCube           = DE_NULL;
532 }
533
534 void ShaderTextureFunctionCase::setupUniforms (int programID, const tcu::Vec4&)
535 {
536         const glw::Functions& gl = m_renderCtx.getFunctions();
537         gl.uniform1i(gl.getUniformLocation(programID, "u_sampler"), 0);
538 }
539
540 ShaderTextureFunctionTests::ShaderTextureFunctionTests (Context& context)
541         : TestCaseGroup(context, "texture_functions", "Texture Access Function Tests")
542 {
543 }
544
545 ShaderTextureFunctionTests::~ShaderTextureFunctionTests (void)
546 {
547 }
548
549 struct TexFuncCaseSpec
550 {
551         const char*                     name;
552         TextureLookupSpec       lookupSpec;
553         TextureSpec                     texSpec;
554         TexEvalFunc                     evalFunc;
555 };
556
557 #define CASE_SPEC(NAME, FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, TEXSPEC, EVALFUNC) \
558         { #NAME, TextureLookupSpec(FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD), TEXSPEC, EVALFUNC }
559
560 static void createCaseGroup (TestCaseGroup* parent, const char* groupName, const char* groupDesc, const TexFuncCaseSpec* cases, int numCases, bool isVertex)
561 {
562         tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), groupName, groupDesc);
563         parent->addChild(group);
564
565         for (int ndx = 0; ndx < numCases; ndx++)
566                 group->addChild(new ShaderTextureFunctionCase(parent->getContext(), cases[ndx].name, "", cases[ndx].lookupSpec, cases[ndx].texSpec, cases[ndx].evalFunc, isVertex));
567 }
568
569 void ShaderTextureFunctionTests::init (void)
570 {
571         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
572
573         // Samplers
574         static const tcu::Sampler       samplerLinearNoMipmap   (tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
575                                                                                                                  tcu::Sampler::LINEAR, tcu::Sampler::LINEAR);
576         static tcu::Sampler                     samplerLinearMipmap             (tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
577                                                                                                                  tcu::Sampler::LINEAR_MIPMAP_NEAREST, tcu::Sampler::LINEAR);
578
579         // GL_MAJOR_VERSION query does not exist on GLES2
580         // so succeeding query implies GLES3+ hardware.
581         glw::GLint majorVersion = 0;
582         gl.getIntegerv(GL_MAJOR_VERSION, &majorVersion);
583         samplerLinearMipmap.seamlessCubeMap = (gl.getError() == GL_NO_ERROR);
584
585         // Default textures.
586         //                                                                                              Type                    Format          DataType                        W               H               L       Sampler
587         static const TextureSpec tex2D                  (TEXTURETYPE_2D,                GL_RGBA,        GL_UNSIGNED_BYTE,       256,    256,    1,      samplerLinearNoMipmap);
588         static const TextureSpec tex2DMipmap    (TEXTURETYPE_2D,                GL_RGBA,        GL_UNSIGNED_BYTE,       256,    256,    9,      samplerLinearMipmap);
589
590         static const TextureSpec texCube                (TEXTURETYPE_CUBE_MAP,  GL_RGBA,        GL_UNSIGNED_BYTE,       256,    256,    1,      samplerLinearNoMipmap);
591         static const TextureSpec texCubeMipmap  (TEXTURETYPE_CUBE_MAP,  GL_RGBA,        GL_UNSIGNED_BYTE,       256,    256,    9,      samplerLinearMipmap);
592
593         // Vertex cases
594         static const TexFuncCaseSpec vertexCases[] =
595         {
596                 //                Name                                          Function                                        MinCoord                                                        MaxCoord                                                        Bias?   MinLod  MaxLod  Texture                 EvalFunc
597                 CASE_SPEC(texture2d,                            FUNCTION_TEXTURE,                       Vec4(-0.2f, -0.4f,  0.0f,  0.0f),       Vec4( 1.5f,  2.3f,  0.0f,  0.0f),       false,  0.0f,   0.0f,   tex2D,                  evalTexture2D),
598 //              CASE_SPEC(texture2d_bias,                       FUNCTION_TEXTURE,                       Vec4(-0.2f, -0.4f,  0.0f,  0.0f),       Vec4( 1.5f,  2.3f,  0.0f,  0.0f),       true,   -2.0f,  2.0f,   tex2D,                  evalTexture2DBias),
599                 CASE_SPEC(texture2dproj_vec3,           FUNCTION_TEXTUREPROJ3,          Vec4(-0.3f, -0.6f,  1.5f,  0.0f),       Vec4(2.25f, 3.45f,  1.5f,  0.0f),       false,  0.0f,   0.0f,   tex2D,                  evalTexture2DProj3),
600                 CASE_SPEC(texture2dproj_vec4,           FUNCTION_TEXTUREPROJ,           Vec4(-0.3f, -0.6f,  0.0f,  1.5f),       Vec4(2.25f, 3.45f,  0.0f,  1.5f),       false,  0.0f,   0.0f,   tex2D,                  evalTexture2DProj),
601                 CASE_SPEC(texture2dlod,                         FUNCTION_TEXTURELOD,            Vec4(-0.2f, -0.4f,  0.0f,  0.0f),       Vec4( 1.5f,  2.3f,  0.0f,  0.0f),       false,  -1.0f,  9.0f,   tex2DMipmap,    evalTexture2DLod),
602 //              CASE_SPEC(texture2dproj_vec3_bias,      FUNCTION_TEXTUREPROJ3,          Vec4(-0.3f, -0.6f,  1.5f,  0.0f),       Vec4(2.25f, 3.45f,  1.5f,  0.0f),       true,   -2.0f,  2.0f,   tex2D,                  evalTexture2DProj3Bias),
603 //              CASE_SPEC(texture2dproj_vec4_bias,      FUNCTION_TEXTUREPROJ,           Vec4(-0.3f, -0.6f,  0.0f,  1.5f),       Vec4(2.25f, 3.45f,  0.0f,  1.5f),       true,   -2.0f,  2.0f,   tex2D,                  evalTexture2DProjBias),
604                 CASE_SPEC(texture2dprojlod_vec3,        FUNCTION_TEXTUREPROJLOD3,       Vec4(-0.3f, -0.6f,  1.5f,  0.0f),       Vec4(2.25f, 3.45f,  1.5f,  0.0f),       false,  -1.0f,  9.0f,   tex2D,                  evalTexture2DProjLod3),
605                 CASE_SPEC(texture2dprojlod_vec4,        FUNCTION_TEXTUREPROJLOD,        Vec4(-0.3f, -0.6f,  0.0f,  1.5f),       Vec4(2.25f, 3.45f,  0.0f,  1.5f),       false,  -1.0f,  9.0f,   tex2D,                  evalTexture2DProjLod),
606                 CASE_SPEC(texturecube,                          FUNCTION_TEXTURE,                       Vec4(-1.0f, -1.0f,  1.01f,  0.0f),      Vec4( 1.0f,  1.0f,  1.01f,  0.0f),      false,  0.0f,   0.0f,   texCube,                evalTextureCube),
607 //              CASE_SPEC(texturecube_bias,                     FUNCTION_TEXTURE,                       Vec4(-1.0f, -1.0f, -1.01f,  0.0f),      Vec4( 1.0f,  1.0f, -1.01f,  0.0f),      true,   -2.0f,  2.0f,   texCube,                evalTextureCubeBias),
608                 CASE_SPEC(texturecubelod,                       FUNCTION_TEXTURELOD,            Vec4(-1.0f, -1.0f,  1.01f,  0.0f),      Vec4( 1.0f,  1.0f,  1.01f,  0.0f),      false,  -1.0f,  9.0f,   texCubeMipmap,  evalTextureCubeLod),
609         };
610         createCaseGroup(this, "vertex", "Vertex Shader Texture Lookups", &vertexCases[0], DE_LENGTH_OF_ARRAY(vertexCases), true);
611
612         // Fragment cases
613         static const TexFuncCaseSpec fragmentCases[] =
614         {
615                 //                Name                                          Function                                MinCoord                                                        MaxCoord                                                        Bias?   MinLod  MaxLod  Texture                 EvalFunc
616                 CASE_SPEC(texture2d,                            FUNCTION_TEXTURE,               Vec4(-0.2f, -0.4f,  0.0f,  0.0f),       Vec4( 1.5f,  2.3f,  0.0f,  0.0f),       false,  0.0f,   0.0f,   tex2DMipmap,    evalTexture2D),
617                 CASE_SPEC(texture2d_bias,                       FUNCTION_TEXTURE,               Vec4(-0.2f, -0.4f,  0.0f,  0.0f),       Vec4( 1.5f,  2.3f,  0.0f,  0.0f),       true,   -2.0f,  2.0f,   tex2DMipmap,    evalTexture2DBias),
618                 CASE_SPEC(texture2dproj_vec3,           FUNCTION_TEXTUREPROJ3,  Vec4(-0.3f, -0.6f,  1.5f,  0.0f),       Vec4(2.25f, 3.45f,  1.5f,  0.0f),       false,  0.0f,   0.0f,   tex2DMipmap,    evalTexture2DProj3),
619                 CASE_SPEC(texture2dproj_vec4,           FUNCTION_TEXTUREPROJ,   Vec4(-0.3f, -0.6f,  0.0f,  1.5f),       Vec4(2.25f, 3.45f,  0.0f,  1.5f),       false,  0.0f,   0.0f,   tex2DMipmap,    evalTexture2DProj),
620                 CASE_SPEC(texture2dproj_vec3_bias,      FUNCTION_TEXTUREPROJ3,  Vec4(-0.3f, -0.6f,  1.5f,  0.0f),       Vec4(2.25f, 3.45f,  1.5f,  0.0f),       true,   -2.0f,  2.0f,   tex2DMipmap,    evalTexture2DProj3Bias),
621                 CASE_SPEC(texture2dproj_vec4_bias,      FUNCTION_TEXTUREPROJ,   Vec4(-0.3f, -0.6f,  0.0f,  1.5f),       Vec4(2.25f, 3.45f,  0.0f,  1.5f),       true,   -2.0f,  2.0f,   tex2DMipmap,    evalTexture2DProjBias),
622                 CASE_SPEC(texturecube,                          FUNCTION_TEXTURE,               Vec4(-1.0f, -1.0f,  1.01f,  0.0f),      Vec4( 1.0f,  1.0f,  1.01f,  0.0f),      false,  0.0f,   0.0f,   texCubeMipmap,  evalTextureCube),
623                 CASE_SPEC(texturecube_bias,                     FUNCTION_TEXTURE,               Vec4(-1.0f, -1.0f, -1.01f,  0.0f),      Vec4( 1.0f,  1.0f, -1.01f,  0.0f),      true,   -2.0f,  2.0f,   texCubeMipmap,  evalTextureCubeBias)
624         };
625         createCaseGroup(this, "fragment", "Fragment Shader Texture Lookups", &fragmentCases[0], DE_LENGTH_OF_ARRAY(fragmentCases), false);
626
627         // Negative cases.
628         {
629                 gls::ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
630                 std::vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/invalid_texture_functions.test");
631
632                 tcu::TestCaseGroup* group = new tcu::TestCaseGroup(m_testCtx, "invalid", "Invalid texture function usage", negativeCases);
633                 addChild(group);
634         }
635 }
636
637 } // Functional
638 } // gles3
639 } // deqp