xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fShaderTextureFunctionTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 
functionHasProj(Function function)61 inline bool functionHasProj(Function function)
62 {
63     return function == FUNCTION_TEXTUREPROJ || function == FUNCTION_TEXTUREPROJ3 ||
64            function == FUNCTION_TEXTUREPROJLOD || function == FUNCTION_TEXTUREPROJLOD3;
65 }
66 
functionHasLod(Function function)67 inline bool functionHasLod(Function function)
68 {
69     return function == FUNCTION_TEXTURELOD || function == FUNCTION_TEXTUREPROJLOD ||
70            function == FUNCTION_TEXTUREPROJLOD3;
71 }
72 
73 struct TextureLookupSpec
74 {
75     Function function;
76 
77     tcu::Vec4 minCoord;
78     tcu::Vec4 maxCoord;
79 
80     // Bias
81     bool useBias;
82 
83     // Bias or Lod for *Lod* functions
84     float minLodBias;
85     float maxLodBias;
86 
TextureLookupSpecdeqp::gles2::Functional::__anone1ab98580111::TextureLookupSpec87     TextureLookupSpec(void)
88         : function(FUNCTION_LAST)
89         , minCoord(0.0f)
90         , maxCoord(1.0f)
91         , useBias(false)
92         , minLodBias(0.0f)
93         , maxLodBias(0.0f)
94     {
95     }
96 
TextureLookupSpecdeqp::gles2::Functional::__anone1ab98580111::TextureLookupSpec97     TextureLookupSpec(Function function_, const tcu::Vec4 &minCoord_, const tcu::Vec4 &maxCoord_, bool useBias_,
98                       float minLodBias_, float maxLodBias_)
99         : function(function_)
100         , minCoord(minCoord_)
101         , maxCoord(maxCoord_)
102         , useBias(useBias_)
103         , minLodBias(minLodBias_)
104         , maxLodBias(maxLodBias_)
105     {
106     }
107 };
108 
109 enum TextureType
110 {
111     TEXTURETYPE_2D,
112     TEXTURETYPE_CUBE_MAP,
113 
114     TEXTURETYPE_LAST
115 };
116 
117 struct TextureSpec
118 {
119     TextureType type; //!< Texture type (2D, cubemap, ...)
120     uint32_t format;
121     uint32_t dataType;
122     int width;
123     int height;
124     int numLevels;
125     tcu::Sampler sampler;
126 
TextureSpecdeqp::gles2::Functional::__anone1ab98580111::TextureSpec127     TextureSpec(void) : type(TEXTURETYPE_LAST), format(GL_NONE), dataType(GL_NONE), width(0), height(0), numLevels(0)
128     {
129     }
130 
TextureSpecdeqp::gles2::Functional::__anone1ab98580111::TextureSpec131     TextureSpec(TextureType type_, uint32_t format_, uint32_t dataType_, int width_, int height_, int numLevels_,
132                 const tcu::Sampler &sampler_)
133         : type(type_)
134         , format(format_)
135         , dataType(dataType_)
136         , width(width_)
137         , height(height_)
138         , numLevels(numLevels_)
139         , sampler(sampler_)
140     {
141     }
142 };
143 
144 struct TexLookupParams
145 {
146     float lod;
147     tcu::Vec4 scale;
148     tcu::Vec4 bias;
149 
TexLookupParamsdeqp::gles2::Functional::__anone1ab98580111::TexLookupParams150     TexLookupParams(void) : lod(0.0f), scale(1.0f), bias(0.0f)
151     {
152     }
153 };
154 
155 } // namespace
156 
157 using tcu::IVec2;
158 using tcu::IVec3;
159 using tcu::IVec4;
160 using tcu::Vec2;
161 using tcu::Vec3;
162 using tcu::Vec4;
163 
164 typedef void (*TexEvalFunc)(gls::ShaderEvalContext &c, const TexLookupParams &lookupParams);
165 
texture2D(const gls::ShaderEvalContext & c,float s,float t,float lod)166 inline Vec4 texture2D(const gls::ShaderEvalContext &c, float s, float t, float lod)
167 {
168     return c.textures[0].tex2D->sample(c.textures[0].sampler, s, t, lod);
169 }
textureCube(const gls::ShaderEvalContext & c,float s,float t,float r,float lod)170 inline Vec4 textureCube(const gls::ShaderEvalContext &c, float s, float t, float r, float lod)
171 {
172     return c.textures[0].texCube->sample(c.textures[0].sampler, s, t, r, lod);
173 }
174 
175 // Eval functions.
evalTexture2D(gls::ShaderEvalContext & c,const TexLookupParams & p)176 static void evalTexture2D(gls::ShaderEvalContext &c, const TexLookupParams &p)
177 {
178     c.color = texture2D(c, c.in[0].x(), c.in[0].y(), p.lod) * p.scale + p.bias;
179 }
evalTextureCube(gls::ShaderEvalContext & c,const TexLookupParams & p)180 static void evalTextureCube(gls::ShaderEvalContext &c, const TexLookupParams &p)
181 {
182     c.color = textureCube(c, c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod) * p.scale + p.bias;
183 }
184 
evalTexture2DBias(gls::ShaderEvalContext & c,const TexLookupParams & p)185 static void evalTexture2DBias(gls::ShaderEvalContext &c, const TexLookupParams &p)
186 {
187     c.color = texture2D(c, c.in[0].x(), c.in[0].y(), p.lod + c.in[1].x()) * p.scale + p.bias;
188 }
evalTextureCubeBias(gls::ShaderEvalContext & c,const TexLookupParams & p)189 static void evalTextureCubeBias(gls::ShaderEvalContext &c, const TexLookupParams &p)
190 {
191     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;
192 }
193 
evalTexture2DProj3(gls::ShaderEvalContext & c,const TexLookupParams & p)194 static void evalTexture2DProj3(gls::ShaderEvalContext &c, const TexLookupParams &p)
195 {
196     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;
197 }
evalTexture2DProj3Bias(gls::ShaderEvalContext & c,const TexLookupParams & p)198 static void evalTexture2DProj3Bias(gls::ShaderEvalContext &c, const TexLookupParams &p)
199 {
200     c.color =
201         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;
202 }
evalTexture2DProj(gls::ShaderEvalContext & c,const TexLookupParams & p)203 static void evalTexture2DProj(gls::ShaderEvalContext &c, const TexLookupParams &p)
204 {
205     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;
206 }
evalTexture2DProjBias(gls::ShaderEvalContext & c,const TexLookupParams & p)207 static void evalTexture2DProjBias(gls::ShaderEvalContext &c, const TexLookupParams &p)
208 {
209     c.color =
210         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;
211 }
212 
evalTexture2DLod(gls::ShaderEvalContext & c,const TexLookupParams & p)213 static void evalTexture2DLod(gls::ShaderEvalContext &c, const TexLookupParams &p)
214 {
215     c.color = texture2D(c, c.in[0].x(), c.in[0].y(), c.in[1].x()) * p.scale + p.bias;
216 }
evalTextureCubeLod(gls::ShaderEvalContext & c,const TexLookupParams & p)217 static void evalTextureCubeLod(gls::ShaderEvalContext &c, const TexLookupParams &p)
218 {
219     c.color = textureCube(c, c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[1].x()) * p.scale + p.bias;
220 }
221 
evalTexture2DProjLod3(gls::ShaderEvalContext & c,const TexLookupParams & p)222 static void evalTexture2DProjLod3(gls::ShaderEvalContext &c, const TexLookupParams &p)
223 {
224     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;
225 }
evalTexture2DProjLod(gls::ShaderEvalContext & c,const TexLookupParams & p)226 static void evalTexture2DProjLod(gls::ShaderEvalContext &c, const TexLookupParams &p)
227 {
228     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;
229 }
230 
231 class TexLookupEvaluator : public gls::ShaderEvaluator
232 {
233 public:
TexLookupEvaluator(TexEvalFunc evalFunc,const TexLookupParams & lookupParams)234     TexLookupEvaluator(TexEvalFunc evalFunc, const TexLookupParams &lookupParams)
235         : m_evalFunc(evalFunc)
236         , m_lookupParams(lookupParams)
237     {
238     }
239 
evaluate(gls::ShaderEvalContext & ctx)240     virtual void evaluate(gls::ShaderEvalContext &ctx)
241     {
242         m_evalFunc(ctx, m_lookupParams);
243     }
244 
245 private:
246     TexEvalFunc m_evalFunc;
247     const TexLookupParams &m_lookupParams;
248 };
249 
250 class ShaderTextureFunctionCase : public gls::ShaderRenderCase
251 {
252 public:
253     ShaderTextureFunctionCase(Context &context, const char *name, const char *desc, const TextureLookupSpec &lookup,
254                               const TextureSpec &texture, TexEvalFunc evalFunc, bool isVertexCase);
255     ~ShaderTextureFunctionCase(void);
256 
257     void init(void);
258     void deinit(void);
259 
260 protected:
261     void setupUniforms(int programID, const tcu::Vec4 &constCoords);
262 
263 private:
264     void initTexture(void);
265     void initShaderSources(void);
266 
267     TextureLookupSpec m_lookupSpec;
268     TextureSpec m_textureSpec;
269 
270     TexLookupParams m_lookupParams;
271     TexLookupEvaluator m_evaluator;
272 
273     glu::Texture2D *m_texture2D;
274     glu::TextureCube *m_textureCube;
275 };
276 
ShaderTextureFunctionCase(Context & context,const char * name,const char * desc,const TextureLookupSpec & lookup,const TextureSpec & texture,TexEvalFunc evalFunc,bool isVertexCase)277 ShaderTextureFunctionCase::ShaderTextureFunctionCase(Context &context, const char *name, const char *desc,
278                                                      const TextureLookupSpec &lookup, const TextureSpec &texture,
279                                                      TexEvalFunc evalFunc, bool isVertexCase)
280     : gls::ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc,
281                             isVertexCase, m_evaluator)
282     , m_lookupSpec(lookup)
283     , m_textureSpec(texture)
284     , m_evaluator(evalFunc, m_lookupParams)
285     , m_texture2D(DE_NULL)
286     , m_textureCube(DE_NULL)
287 {
288 }
289 
~ShaderTextureFunctionCase(void)290 ShaderTextureFunctionCase::~ShaderTextureFunctionCase(void)
291 {
292     delete m_texture2D;
293     delete m_textureCube;
294 }
295 
init(void)296 void ShaderTextureFunctionCase::init(void)
297 {
298     if (m_isVertexCase)
299     {
300         const glw::Functions &gl = m_renderCtx.getFunctions();
301         int numVertexUnits       = 0;
302         gl.getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &numVertexUnits);
303         if (numVertexUnits < 1)
304             throw tcu::NotSupportedError("Vertex shader texture access is not supported");
305     }
306 
307     {
308         // Base coord scale & bias
309         Vec4 s = m_lookupSpec.maxCoord - m_lookupSpec.minCoord;
310         Vec4 b = m_lookupSpec.minCoord;
311 
312         float baseCoordTrans[] = {s.x(),        0.0f,         0.f, b.x(),
313                                   0.f,          s.y(),        0.f, b.y(),
314                                   s.z() / 2.f,  -s.z() / 2.f, 0.f, s.z() / 2.f + b.z(),
315                                   -s.w() / 2.f, s.w() / 2.f,  0.f, s.w() / 2.f + b.w()};
316 
317         m_userAttribTransforms.push_back(tcu::Mat4(baseCoordTrans));
318     }
319 
320     if (functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias)
321     {
322         float s               = m_lookupSpec.maxLodBias - m_lookupSpec.minLodBias;
323         float b               = m_lookupSpec.minLodBias;
324         float lodCoordTrans[] = {s / 2.0f, s / 2.0f, 0.f,  b,    0.0f, 0.0f, 0.0f, 0.0f,
325                                  0.0f,     0.0f,     0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
326 
327         m_userAttribTransforms.push_back(tcu::Mat4(lodCoordTrans));
328     }
329 
330     initShaderSources();
331     initTexture();
332 
333     gls::ShaderRenderCase::init();
334 }
335 
initTexture(void)336 void ShaderTextureFunctionCase::initTexture(void)
337 {
338     static const IVec4 texCubeSwz[] = {IVec4(0, 0, 1, 1), IVec4(1, 1, 0, 0), IVec4(0, 1, 0, 1),
339                                        IVec4(1, 0, 1, 0), IVec4(0, 1, 1, 0), IVec4(1, 0, 0, 1)};
340     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(texCubeSwz) == tcu::CUBEFACE_LAST);
341 
342     tcu::TextureFormat texFmt      = glu::mapGLTransferFormat(m_textureSpec.format, m_textureSpec.dataType);
343     tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
344     tcu::IVec2 viewportSize        = getViewportSize();
345     bool useProj                   = functionHasProj(m_lookupSpec.function) && !functionHasLod(m_lookupSpec.function);
346     float proj = useProj ? 1.0f / m_lookupSpec.minCoord[m_lookupSpec.function == FUNCTION_TEXTUREPROJ3 ? 2 : 3] : 1.0f;
347 
348     switch (m_textureSpec.type)
349     {
350     case TEXTURETYPE_2D:
351     {
352         float cStep      = 1.0f / (float)de::max(1, m_textureSpec.numLevels - 1);
353         Vec4 cScale      = fmtInfo.valueMax - fmtInfo.valueMin;
354         Vec4 cBias       = fmtInfo.valueMin;
355         int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
356 
357         m_texture2D = new glu::Texture2D(m_renderCtx, m_textureSpec.format, m_textureSpec.dataType, m_textureSpec.width,
358                                          m_textureSpec.height);
359         for (int level = 0; level < m_textureSpec.numLevels; level++)
360         {
361             float fA    = float(level) * cStep;
362             float fB    = 1.0f - fA;
363             Vec4 colorA = cBias + cScale * Vec4(fA, fB, fA, fB);
364             Vec4 colorB = cBias + cScale * Vec4(fB, fA, fB, fA);
365 
366             m_texture2D->getRefTexture().allocLevel(level);
367             tcu::fillWithGrid(m_texture2D->getRefTexture().getLevel(level), de::max(1, baseCellSize >> level), colorA,
368                               colorB);
369         }
370         m_texture2D->upload();
371 
372         // Compute LOD.
373         float dudx = (m_lookupSpec.maxCoord[0] - m_lookupSpec.minCoord[0]) * proj * (float)m_textureSpec.width /
374                      (float)viewportSize[0];
375         float dvdy = (m_lookupSpec.maxCoord[1] - m_lookupSpec.minCoord[1]) * proj * (float)m_textureSpec.height /
376                      (float)viewportSize[1];
377         m_lookupParams.lod =
378             glu::TextureTestUtil::computeLodFromDerivates(glu::TextureTestUtil::LODMODE_EXACT, dudx, 0.0f, 0.0f, dvdy);
379 
380         // Append to texture list.
381         m_textures.push_back(gls::TextureBinding(m_texture2D, m_textureSpec.sampler));
382         break;
383     }
384 
385     case TEXTURETYPE_CUBE_MAP:
386     {
387         float cStep      = 1.0f / (float)de::max(1, m_textureSpec.numLevels - 1);
388         Vec4 cScale      = fmtInfo.valueMax - fmtInfo.valueMin;
389         Vec4 cBias       = fmtInfo.valueMin;
390         int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
391 
392         DE_ASSERT(m_textureSpec.width == m_textureSpec.height);
393         m_textureCube =
394             new glu::TextureCube(m_renderCtx, m_textureSpec.format, m_textureSpec.dataType, m_textureSpec.width);
395         for (int level = 0; level < m_textureSpec.numLevels; level++)
396         {
397             float fA = float(level) * cStep;
398             float fB = 1.0f - fA;
399             Vec2 f(fA, fB);
400 
401             for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
402             {
403                 const IVec4 &swzA = texCubeSwz[face];
404                 IVec4 swzB        = 1 - swzA;
405                 Vec4 colorA       = cBias + cScale * f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]);
406                 Vec4 colorB       = cBias + cScale * f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]);
407 
408                 m_textureCube->getRefTexture().allocLevel((tcu::CubeFace)face, level);
409                 tcu::fillWithGrid(m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face),
410                                   de::max(1, baseCellSize >> level), colorA, colorB);
411             }
412         }
413         m_textureCube->upload();
414 
415         // Compute LOD \note Assumes that only single side is accessed and R is constant major axis.
416         DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005);
417         DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) &&
418                   de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2]));
419         DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) &&
420                   de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2]));
421 
422         tcu::CubeFaceFloatCoords c00 = tcu::getCubeFaceCoords(
423             Vec3(m_lookupSpec.minCoord[0] * proj, m_lookupSpec.minCoord[1] * proj, m_lookupSpec.minCoord[2] * proj));
424         tcu::CubeFaceFloatCoords c10 = tcu::getCubeFaceCoords(
425             Vec3(m_lookupSpec.maxCoord[0] * proj, m_lookupSpec.minCoord[1] * proj, m_lookupSpec.minCoord[2] * proj));
426         tcu::CubeFaceFloatCoords c01 = tcu::getCubeFaceCoords(
427             Vec3(m_lookupSpec.minCoord[0] * proj, m_lookupSpec.maxCoord[1] * proj, m_lookupSpec.minCoord[2] * proj));
428         float dudx = (c10.s - c00.s) * (float)m_textureSpec.width / (float)viewportSize[0];
429         float dvdy = (c01.t - c00.t) * (float)m_textureSpec.height / (float)viewportSize[1];
430 
431         m_lookupParams.lod =
432             glu::TextureTestUtil::computeLodFromDerivates(glu::TextureTestUtil::LODMODE_EXACT, dudx, 0.0f, 0.0f, dvdy);
433 
434         m_textures.push_back(gls::TextureBinding(m_textureCube, m_textureSpec.sampler));
435         break;
436     }
437 
438     default:
439         DE_ASSERT(false);
440     }
441 
442     // Set lookup scale & bias
443     m_lookupParams.scale = fmtInfo.lookupScale;
444     m_lookupParams.bias  = fmtInfo.lookupBias;
445 }
446 
initShaderSources(void)447 void ShaderTextureFunctionCase::initShaderSources(void)
448 {
449     Function function = m_lookupSpec.function;
450     bool isVtxCase    = m_isVertexCase;
451     bool isProj       = functionHasProj(function);
452     bool is2DProj4    = m_textureSpec.type == TEXTURETYPE_2D &&
453                      (function == FUNCTION_TEXTUREPROJ || function == FUNCTION_TEXTUREPROJLOD);
454     bool hasLodBias           = functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias;
455     int texCoordComps         = m_textureSpec.type == TEXTURETYPE_2D ? 2 : 3;
456     int extraCoordComps       = isProj ? (is2DProj4 ? 2 : 1) : 0;
457     glu::DataType coordType   = glu::getDataTypeFloatVec(texCoordComps + extraCoordComps);
458     glu::Precision coordPrec  = glu::PRECISION_MEDIUMP;
459     const char *coordTypeName = glu::getDataTypeName(coordType);
460     const char *coordPrecName = glu::getPrecisionName(coordPrec);
461     tcu::TextureFormat texFmt = glu::mapGLTransferFormat(m_textureSpec.format, m_textureSpec.dataType);
462     glu::DataType samplerType = glu::TYPE_LAST;
463     const char *baseFuncName  = m_textureSpec.type == TEXTURETYPE_2D ? "texture2D" : "textureCube";
464     const char *funcExt       = DE_NULL;
465 
466     switch (m_textureSpec.type)
467     {
468     case TEXTURETYPE_2D:
469         samplerType = glu::getSampler2DType(texFmt);
470         break;
471     case TEXTURETYPE_CUBE_MAP:
472         samplerType = glu::getSamplerCubeType(texFmt);
473         break;
474     default:
475         DE_ASSERT(false);
476     }
477 
478     switch (m_lookupSpec.function)
479     {
480     case FUNCTION_TEXTURE:
481         funcExt = "";
482         break;
483     case FUNCTION_TEXTUREPROJ:
484         funcExt = "Proj";
485         break;
486     case FUNCTION_TEXTUREPROJ3:
487         funcExt = "Proj";
488         break;
489     case FUNCTION_TEXTURELOD:
490         funcExt = "Lod";
491         break;
492     case FUNCTION_TEXTUREPROJLOD:
493         funcExt = "ProjLod";
494         break;
495     case FUNCTION_TEXTUREPROJLOD3:
496         funcExt = "ProjLod";
497         break;
498     default:
499         DE_ASSERT(false);
500     }
501 
502     std::ostringstream vert;
503     std::ostringstream frag;
504     std::ostringstream &op = isVtxCase ? vert : frag;
505 
506     vert << "attribute highp vec4 a_position;\n"
507          << "attribute " << coordPrecName << " " << coordTypeName << " a_in0;\n";
508 
509     if (hasLodBias)
510         vert << "attribute " << coordPrecName << " float a_in1;\n";
511 
512     if (isVtxCase)
513     {
514         vert << "varying mediump vec4 v_color;\n";
515         frag << "varying mediump vec4 v_color;\n";
516     }
517     else
518     {
519         vert << "varying " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
520         frag << "varying " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
521 
522         if (hasLodBias)
523         {
524             vert << "varying " << coordPrecName << " float v_lodBias;\n";
525             frag << "varying " << coordPrecName << " float v_lodBias;\n";
526         }
527     }
528 
529     // Uniforms
530     op << "uniform lowp " << glu::getDataTypeName(samplerType) << " u_sampler;\n";
531 
532     vert << "\nvoid main()\n{\n"
533          << "\tgl_Position = a_position;\n";
534     frag << "\nvoid main()\n{\n";
535 
536     if (isVtxCase)
537         vert << "\tv_color = ";
538     else
539         frag << "\tgl_FragColor = ";
540 
541     // Op.
542     {
543         const char *texCoord = isVtxCase ? "a_in0" : "v_texCoord";
544         const char *lodBias  = isVtxCase ? "a_in1" : "v_lodBias";
545 
546         op << baseFuncName << funcExt;
547         op << "(u_sampler, " << texCoord;
548 
549         if (functionHasLod(function) || m_lookupSpec.useBias)
550             op << ", " << lodBias;
551 
552         op << ");\n";
553     }
554 
555     if (isVtxCase)
556         frag << "\tgl_FragColor = v_color;\n";
557     else
558     {
559         vert << "\tv_texCoord = a_in0;\n";
560 
561         if (hasLodBias)
562             vert << "\tv_lodBias = a_in1;\n";
563     }
564 
565     vert << "}\n";
566     frag << "}\n";
567 
568     m_vertShaderSource = vert.str();
569     m_fragShaderSource = frag.str();
570 }
571 
deinit(void)572 void ShaderTextureFunctionCase::deinit(void)
573 {
574     gls::ShaderRenderCase::deinit();
575 
576     delete m_texture2D;
577     delete m_textureCube;
578 
579     m_texture2D   = DE_NULL;
580     m_textureCube = DE_NULL;
581 }
582 
setupUniforms(int programID,const tcu::Vec4 &)583 void ShaderTextureFunctionCase::setupUniforms(int programID, const tcu::Vec4 &)
584 {
585     const glw::Functions &gl = m_renderCtx.getFunctions();
586     gl.uniform1i(gl.getUniformLocation(programID, "u_sampler"), 0);
587 }
588 
ShaderTextureFunctionTests(Context & context)589 ShaderTextureFunctionTests::ShaderTextureFunctionTests(Context &context)
590     : TestCaseGroup(context, "texture_functions", "Texture Access Function Tests")
591 {
592 }
593 
~ShaderTextureFunctionTests(void)594 ShaderTextureFunctionTests::~ShaderTextureFunctionTests(void)
595 {
596 }
597 
598 struct TexFuncCaseSpec
599 {
600     const char *name;
601     TextureLookupSpec lookupSpec;
602     TextureSpec texSpec;
603     TexEvalFunc evalFunc;
604 };
605 
606 #define CASE_SPEC(NAME, FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, TEXSPEC, EVALFUNC)          \
607     {                                                                                                  \
608         #NAME, TextureLookupSpec(FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD), TEXSPEC, EVALFUNC \
609     }
610 
createCaseGroup(TestCaseGroup * parent,const char * groupName,const char * groupDesc,const TexFuncCaseSpec * cases,int numCases,bool isVertex)611 static void createCaseGroup(TestCaseGroup *parent, const char *groupName, const char *groupDesc,
612                             const TexFuncCaseSpec *cases, int numCases, bool isVertex)
613 {
614     tcu::TestCaseGroup *group = new tcu::TestCaseGroup(parent->getTestContext(), groupName, groupDesc);
615     parent->addChild(group);
616 
617     for (int ndx = 0; ndx < numCases; ndx++)
618         group->addChild(new ShaderTextureFunctionCase(parent->getContext(), cases[ndx].name, "", cases[ndx].lookupSpec,
619                                                       cases[ndx].texSpec, cases[ndx].evalFunc, isVertex));
620 }
621 
init(void)622 void ShaderTextureFunctionTests::init(void)
623 {
624     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
625 
626     // Samplers
627     static const tcu::Sampler samplerLinearNoMipmap(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
628                                                     tcu::Sampler::REPEAT_GL, tcu::Sampler::LINEAR,
629                                                     tcu::Sampler::LINEAR);
630     static tcu::Sampler samplerLinearMipmap(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
631                                             tcu::Sampler::LINEAR_MIPMAP_NEAREST, tcu::Sampler::LINEAR);
632 
633     samplerLinearMipmap.seamlessCubeMap = glu::IsES3Compatible(gl);
634 
635     // Default textures.
636     //                                                Type            Format        DataType            W        H        L    Sampler
637     static const TextureSpec tex2D(TEXTURETYPE_2D, GL_RGBA, GL_UNSIGNED_BYTE, 256, 256, 1, samplerLinearNoMipmap);
638     static const TextureSpec tex2DMipmap(TEXTURETYPE_2D, GL_RGBA, GL_UNSIGNED_BYTE, 256, 256, 9, samplerLinearMipmap);
639 
640     static const TextureSpec texCube(TEXTURETYPE_CUBE_MAP, GL_RGBA, GL_UNSIGNED_BYTE, 256, 256, 1,
641                                      samplerLinearNoMipmap);
642     static const TextureSpec texCubeMipmap(TEXTURETYPE_CUBE_MAP, GL_RGBA, GL_UNSIGNED_BYTE, 256, 256, 9,
643                                            samplerLinearMipmap);
644 
645     // Vertex cases
646     static const TexFuncCaseSpec vertexCases[] = {
647         //          Name                        Function                    MinCoord                            MaxCoord                            Bias?    MinLod    MaxLod    Texture            EvalFunc
648         CASE_SPEC(texture2d, FUNCTION_TEXTURE, Vec4(-0.2f, -0.4f, 0.0f, 0.0f), Vec4(1.5f, 2.3f, 0.0f, 0.0f), false,
649                   0.0f, 0.0f, tex2D, evalTexture2D),
650         //        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),
651         CASE_SPEC(texture2dproj_vec3, FUNCTION_TEXTUREPROJ3, Vec4(-0.3f, -0.6f, 1.5f, 0.0f),
652                   Vec4(2.25f, 3.45f, 1.5f, 0.0f), false, 0.0f, 0.0f, tex2D, evalTexture2DProj3),
653         CASE_SPEC(texture2dproj_vec4, FUNCTION_TEXTUREPROJ, Vec4(-0.3f, -0.6f, 0.0f, 1.5f),
654                   Vec4(2.25f, 3.45f, 0.0f, 1.5f), false, 0.0f, 0.0f, tex2D, evalTexture2DProj),
655         CASE_SPEC(texture2dlod, FUNCTION_TEXTURELOD, Vec4(-0.2f, -0.4f, 0.0f, 0.0f), Vec4(1.5f, 2.3f, 0.0f, 0.0f),
656                   false, -1.0f, 9.0f, tex2DMipmap, evalTexture2DLod),
657         //        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),
658         //        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),
659         CASE_SPEC(texture2dprojlod_vec3, FUNCTION_TEXTUREPROJLOD3, Vec4(-0.3f, -0.6f, 1.5f, 0.0f),
660                   Vec4(2.25f, 3.45f, 1.5f, 0.0f), false, -1.0f, 9.0f, tex2D, evalTexture2DProjLod3),
661         CASE_SPEC(texture2dprojlod_vec4, FUNCTION_TEXTUREPROJLOD, Vec4(-0.3f, -0.6f, 0.0f, 1.5f),
662                   Vec4(2.25f, 3.45f, 0.0f, 1.5f), false, -1.0f, 9.0f, tex2D, evalTexture2DProjLod),
663         CASE_SPEC(texturecube, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, 0.0f), Vec4(1.0f, 1.0f, 1.01f, 0.0f), false,
664                   0.0f, 0.0f, texCube, evalTextureCube),
665         //        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),
666         CASE_SPEC(texturecubelod, FUNCTION_TEXTURELOD, Vec4(-1.0f, -1.0f, 1.01f, 0.0f), Vec4(1.0f, 1.0f, 1.01f, 0.0f),
667                   false, -1.0f, 9.0f, texCubeMipmap, evalTextureCubeLod),
668     };
669     createCaseGroup(this, "vertex", "Vertex Shader Texture Lookups", &vertexCases[0], DE_LENGTH_OF_ARRAY(vertexCases),
670                     true);
671 
672     // Fragment cases
673     static const TexFuncCaseSpec fragmentCases[] = {
674         //          Name                        Function                MinCoord                            MaxCoord                            Bias?    MinLod    MaxLod    Texture            EvalFunc
675         CASE_SPEC(texture2d, FUNCTION_TEXTURE, Vec4(-0.2f, -0.4f, 0.0f, 0.0f), Vec4(1.5f, 2.3f, 0.0f, 0.0f), false,
676                   0.0f, 0.0f, tex2DMipmap, evalTexture2D),
677         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,
678                   -2.0f, 2.0f, tex2DMipmap, evalTexture2DBias),
679         CASE_SPEC(texture2dproj_vec3, FUNCTION_TEXTUREPROJ3, Vec4(-0.3f, -0.6f, 1.5f, 0.0f),
680                   Vec4(2.25f, 3.45f, 1.5f, 0.0f), false, 0.0f, 0.0f, tex2DMipmap, evalTexture2DProj3),
681         CASE_SPEC(texture2dproj_vec4, FUNCTION_TEXTUREPROJ, Vec4(-0.3f, -0.6f, 0.0f, 1.5f),
682                   Vec4(2.25f, 3.45f, 0.0f, 1.5f), false, 0.0f, 0.0f, tex2DMipmap, evalTexture2DProj),
683         CASE_SPEC(texture2dproj_vec3_bias, FUNCTION_TEXTUREPROJ3, Vec4(-0.3f, -0.6f, 1.5f, 0.0f),
684                   Vec4(2.25f, 3.45f, 1.5f, 0.0f), true, -2.0f, 2.0f, tex2DMipmap, evalTexture2DProj3Bias),
685         CASE_SPEC(texture2dproj_vec4_bias, FUNCTION_TEXTUREPROJ, Vec4(-0.3f, -0.6f, 0.0f, 1.5f),
686                   Vec4(2.25f, 3.45f, 0.0f, 1.5f), true, -2.0f, 2.0f, tex2DMipmap, evalTexture2DProjBias),
687         CASE_SPEC(texturecube, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, 0.0f), Vec4(1.0f, 1.0f, 1.01f, 0.0f), false,
688                   0.0f, 0.0f, texCubeMipmap, evalTextureCube),
689         CASE_SPEC(texturecube_bias, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, -1.01f, 0.0f), Vec4(1.0f, 1.0f, -1.01f, 0.0f),
690                   true, -2.0f, 2.0f, texCubeMipmap, evalTextureCubeBias)};
691     createCaseGroup(this, "fragment", "Fragment Shader Texture Lookups", &fragmentCases[0],
692                     DE_LENGTH_OF_ARRAY(fragmentCases), false);
693 
694     // Negative cases.
695     {
696         gls::ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
697         std::vector<tcu::TestNode *> negativeCases = library.loadShaderFile("shaders/invalid_texture_functions.test");
698 
699         tcu::TestCaseGroup *group =
700             new tcu::TestCaseGroup(m_testCtx, "invalid", "Invalid texture function usage", negativeCases);
701         addChild(group);
702     }
703 }
704 
705 } // namespace Functional
706 } // namespace gles2
707 } // namespace deqp
708