1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2019 The Khronos Group Inc.
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
22 */ /*-------------------------------------------------------------------*/
23
24 /*!
25 * \file esextcTextureShadowLodFunctionsTest.cpp
26 * \brief EXT_texture_shadow_lod extension testing
27 */ /*-------------------------------------------------------------------*/
28
29 #include "esextcTextureShadowLodFunctionsTest.hpp"
30 #include "deMath.h"
31 #include "glcShaderLibrary.hpp"
32 #include "glcShaderRenderCase.hpp"
33 #include "glsTextureTestUtil.hpp"
34 #include "gluPixelTransfer.hpp"
35 #include "gluStrUtil.hpp"
36 #include "gluTexture.hpp"
37 #include "gluTextureUtil.hpp"
38 #include "glwFunctions.hpp"
39 #include "tcuMatrix.hpp"
40 #include "tcuMatrixUtil.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuTextureUtil.hpp"
43
44 #include <sstream>
45
46 #include "glwEnums.hpp"
47 #include "glwFunctions.hpp"
48
49 namespace deqp
50 {
51 namespace Functional
52 {
53 namespace
54 {
55
56 using glu::TextureTestUtil::computeLodFromDerivates;
57
58 enum Function
59 {
60 FUNCTION_TEXTURE = 0, //!< texture(), textureOffset()
61 FUNCTION_TEXTURELOD, // ...
62 FUNCTION_LAST
63 };
64
65 // For texture(..., [bias]) functions.
functionHasAutoLod(glu::ShaderType shaderType,Function function)66 inline bool functionHasAutoLod(glu::ShaderType shaderType, Function function)
67 {
68 return (shaderType == glu::SHADERTYPE_FRAGMENT) && (function == FUNCTION_TEXTURE);
69 }
70
71 // For textureLod* functions.
functionHasLod(Function function)72 inline bool functionHasLod(Function function)
73 {
74 return function == FUNCTION_TEXTURELOD;
75 }
76
77 struct TextureLookupSpec
78 {
79 // The texture function to use.
80 Function function;
81
82 // Min/max texture coordinates.
83 tcu::Vec4 minCoord;
84 tcu::Vec4 maxCoord;
85
86 // Bias
87 bool useBias;
88
89 // Bias or Lod for *Lod* functions
90 float minLodBias;
91 float maxLodBias;
92
93 // For *Offset variants
94 bool useOffset;
95 tcu::IVec3 offset;
96
97 // Do we require an additional shadow ref "compare"
98 // parameter in the texture function's parameter list? (used for
99 // shadow cube array textures).
100 bool useSepRef;
101 float minSepRef;
102 float maxSepRef;
103
TextureLookupSpecdeqp::Functional::__anon922096fb0111::TextureLookupSpec104 TextureLookupSpec(void)
105 : function(FUNCTION_LAST)
106 , minCoord(0.0f)
107 , maxCoord(1.0f)
108 , useBias(false)
109 , minLodBias(0.0f)
110 , maxLodBias(0.0f)
111 , useOffset(false)
112 , offset(0)
113 , useSepRef(false)
114 , minSepRef(0.0f)
115 , maxSepRef(0.0f)
116 {
117 }
118
TextureLookupSpecdeqp::Functional::__anon922096fb0111::TextureLookupSpec119 TextureLookupSpec(Function function_, const tcu::Vec4& minCoord_, const tcu::Vec4& maxCoord_, bool useBias_,
120 float minLodBias_, float maxLodBias_, bool useOffset_, const tcu::IVec3& offset_, bool useSepRef_,
121 float minSepRef_, float maxSepRef_)
122 : function(function_)
123 , minCoord(minCoord_)
124 , maxCoord(maxCoord_)
125 , useBias(useBias_)
126 , minLodBias(minLodBias_)
127 , maxLodBias(maxLodBias_)
128 , useOffset(useOffset_)
129 , offset(offset_)
130 , useSepRef(useSepRef_)
131 , minSepRef(minSepRef_)
132 , maxSepRef(maxSepRef_)
133 {
134 }
135 };
136
137 // Only shadow texture types contained in EXT_texture_shadow_lod will be tested.
138 enum TextureType
139 {
140 TEXTURETYPE_2D,
141 TEXTURETYPE_CUBE_MAP,
142 TEXTURETYPE_CUBE_MAP_ARRAY,
143 TEXTURETYPE_2D_ARRAY,
144
145 TEXTURETYPE_LAST
146 };
147
148 struct TextureSpec
149 {
150 TextureType type; //!< Texture type (2D, cubemap, ...)
151 deUint32 format; //!< Internal format.
152 int width;
153 int height;
154 int depth;
155 int numLevels;
156 tcu::Sampler sampler;
157
TextureSpecdeqp::Functional::__anon922096fb0111::TextureSpec158 TextureSpec(void) : type(TEXTURETYPE_LAST), format(GL_NONE), width(0), height(0), depth(0), numLevels(0)
159 {
160 }
161
TextureSpecdeqp::Functional::__anon922096fb0111::TextureSpec162 TextureSpec(TextureType type_, deUint32 format_, int width_, int height_, int depth_, int numLevels_,
163 const tcu::Sampler& sampler_)
164 : type(type_)
165 , format(format_)
166 , width(width_)
167 , height(height_)
168 , depth(depth_)
169 , numLevels(numLevels_)
170 , sampler(sampler_)
171 {
172 }
173 };
174
175 struct TexLookupParams
176 {
177 float lod;
178 tcu::IVec3 offset;
179 tcu::Vec4 scale;
180 tcu::Vec4 bias;
181
TexLookupParamsdeqp::Functional::__anon922096fb0111::TexLookupParams182 TexLookupParams(void) : lod(0.0f), offset(0), scale(1.0f), bias(0.0f)
183 {
184 }
185 };
186
187 } // namespace
188
189 using tcu::IVec2;
190 using tcu::IVec3;
191 using tcu::IVec4;
192 using tcu::Vec2;
193 using tcu::Vec3;
194 using tcu::Vec4;
195
196 static const glu::TextureTestUtil::LodMode DEFAULT_LOD_MODE = glu::TextureTestUtil::LODMODE_EXACT;
197
198 typedef void (*TexEvalFunc)(ShaderEvalContext& c, const TexLookupParams& lookupParams);
199
texture2DShadow(const ShaderEvalContext & c,float ref,float s,float t,float lod)200 inline float texture2DShadow(const ShaderEvalContext& c, float ref, float s, float t, float lod)
201 {
202 return c.textures[0].tex2D->sampleCompare(c.textures[0].sampler, ref, s, t, lod);
203 }
texture2DArrayShadow(const ShaderEvalContext & c,float ref,float s,float t,float r,float lod)204 inline float texture2DArrayShadow(const ShaderEvalContext& c, float ref, float s, float t, float r, float lod)
205 {
206 return c.textures[0].tex2DArray->sampleCompare(c.textures[0].sampler, ref, s, t, r, lod);
207 }
textureCubeShadow(const ShaderEvalContext & c,float ref,float s,float t,float r,float lod)208 inline float textureCubeShadow(const ShaderEvalContext& c, float ref, float s, float t, float r, float lod)
209 {
210 return c.textures[0].texCube->sampleCompare(c.textures[0].sampler, ref, s, t, r, lod);
211 }
textureCubeArrayShadow(const ShaderEvalContext & c,float ref,float s,float t,float r,float q,float lod)212 inline float textureCubeArrayShadow(const ShaderEvalContext& c, float ref, float s, float t, float r, float q,
213 float lod)
214 {
215 return c.textures[0].texCubeArray->sampleCompare(c.textures[0].sampler, ref, s, t, r, q, lod);
216 }
texture2DShadowOffset(const ShaderEvalContext & c,float ref,float s,float t,float lod,IVec2 offset)217 inline float texture2DShadowOffset(const ShaderEvalContext& c, float ref, float s, float t, float lod, IVec2 offset)
218 {
219 return c.textures[0].tex2D->sampleCompareOffset(c.textures[0].sampler, ref, s, t, lod, offset);
220 }
texture2DArrayShadowOffset(const ShaderEvalContext & c,float ref,float s,float t,float r,float lod,IVec2 offset)221 inline float texture2DArrayShadowOffset(const ShaderEvalContext& c, float ref, float s, float t, float r, float lod,
222 IVec2 offset)
223 {
224 return c.textures[0].tex2DArray->sampleCompareOffset(c.textures[0].sampler, ref, s, t, r, lod, offset);
225 }
226
227 // Shadow evaluation functions
evalTexture2DArrayShadow(ShaderEvalContext & c,const TexLookupParams & p)228 static void evalTexture2DArrayShadow(ShaderEvalContext& c, const TexLookupParams& p)
229 {
230 c.color.x() = texture2DArrayShadow(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod);
231 }
evalTexture2DArrayShadowBias(ShaderEvalContext & c,const TexLookupParams & p)232 static void evalTexture2DArrayShadowBias(ShaderEvalContext& c, const TexLookupParams& p)
233 {
234 c.color.x() = texture2DArrayShadow(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod + c.in[1].x());
235 }
evalTexture2DArrayShadowOffset(ShaderEvalContext & c,const TexLookupParams & p)236 static void evalTexture2DArrayShadowOffset(ShaderEvalContext& c, const TexLookupParams& p)
237 {
238 c.color.x() = texture2DArrayShadowOffset(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod,
239 p.offset.swizzle(0, 1));
240 }
evalTexture2DArrayShadowOffsetBias(ShaderEvalContext & c,const TexLookupParams & p)241 static void evalTexture2DArrayShadowOffsetBias(ShaderEvalContext& c, const TexLookupParams& p)
242 {
243 c.color.x() = texture2DArrayShadowOffset(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod + c.in[1].x(),
244 p.offset.swizzle(0, 1));
245 }
246
evalTexture2DArrayShadowLod(ShaderEvalContext & c,const TexLookupParams & p)247 static void evalTexture2DArrayShadowLod(ShaderEvalContext& c, const TexLookupParams& p)
248 {
249 (void)p;
250 c.color.x() = texture2DArrayShadow(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[1].x());
251 }
evalTexture2DArrayShadowLodOffset(ShaderEvalContext & c,const TexLookupParams & p)252 static void evalTexture2DArrayShadowLodOffset(ShaderEvalContext& c, const TexLookupParams& p)
253 {
254 c.color.x() = texture2DArrayShadowOffset(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[1].x(),
255 p.offset.swizzle(0, 1));
256 }
257
evalTextureCubeShadow(ShaderEvalContext & c,const TexLookupParams & p)258 static void evalTextureCubeShadow(ShaderEvalContext& c, const TexLookupParams& p)
259 {
260 c.color.x() = textureCubeShadow(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod);
261 }
evalTextureCubeShadowBias(ShaderEvalContext & c,const TexLookupParams & p)262 static void evalTextureCubeShadowBias(ShaderEvalContext& c, const TexLookupParams& p)
263 {
264 c.color.x() = textureCubeShadow(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod + c.in[1].x());
265 }
evalTextureCubeShadowLod(ShaderEvalContext & c,const TexLookupParams & p)266 static void evalTextureCubeShadowLod(ShaderEvalContext& c, const TexLookupParams& p)
267 {
268 (void)p;
269 c.color.x() = textureCubeShadow(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[1].x());
270 }
271
evalTextureCubeArrayShadow(ShaderEvalContext & c,const TexLookupParams & p)272 static void evalTextureCubeArrayShadow(ShaderEvalContext& c, const TexLookupParams& p)
273 {
274 c.color.x() = textureCubeArrayShadow(c, c.in[1].y(), c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[0].w(), p.lod);
275 }
evalTextureCubeArrayShadowBias(ShaderEvalContext & c,const TexLookupParams & p)276 static void evalTextureCubeArrayShadowBias(ShaderEvalContext& c, const TexLookupParams& p)
277 {
278 c.color.x() =
279 textureCubeArrayShadow(c, c.in[1].y(), c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[0].w(), p.lod + c.in[1].x());
280 }
evalTextureCubeArrayShadowLod(ShaderEvalContext & c,const TexLookupParams & p)281 static void evalTextureCubeArrayShadowLod(ShaderEvalContext& c, const TexLookupParams& p)
282 {
283 (void)p;
284 c.color.x() =
285 textureCubeArrayShadow(c, c.in[1].y(), c.in[0].x(), c.in[0].y(), c.in[0].z(), c.in[0].w(), c.in[1].x());
286 }
287
288 class TexLookupEvaluator : public ShaderEvaluator
289 {
290 public:
TexLookupEvaluator(TexEvalFunc evalFunc,const TexLookupParams & lookupParams)291 TexLookupEvaluator(TexEvalFunc evalFunc, const TexLookupParams& lookupParams)
292 : m_evalFunc(evalFunc), m_lookupParams(lookupParams)
293 {
294 }
295
evaluate(ShaderEvalContext & ctx)296 virtual void evaluate(ShaderEvalContext& ctx)
297 {
298 m_evalFunc(ctx, m_lookupParams);
299 }
300
301 private:
302 TexEvalFunc m_evalFunc;
303 const TexLookupParams& m_lookupParams;
304 };
305
306 class TextureShadowLodTestCase : public ShaderRenderCase
307 {
308 public:
309 TextureShadowLodTestCase(Context& context, const char* name, const char* desc, const TextureLookupSpec& lookup,
310 const TextureSpec& texture, TexEvalFunc evalFunc, bool isVertexCase);
311 ~TextureShadowLodTestCase(void);
312
313 void init(void);
314 void deinit(void);
315
316 protected:
317 void setupUniforms(deUint32 programID, const tcu::Vec4& constCoords);
318
319 private:
320 void initTexture(void);
321 void initShaderSources(void);
322
323 TextureLookupSpec m_lookupSpec;
324 TextureSpec m_textureSpec;
325
326 TexLookupParams m_lookupParams;
327 TexLookupEvaluator m_evaluator;
328
329 glu::Texture2D* m_texture2D;
330 glu::TextureCube* m_textureCube;
331 glu::TextureCubeArray* m_textureCubeArray;
332 glu::Texture2DArray* m_texture2DArray;
333 };
334
TextureShadowLodTestCase(Context & context,const char * name,const char * desc,const TextureLookupSpec & lookup,const TextureSpec & texture,TexEvalFunc evalFunc,bool isVertexCase)335 TextureShadowLodTestCase::TextureShadowLodTestCase(Context& context, const char* name, const char* desc,
336 const TextureLookupSpec& lookup, const TextureSpec& texture,
337 TexEvalFunc evalFunc, bool isVertexCase)
338 : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc,
339 isVertexCase, m_evaluator)
340 , m_lookupSpec(lookup)
341 , m_textureSpec(texture)
342 , m_evaluator(evalFunc, m_lookupParams)
343 , m_texture2D(DE_NULL)
344 , m_textureCube(DE_NULL)
345 , m_textureCubeArray(DE_NULL)
346 , m_texture2DArray(DE_NULL)
347 {
348 }
349
~TextureShadowLodTestCase(void)350 TextureShadowLodTestCase::~TextureShadowLodTestCase(void)
351 {
352 delete m_texture2D;
353 delete m_textureCube;
354 delete m_textureCubeArray;
355 delete m_texture2DArray;
356 }
357
init(void)358 void TextureShadowLodTestCase::init(void)
359 {
360 // Check extension and other features are supported with this context/platform.
361 {
362 glu::ContextInfo* info = glu::ContextInfo::create(m_renderCtx);
363
364 // First check if extension is available.
365 if (!info->isExtensionSupported("GL_EXT_texture_shadow_lod"))
366 {
367 throw tcu::NotSupportedError("EXT_texture_shadow_lod is not supported on the platform");
368 }
369
370 // Check that API support and that the various texture_cube_map_array extension is supported based on GL / ES versions.
371
372 if (glu::isContextTypeES(m_renderCtx.getType()))
373 {
374 // ES
375 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 0)))
376 {
377 throw tcu::NotSupportedError(
378 "EXT_texture_shadow_lod is not supported due to minimum ES version requirements");
379 }
380
381 // Check if cube map array is supported. For ES, it is supported
382 // as of ES 3.2, or with OES_texture_cube_map_array for
383 // 3.1.
384 if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY)
385 {
386 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 2)) &&
387 !(glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 1)) &&
388 (info->isExtensionSupported("GL_OES_texture_cube_map_array") ||
389 info->isExtensionSupported("GL_EXT_texture_cube_map_array"))))
390 {
391 throw tcu::NotSupportedError("GL_OES_texture_cube_map_array or GL_EXT_texture_cube_map_array is "
392 "required for this configuration and is not available.");
393 }
394 }
395 }
396 else
397 {
398 // GL
399 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(2, 0)))
400 {
401 throw tcu::NotSupportedError(
402 "EXT_texture_shadow_lod is not supported due to minimum GL version requirements");
403 }
404
405 // Check if cube map array is supported. For GL, it is supported
406 // as of GL 4.0 core, or with ARB_texture_cube_map_array prior.
407 if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY)
408 {
409 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 0)) &&
410 !info->isExtensionSupported("GL_ARB_texture_cube_map_array"))
411 {
412 throw tcu::NotSupportedError(
413 "ARB_texture_cube_map_array is required for this configuration and is not available.");
414 }
415 }
416 }
417 }
418
419 // Set up the user attributes.
420 // The user attributes are set up as matrices where each row represents a component
421 // in the attribute transformed against the vertex's interpolated position across the grid.
422 {
423 // Base coord scale & bias
424 Vec4 s = m_lookupSpec.maxCoord - m_lookupSpec.minCoord;
425 Vec4 b = m_lookupSpec.minCoord;
426
427 float baseCoordTrans[] = { s.x(), 0.0f, 0.f, b.x(),
428 0.f, s.y(), 0.f, b.y(),
429 s.z() / 2.f, -s.z() / 2.f, 0.f, s.z() / 2.f + b.z(),
430 -s.w() / 2.f, s.w() / 2.f, 0.f, s.w() / 2.f + b.w() };
431
432 //a_in0
433 m_userAttribTransforms.push_back(tcu::Mat4(baseCoordTrans));
434 }
435
436 bool hasLodBias = functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias;
437
438 if (hasLodBias || m_lookupSpec.useSepRef)
439 {
440 float s = 0.0f;
441 float b = 0.0f;
442 float sepRefS = 0.0f;
443 float sepRefB = 0.0f;
444
445 if (hasLodBias)
446 {
447 s = m_lookupSpec.maxLodBias - m_lookupSpec.minLodBias;
448 b = m_lookupSpec.minLodBias;
449 }
450
451 if (m_lookupSpec.useSepRef)
452 {
453 sepRefS = m_lookupSpec.maxSepRef - m_lookupSpec.minSepRef;
454 sepRefB = m_lookupSpec.minSepRef;
455 }
456 float lodCoordTrans[] = { s / 2.0f, s / 2.0f, 0.f, b, sepRefS / 2.0f, sepRefS / 2.0f, 0.0f, sepRefB,
457 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
458
459 //a_in1
460 m_userAttribTransforms.push_back(tcu::Mat4(lodCoordTrans));
461 }
462
463 initShaderSources();
464 initTexture();
465
466 ShaderRenderCase::init();
467 }
468
initTexture(void)469 void TextureShadowLodTestCase::initTexture(void)
470 {
471 static const IVec4 texCubeSwz[] = { IVec4(0, 0, 1, 1), IVec4(1, 1, 0, 0), IVec4(0, 1, 0, 1),
472 IVec4(1, 0, 1, 0), IVec4(0, 1, 1, 0), IVec4(1, 0, 0, 1) };
473 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(texCubeSwz) == tcu::CUBEFACE_LAST);
474
475 tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_textureSpec.format);
476 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
477 tcu::IVec2 viewportSize = getViewportSize();
478 bool isAutoLod = functionHasAutoLod(m_isVertexCase ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT,
479 m_lookupSpec.function); // LOD can vary significantly
480
481 switch (m_textureSpec.type)
482 {
483 case TEXTURETYPE_2D:
484 {
485 float levelStep = isAutoLod ? 0.0f : 1.0f / (float)de::max(1, m_textureSpec.numLevels - 1);
486 Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
487 Vec4 cBias = fmtInfo.valueMin;
488 int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
489
490 m_texture2D = new glu::Texture2D(m_renderCtx, m_textureSpec.format, m_textureSpec.width, m_textureSpec.height);
491 for (int level = 0; level < m_textureSpec.numLevels; level++)
492 {
493 float fA = float(level) * levelStep;
494 float fB = 1.0f - fA;
495 Vec4 colorA = cBias + cScale * Vec4(fA, fB, fA, fB);
496 Vec4 colorB = cBias + cScale * Vec4(fB, fA, fB, fA);
497
498 m_texture2D->getRefTexture().allocLevel(level);
499 tcu::fillWithGrid(m_texture2D->getRefTexture().getLevel(level), de::max(1, baseCellSize >> level), colorA,
500 colorB);
501 }
502 m_texture2D->upload();
503
504 // Compute LOD.
505 float dudx =
506 (m_lookupSpec.maxCoord[0] - m_lookupSpec.minCoord[0]) * (float)m_textureSpec.width / (float)viewportSize[0];
507 float dvdy = (m_lookupSpec.maxCoord[1] - m_lookupSpec.minCoord[1]) * (float)m_textureSpec.height /
508 (float)viewportSize[1];
509 m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy);
510
511 // Append to texture list.
512 m_textures.push_back(TextureBinding(m_texture2D, m_textureSpec.sampler));
513 break;
514 }
515
516 case TEXTURETYPE_2D_ARRAY:
517 {
518 float layerStep = 1.0f / (float)m_textureSpec.depth;
519 float levelStep =
520 isAutoLod ? 0.0f : 1.0f / (float)(de::max(1, m_textureSpec.numLevels - 1) * m_textureSpec.depth);
521 Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
522 Vec4 cBias = fmtInfo.valueMin;
523 int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
524
525 m_texture2DArray = new glu::Texture2DArray(m_renderCtx, m_textureSpec.format, m_textureSpec.width,
526 m_textureSpec.height, m_textureSpec.depth);
527 for (int level = 0; level < m_textureSpec.numLevels; level++)
528 {
529 m_texture2DArray->getRefTexture().allocLevel(level);
530 tcu::PixelBufferAccess levelAccess = m_texture2DArray->getRefTexture().getLevel(level);
531
532 for (int layer = 0; layer < levelAccess.getDepth(); layer++)
533 {
534 float fA = (float)layer * layerStep + (float)level * levelStep;
535 float fB = 1.0f - fA;
536 Vec4 colorA = cBias + cScale * Vec4(fA, fB, fA, fB);
537 Vec4 colorB = cBias + cScale * Vec4(fB, fA, fB, fA);
538
539 tcu::fillWithGrid(
540 tcu::getSubregion(levelAccess, 0, 0, layer, levelAccess.getWidth(), levelAccess.getHeight(), 1),
541 de::max(1, baseCellSize >> level), colorA, colorB);
542 }
543 }
544 m_texture2DArray->upload();
545
546 // Compute LOD.
547 float dudx =
548 (m_lookupSpec.maxCoord[0] - m_lookupSpec.minCoord[0]) * (float)m_textureSpec.width / (float)viewportSize[0];
549 float dvdy = (m_lookupSpec.maxCoord[1] - m_lookupSpec.minCoord[1]) * (float)m_textureSpec.height /
550 (float)viewportSize[1];
551 m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy);
552
553 // Append to texture list.
554 m_textures.push_back(TextureBinding(m_texture2DArray, m_textureSpec.sampler));
555 break;
556 }
557
558 case TEXTURETYPE_CUBE_MAP:
559 {
560 float levelStep = isAutoLod ? 0.0f : 1.0f / (float)de::max(1, m_textureSpec.numLevels - 1);
561 Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
562 Vec4 cBias = fmtInfo.valueMin;
563 Vec4 cCorner = cBias + cScale * 0.5f;
564 int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
565
566 DE_ASSERT(m_textureSpec.width == m_textureSpec.height);
567 m_textureCube = new glu::TextureCube(m_renderCtx, m_textureSpec.format, m_textureSpec.width);
568 for (int level = 0; level < m_textureSpec.numLevels; level++)
569 {
570 float fA = float(level) * levelStep;
571 float fB = 1.0f - fA;
572 Vec2 f(fA, fB);
573
574 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
575 {
576 const IVec4& swzA = texCubeSwz[face];
577 IVec4 swzB = 1 - swzA;
578 Vec4 colorA = cBias + cScale * f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]);
579 Vec4 colorB = cBias + cScale * f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]);
580
581 m_textureCube->getRefTexture().allocLevel((tcu::CubeFace)face, level);
582 {
583 const tcu::PixelBufferAccess access =
584 m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face);
585 const int lastPix = access.getWidth() - 1;
586
587 tcu::fillWithGrid(access, de::max(1, baseCellSize >> level), colorA, colorB);
588
589 // Ensure all corners have identical colors in order to avoid dealing with ambiguous corner texel filtering
590 access.setPixel(cCorner, 0, 0);
591 access.setPixel(cCorner, 0, lastPix);
592 access.setPixel(cCorner, lastPix, 0);
593 access.setPixel(cCorner, lastPix, lastPix);
594 }
595 }
596 }
597 m_textureCube->upload();
598
599 // Compute LOD \note Assumes that only single side is accessed and R is constant major axis.
600 DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005);
601 DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) &&
602 de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2]));
603 DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) &&
604 de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2]));
605
606 tcu::CubeFaceFloatCoords c00 =
607 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2]));
608 tcu::CubeFaceFloatCoords c10 =
609 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.maxCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2]));
610 tcu::CubeFaceFloatCoords c01 =
611 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.maxCoord[1], m_lookupSpec.minCoord[2]));
612 float dudx = (c10.s - c00.s) * (float)m_textureSpec.width / (float)viewportSize[0];
613 float dvdy = (c01.t - c00.t) * (float)m_textureSpec.height / (float)viewportSize[1];
614
615 m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy);
616
617 m_textures.push_back(TextureBinding(m_textureCube, m_textureSpec.sampler));
618 break;
619 }
620
621 case TEXTURETYPE_CUBE_MAP_ARRAY:
622 {
623 float layerStep = 1.0f / (float)m_textureSpec.depth;
624 float levelStep =
625 isAutoLod ? 0.0f : 1.0f / (float)(de::max(1, m_textureSpec.numLevels - 1) * m_textureSpec.depth);
626 Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
627 Vec4 cBias = fmtInfo.valueMin;
628 Vec4 cCorner = cBias + cScale * 0.5f;
629 int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
630
631 DE_ASSERT(m_textureSpec.width == m_textureSpec.height);
632 // I think size here means width/height of cube tex
633 m_textureCubeArray =
634 new glu::TextureCubeArray(m_renderCtx, m_textureSpec.format, m_textureSpec.width, m_textureSpec.depth * 6);
635 // mipmap level
636 for (int level = 0; level < m_textureSpec.numLevels; level++)
637 {
638 m_textureCubeArray->getRefTexture().allocLevel(level);
639 tcu::PixelBufferAccess levelAccess = m_textureCubeArray->getRefTexture().getLevel(level);
640
641 //array layer
642 DE_ASSERT((levelAccess.getDepth() % 6) == 0);
643
644 for (int layer = 0; layer < levelAccess.getDepth() / 6; ++layer)
645 {
646 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
647 {
648 float fA = (float)layer * layerStep + float(level) * levelStep;
649 float fB = 1.0f - fA;
650 Vec2 f(fA, fB);
651
652 const IVec4& swzA = texCubeSwz[face];
653 IVec4 swzB = 1 - swzA;
654 Vec4 colorA = cBias + cScale * f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]);
655 Vec4 colorB = cBias + cScale * f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]);
656
657 {
658 const tcu::PixelBufferAccess access = m_textureCubeArray->getRefTexture().getLevel(level);
659 const int lastPix = access.getWidth() - 1;
660
661 int layerFaceNdx = face + layer * 6;
662
663 DE_ASSERT(levelAccess.getWidth() == levelAccess.getHeight());
664 tcu::fillWithGrid(tcu::getSubregion(access, 0, 0, layerFaceNdx, levelAccess.getWidth(),
665 levelAccess.getHeight(), 1),
666 de::max(1, baseCellSize >> level), colorA, colorB);
667
668 // Ensure all corners have identical colors in order to avoid dealing with ambiguous corner texel filtering
669 access.setPixel(cCorner, 0, 0, layer);
670 access.setPixel(cCorner, 0, lastPix, layer);
671 access.setPixel(cCorner, lastPix, 0, layer);
672 access.setPixel(cCorner, lastPix, lastPix, layer);
673 }
674 }
675 }
676 }
677 m_textureCubeArray->upload();
678
679 // Compute LOD \note Assumes that only single side is accessed and R is constant major axis.
680 DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005);
681 DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) &&
682 de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2]));
683 DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) &&
684 de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2]));
685
686 tcu::CubeFaceFloatCoords c00 =
687 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2]));
688 tcu::CubeFaceFloatCoords c10 =
689 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.maxCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2]));
690 tcu::CubeFaceFloatCoords c01 =
691 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.maxCoord[1], m_lookupSpec.minCoord[2]));
692 float dudx = (c10.s - c00.s) * (float)m_textureSpec.width / (float)viewportSize[0];
693 float dvdy = (c01.t - c00.t) * (float)m_textureSpec.height / (float)viewportSize[1];
694
695 m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy);
696
697 m_textures.push_back(TextureBinding(m_textureCubeArray, m_textureSpec.sampler));
698 break;
699 }
700
701 default:
702 DE_ASSERT(DE_FALSE);
703 }
704
705 // Set lookup scale & bias
706 m_lookupParams.scale = fmtInfo.lookupScale;
707 m_lookupParams.bias = fmtInfo.lookupBias;
708 m_lookupParams.offset = m_lookupSpec.offset;
709 }
710
initShaderSources(void)711 void TextureShadowLodTestCase::initShaderSources(void)
712 {
713 Function function = m_lookupSpec.function;
714 bool isVtxCase = m_isVertexCase;
715 bool hasLodBias = functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias;
716 int texCoordComps = m_textureSpec.type == TEXTURETYPE_2D ? 2 : 3;
717 int extraCoordComps = 1; // For shadow ref
718 bool hasSepShadowRef = m_lookupSpec.useSepRef;
719 glu::DataType coordType = glu::getDataTypeFloatVec(texCoordComps + extraCoordComps);
720 glu::Precision coordPrec = glu::PRECISION_HIGHP;
721 const char* coordTypeName = glu::getDataTypeName(coordType);
722 const char* coordPrecName = glu::getPrecisionName(coordPrec);
723 glu::DataType samplerType = glu::TYPE_LAST;
724 const char* baseFuncName = DE_NULL;
725
726 switch (m_textureSpec.type)
727 {
728 case TEXTURETYPE_2D:
729 samplerType = glu::TYPE_SAMPLER_2D_SHADOW;
730 break;
731 case TEXTURETYPE_CUBE_MAP:
732 samplerType = glu::TYPE_SAMPLER_CUBE_SHADOW;
733 break;
734 case TEXTURETYPE_CUBE_MAP_ARRAY:
735 samplerType = glu::TYPE_SAMPLER_CUBE_ARRAY_SHADOW;
736 break;
737 case TEXTURETYPE_2D_ARRAY:
738 samplerType = glu::TYPE_SAMPLER_2D_ARRAY_SHADOW;
739 break;
740 default:
741 DE_ASSERT(DE_FALSE);
742 }
743
744 switch (m_lookupSpec.function)
745 {
746 case FUNCTION_TEXTURE:
747 baseFuncName = "texture";
748 break;
749 case FUNCTION_TEXTURELOD:
750 baseFuncName = "textureLod";
751 break;
752 default:
753 DE_ASSERT(DE_FALSE);
754 }
755
756 bool isGL = glu::isContextTypeGLCore(m_renderCtx.getType());
757 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_renderCtx.getType());
758
759 std::string shaderVersion = glu::getGLSLVersionDeclaration(glslVersion);
760
761 std::ostringstream vert;
762 std::ostringstream frag;
763 std::ostringstream& op = isVtxCase ? vert : frag;
764
765 std::string cubeMapArrayEXT = "";
766
767 // Check if we need to add the texture_cube_map_array extension.
768 if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY)
769 {
770 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 2)) &&
771 !glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 0)))
772 {
773 if (isGL)
774 {
775 cubeMapArrayEXT = "#extension GL_ARB_texture_cube_map_array : require\n";
776 }
777 else
778 {
779 glu::ContextInfo* info = glu::ContextInfo::create(m_renderCtx);
780 if (info->isExtensionSupported("GL_EXT_texture_cube_map_array"))
781 {
782 cubeMapArrayEXT = "#extension GL_EXT_texture_cube_map_array : require\n";
783 }
784 else
785 {
786 cubeMapArrayEXT = "#extension GL_OES_texture_cube_map_array : require\n";
787 }
788 }
789 }
790 }
791
792 vert << shaderVersion << "\n"
793 << "#extension GL_EXT_texture_shadow_lod : require\n\n";
794
795 vert << cubeMapArrayEXT;
796
797 vert << "in highp vec4 a_position;\n"
798 << "in " << coordPrecName << " " << coordTypeName << " a_in0;\n";
799
800 if (hasLodBias || hasSepShadowRef)
801 {
802 vert << "in " << coordPrecName << " vec4 a_in1;\n";
803 }
804
805 frag << shaderVersion << "\n"
806 << "#extension GL_EXT_texture_shadow_lod : require\n\n";
807
808 frag << cubeMapArrayEXT;
809
810 frag << "out mediump vec4 o_color;\n";
811
812 if (isVtxCase)
813 {
814 vert << "out mediump vec4 v_color;\n";
815 frag << "in mediump vec4 v_color;\n";
816 }
817 else
818 {
819 vert << "out " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
820 frag << "in " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
821
822 if (hasLodBias || hasSepShadowRef)
823 {
824 vert << "out " << coordPrecName << " vec4 v_lodShadowRef;\n";
825 frag << "in " << coordPrecName << " vec4 v_lodShadowRef;\n";
826 }
827 }
828
829 // Uniforms
830 op << "uniform highp " << glu::getDataTypeName(samplerType) << " u_sampler;\n"
831 << "uniform highp vec4 u_scale;\n"
832 << "uniform highp vec4 u_bias;\n";
833
834 vert << "\nvoid main()\n{\n"
835 << "\tgl_Position = a_position;\n";
836 frag << "\nvoid main()\n{\n";
837
838 if (isVtxCase)
839 vert << "\tv_color = ";
840 else
841 frag << "\to_color = ";
842
843 // Op.
844 {
845 const char* texCoord = isVtxCase ? "a_in0" : "v_texCoord";
846 const char* lodBias = isVtxCase ? "a_in1" : "v_lodShadowRef";
847
848 op << "vec4(" << baseFuncName;
849 if (m_lookupSpec.useOffset)
850 op << "Offset";
851 op << "(u_sampler, ";
852
853 op << texCoord;
854
855 if (m_lookupSpec.useSepRef)
856 {
857 op << ", " << lodBias << ".y";
858 }
859
860 if (functionHasLod(function))
861 {
862 op << ", " << lodBias << ".x";
863 }
864
865 if (m_lookupSpec.useOffset)
866 {
867 int offsetComps = 2;
868
869 op << ", ivec" << offsetComps << "(";
870 for (int ndx = 0; ndx < offsetComps; ndx++)
871 {
872 if (ndx != 0)
873 op << ", ";
874 op << m_lookupSpec.offset[ndx];
875 }
876 op << ")";
877 }
878
879 if (m_lookupSpec.useBias)
880 op << ", " << lodBias << ".x";
881
882 op << ")";
883
884 op << ", 0.0, 0.0, 1.0)";
885
886 op << ";\n";
887 }
888
889 if (isVtxCase)
890 frag << "\to_color = v_color;\n";
891 else
892 {
893 vert << "\tv_texCoord = a_in0;\n";
894
895 if (hasLodBias || hasSepShadowRef)
896 {
897 vert << "\tv_lodShadowRef = a_in1;\n";
898 }
899 }
900
901 vert << "}\n";
902 frag << "}\n";
903
904 m_vertShaderSource = vert.str();
905 m_fragShaderSource = frag.str();
906 }
907
deinit(void)908 void TextureShadowLodTestCase::deinit(void)
909 {
910 ShaderRenderCase::deinit();
911
912 delete m_texture2D;
913 delete m_textureCube;
914 delete m_texture2DArray;
915
916 m_texture2D = DE_NULL;
917 m_textureCube = DE_NULL;
918 m_texture2DArray = DE_NULL;
919 }
920
setupUniforms(deUint32 programID,const tcu::Vec4 &)921 void TextureShadowLodTestCase::setupUniforms(deUint32 programID, const tcu::Vec4&)
922 {
923 const glw::Functions& gl = m_renderCtx.getFunctions();
924 gl.uniform1i(gl.getUniformLocation(programID, "u_sampler"), 0);
925 gl.uniform4fv(gl.getUniformLocation(programID, "u_scale"), 1, m_lookupParams.scale.getPtr());
926 gl.uniform4fv(gl.getUniformLocation(programID, "u_bias"), 1, m_lookupParams.bias.getPtr());
927 }
928
TextureShadowLodTest(Context & context)929 TextureShadowLodTest::TextureShadowLodTest(Context& context)
930 : TestCaseGroup(context, "ext_texture_shadow_lod", "Texture Access Function Tests")
931 {
932 }
933
~TextureShadowLodTest(void)934 TextureShadowLodTest::~TextureShadowLodTest(void)
935 {
936 }
937
938 enum CaseFlags
939 {
940 VERTEX = (1 << 0),
941 FRAGMENT = (1 << 1),
942 BOTH = VERTEX | FRAGMENT
943 };
944
945 struct TexFuncCaseSpec
946 {
947 const char* name;
948 TextureLookupSpec lookupSpec;
949 TextureSpec texSpec;
950 TexEvalFunc evalFunc;
951 deUint32 flags;
952 };
953
954 #define CASE_SPEC(NAME, FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, USEOFFSET, OFFSET, USESEPREF, MINSEPREF, \
955 MAXSEPREF, TEXSPEC, EVALFUNC, FLAGS) \
956 { \
957 #NAME, TextureLookupSpec(FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, USEOFFSET, OFFSET, USESEPREF, \
958 MINSEPREF, MAXSEPREF), \
959 TEXSPEC, EVALFUNC, FLAGS \
960 }
961
createCaseGroup(TestCaseGroup * parent,const char * groupName,const char * groupDesc,const TexFuncCaseSpec * cases,int numCases)962 static void createCaseGroup(TestCaseGroup* parent, const char* groupName, const char* groupDesc,
963 const TexFuncCaseSpec* cases, int numCases)
964 {
965 tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), groupName, groupDesc);
966 parent->addChild(group);
967
968 for (int ndx = 0; ndx < numCases; ndx++)
969 {
970 std::string name = cases[ndx].name;
971 if (cases[ndx].flags & VERTEX)
972 group->addChild(new TextureShadowLodTestCase(parent->getContext(), (name + "_vertex").c_str(), "",
973 cases[ndx].lookupSpec, cases[ndx].texSpec, cases[ndx].evalFunc,
974 true));
975 if (cases[ndx].flags & FRAGMENT)
976 group->addChild(new TextureShadowLodTestCase(parent->getContext(), (name + "_fragment").c_str(), "",
977 cases[ndx].lookupSpec, cases[ndx].texSpec, cases[ndx].evalFunc,
978 false));
979 }
980 }
981
init(void)982 void TextureShadowLodTest::init(void)
983 {
984 // Samplers
985 static const tcu::Sampler samplerShadowNoMipmap(
986 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::NEAREST,
987 tcu::Sampler::NEAREST, 0.0f /* LOD threshold */, true /* normalized coords */, tcu::Sampler::COMPAREMODE_LESS,
988 0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */);
989 static const tcu::Sampler samplerShadowMipmap(
990 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::NEAREST_MIPMAP_NEAREST,
991 tcu::Sampler::NEAREST, 0.0f /* LOD threshold */, true /* normalized coords */, tcu::Sampler::COMPAREMODE_LESS,
992 0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */);
993
994 // Default textures.
995 // Type Format W H D L Sampler
996
997 static const TextureSpec tex2DArrayShadow(TEXTURETYPE_2D_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 1,
998 samplerShadowNoMipmap);
999 static const TextureSpec texCubeShadow(TEXTURETYPE_CUBE_MAP, GL_DEPTH_COMPONENT16, 256, 256, 1, 1,
1000 samplerShadowNoMipmap);
1001 static const TextureSpec texCubeMipmapShadow(TEXTURETYPE_CUBE_MAP, GL_DEPTH_COMPONENT16, 256, 256, 1, 9,
1002 samplerShadowMipmap);
1003 static const TextureSpec texCubeArrayShadow(TEXTURETYPE_CUBE_MAP_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 1,
1004 samplerShadowNoMipmap);
1005 static const TextureSpec texCubeArrayMipmapShadow(TEXTURETYPE_CUBE_MAP_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 8,
1006 samplerShadowMipmap);
1007 static const TextureSpec tex2DArrayMipmapShadow(TEXTURETYPE_2D_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 8,
1008 samplerShadowMipmap);
1009
1010 // texture() cases
1011 static const TexFuncCaseSpec textureCases[] = {
1012 // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags
1013 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f),
1014 false, 0.0f, 0.0f, false, IVec3(0), false, 0.0f, 0.0f, tex2DArrayShadow, evalTexture2DArrayShadow,
1015 VERTEX),
1016 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f),
1017 false, 0.0f, 0.0f, false, IVec3(0), false, 0.0f, 0.0f, tex2DArrayMipmapShadow,
1018 evalTexture2DArrayShadow, FRAGMENT),
1019 CASE_SPEC(sampler2darrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f),
1020 Vec4(1.5f, 2.3f, 3.5f, 1.0f), true, -2.0f, 2.0f, false, IVec3(0), false, 0.0f, 0.0f,
1021 tex2DArrayMipmapShadow, evalTexture2DArrayShadowBias, FRAGMENT),
1022
1023 CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f),
1024 Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, 0.0f, 0.0f, false, IVec3(0), true, 0.0f, 1.0f,
1025 texCubeArrayShadow, evalTextureCubeArrayShadow, VERTEX),
1026 CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f),
1027 Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, 0.0f, 0.0f, false, IVec3(0), true, 0.0f, 1.0f,
1028 texCubeArrayMipmapShadow, evalTextureCubeArrayShadow, FRAGMENT),
1029 CASE_SPEC(samplercubearrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f),
1030 Vec4(1.0f, 1.0f, 1.01f, 3.5f), true, -2.0, 2.0f, false, IVec3(0), true, 0.0f, 1.0f,
1031 texCubeArrayMipmapShadow, evalTextureCubeArrayShadowBias, FRAGMENT),
1032 };
1033 createCaseGroup(this, "texture", "texture() Tests", textureCases, DE_LENGTH_OF_ARRAY(textureCases));
1034
1035 // textureOffset() cases
1036 // \note _bias variants are not using mipmap thanks to wide allowed range for LOD computation
1037 static const TexFuncCaseSpec textureOffsetCases[] = {
1038 // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags
1039 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f),
1040 false, 0.0f, 0.0f, true, IVec3(-8, 7, 0), false, 0.0f, 0.0f, tex2DArrayShadow,
1041 evalTexture2DArrayShadowOffset, VERTEX),
1042 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f),
1043 false, 0.0f, 0.0f, true, IVec3(7, -8, 0), false, 0.0f, 0.0f, tex2DArrayMipmapShadow,
1044 evalTexture2DArrayShadowOffset, FRAGMENT),
1045 CASE_SPEC(sampler2darrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f),
1046 Vec4(1.5f, 2.3f, 3.5f, 1.0f), true, -2.0f, 2.0f, true, IVec3(7, -8, 0), false, 0.0f, 0.0f,
1047 tex2DArrayMipmapShadow, evalTexture2DArrayShadowOffsetBias, FRAGMENT),
1048 };
1049 createCaseGroup(this, "textureoffset", "textureOffset() Tests", textureOffsetCases,
1050 DE_LENGTH_OF_ARRAY(textureOffsetCases));
1051
1052 // textureLod() cases
1053 static const TexFuncCaseSpec textureLodCases[] = {
1054 // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags
1055 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.2f, -0.4f, -0.5f, 0.0f),
1056 Vec4(1.5f, 2.3f, 3.5f, 1.0f), false, -1.0f, 8.0f, false, IVec3(0), false, 0.0f, 0.0f,
1057 tex2DArrayMipmapShadow, evalTexture2DArrayShadowLod, BOTH),
1058 CASE_SPEC(samplercubeshadow, FUNCTION_TEXTURELOD, Vec4(-1.0f, -1.0f, 1.01f, 0.0f),
1059 Vec4(1.0f, 1.0f, 1.01f, 1.0f), false, -1.0f, 8.0f, false, IVec3(0), false, 0.0f, 0.0f,
1060 texCubeMipmapShadow, evalTextureCubeShadowLod, BOTH),
1061 CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.0f, -1.0f, 1.01f, -0.5f),
1062 Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, -1.0f, 8.0f, false, IVec3(0), true, 0.0f, 1.0f,
1063 texCubeArrayMipmapShadow, evalTextureCubeArrayShadowLod, FRAGMENT)
1064 };
1065 createCaseGroup(this, "texturelod", "textureLod() Tests", textureLodCases, DE_LENGTH_OF_ARRAY(textureLodCases));
1066
1067 // textureLodOffset() cases
1068 static const TexFuncCaseSpec textureLodOffsetCases[] = {
1069 // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags
1070 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.2f, -0.4f, -0.5f, 0.0f),
1071 Vec4(1.5f, 2.3f, 3.5f, 1.0f), false, -1.0f, 9.0f, true, IVec3(-8, 7, 0), false, 0.0f, 0.0f,
1072 tex2DArrayMipmapShadow, evalTexture2DArrayShadowLodOffset, BOTH),
1073 };
1074 createCaseGroup(this, "texturelodoffset", "textureLodOffset() Tests", textureLodOffsetCases,
1075 DE_LENGTH_OF_ARRAY(textureLodOffsetCases));
1076 }
1077 } // namespace Functional
1078 } // namespace deqp
1079