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::__anon58642bf20111::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::__anon58642bf20111::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 uint32_t format; //!< Internal format.
152 int width;
153 int height;
154 int depth;
155 int numLevels;
156 tcu::Sampler sampler;
157
TextureSpecdeqp::Functional::__anon58642bf20111::TextureSpec158 TextureSpec(void) : type(TEXTURETYPE_LAST), format(GL_NONE), width(0), height(0), depth(0), numLevels(0)
159 {
160 }
161
TextureSpecdeqp::Functional::__anon58642bf20111::TextureSpec162 TextureSpec(TextureType type_, uint32_t 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::__anon58642bf20111::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)
293 , m_lookupParams(lookupParams)
294 {
295 }
296
evaluate(ShaderEvalContext & ctx)297 virtual void evaluate(ShaderEvalContext &ctx)
298 {
299 m_evalFunc(ctx, m_lookupParams);
300 }
301
302 private:
303 TexEvalFunc m_evalFunc;
304 const TexLookupParams &m_lookupParams;
305 };
306
307 class TextureShadowLodTestCase : public ShaderRenderCase
308 {
309 public:
310 TextureShadowLodTestCase(Context &context, const char *name, const char *desc, const TextureLookupSpec &lookup,
311 const TextureSpec &texture, TexEvalFunc evalFunc, bool isVertexCase);
312 ~TextureShadowLodTestCase(void);
313
314 void init(void);
315 void deinit(void);
316
317 protected:
318 void setupUniforms(uint32_t programID, const tcu::Vec4 &constCoords);
319
320 private:
321 void initTexture(void);
322 void initShaderSources(void);
323
324 TextureLookupSpec m_lookupSpec;
325 TextureSpec m_textureSpec;
326
327 TexLookupParams m_lookupParams;
328 TexLookupEvaluator m_evaluator;
329
330 glu::Texture2D *m_texture2D;
331 glu::TextureCube *m_textureCube;
332 glu::TextureCubeArray *m_textureCubeArray;
333 glu::Texture2DArray *m_texture2DArray;
334 };
335
TextureShadowLodTestCase(Context & context,const char * name,const char * desc,const TextureLookupSpec & lookup,const TextureSpec & texture,TexEvalFunc evalFunc,bool isVertexCase)336 TextureShadowLodTestCase::TextureShadowLodTestCase(Context &context, const char *name, const char *desc,
337 const TextureLookupSpec &lookup, const TextureSpec &texture,
338 TexEvalFunc evalFunc, bool isVertexCase)
339 : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc,
340 isVertexCase, m_evaluator)
341 , m_lookupSpec(lookup)
342 , m_textureSpec(texture)
343 , m_evaluator(evalFunc, m_lookupParams)
344 , m_texture2D(DE_NULL)
345 , m_textureCube(DE_NULL)
346 , m_textureCubeArray(DE_NULL)
347 , m_texture2DArray(DE_NULL)
348 {
349 }
350
~TextureShadowLodTestCase(void)351 TextureShadowLodTestCase::~TextureShadowLodTestCase(void)
352 {
353 delete m_texture2D;
354 delete m_textureCube;
355 delete m_textureCubeArray;
356 delete m_texture2DArray;
357 }
358
init(void)359 void TextureShadowLodTestCase::init(void)
360 {
361 // Check extension and other features are supported with this context/platform.
362 {
363 glu::ContextInfo *info = glu::ContextInfo::create(m_renderCtx);
364
365 // First check if extension is available.
366 if (!info->isExtensionSupported("GL_EXT_texture_shadow_lod"))
367 {
368 throw tcu::NotSupportedError("EXT_texture_shadow_lod is not supported on the platform");
369 }
370
371 // Check that API support and that the various texture_cube_map_array extension is supported based on GL / ES versions.
372
373 if (glu::isContextTypeES(m_renderCtx.getType()))
374 {
375 // ES
376 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 0)))
377 {
378 throw tcu::NotSupportedError(
379 "EXT_texture_shadow_lod is not supported due to minimum ES version requirements");
380 }
381
382 // Check if cube map array is supported. For ES, it is supported
383 // as of ES 3.2, or with OES_texture_cube_map_array for
384 // 3.1.
385 if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY)
386 {
387 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 2)) &&
388 !(glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 1)) &&
389 (info->isExtensionSupported("GL_OES_texture_cube_map_array") ||
390 info->isExtensionSupported("GL_EXT_texture_cube_map_array"))))
391 {
392 throw tcu::NotSupportedError("GL_OES_texture_cube_map_array or GL_EXT_texture_cube_map_array is "
393 "required for this configuration and is not available.");
394 }
395 }
396 }
397 else
398 {
399 // GL
400 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(2, 0)))
401 {
402 throw tcu::NotSupportedError(
403 "EXT_texture_shadow_lod is not supported due to minimum GL version requirements");
404 }
405
406 // Check if cube map array is supported. For GL, it is supported
407 // as of GL 4.0 core, or with ARB_texture_cube_map_array prior.
408 if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY)
409 {
410 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 0)) &&
411 !info->isExtensionSupported("GL_ARB_texture_cube_map_array"))
412 {
413 throw tcu::NotSupportedError(
414 "ARB_texture_cube_map_array is required for this configuration and is not available.");
415 }
416 }
417 }
418 }
419
420 // Set up the user attributes.
421 // The user attributes are set up as matrices where each row represents a component
422 // in the attribute transformed against the vertex's interpolated position across the grid.
423 {
424 // Base coord scale & bias
425 Vec4 s = m_lookupSpec.maxCoord - m_lookupSpec.minCoord;
426 Vec4 b = m_lookupSpec.minCoord;
427
428 float baseCoordTrans[] = {s.x(), 0.0f, 0.f, b.x(),
429 0.f, s.y(), 0.f, b.y(),
430 s.z() / 2.f, -s.z() / 2.f, 0.f, s.z() / 2.f + b.z(),
431 -s.w() / 2.f, s.w() / 2.f, 0.f, s.w() / 2.f + b.w()};
432
433 //a_in0
434 m_userAttribTransforms.push_back(tcu::Mat4(baseCoordTrans));
435 }
436
437 bool hasLodBias = functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias;
438
439 if (hasLodBias || m_lookupSpec.useSepRef)
440 {
441 float s = 0.0f;
442 float b = 0.0f;
443 float sepRefS = 0.0f;
444 float sepRefB = 0.0f;
445
446 if (hasLodBias)
447 {
448 s = m_lookupSpec.maxLodBias - m_lookupSpec.minLodBias;
449 b = m_lookupSpec.minLodBias;
450 }
451
452 if (m_lookupSpec.useSepRef)
453 {
454 sepRefS = m_lookupSpec.maxSepRef - m_lookupSpec.minSepRef;
455 sepRefB = m_lookupSpec.minSepRef;
456 }
457 float lodCoordTrans[] = {s / 2.0f, s / 2.0f, 0.f, b, sepRefS / 2.0f, sepRefS / 2.0f, 0.0f, sepRefB,
458 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
459
460 //a_in1
461 m_userAttribTransforms.push_back(tcu::Mat4(lodCoordTrans));
462 }
463
464 initShaderSources();
465 initTexture();
466
467 ShaderRenderCase::init();
468 }
469
initTexture(void)470 void TextureShadowLodTestCase::initTexture(void)
471 {
472 static const IVec4 texCubeSwz[] = {IVec4(0, 0, 1, 1), IVec4(1, 1, 0, 0), IVec4(0, 1, 0, 1),
473 IVec4(1, 0, 1, 0), IVec4(0, 1, 1, 0), IVec4(1, 0, 0, 1)};
474 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(texCubeSwz) == tcu::CUBEFACE_LAST);
475
476 tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_textureSpec.format);
477 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
478 tcu::IVec2 viewportSize = getViewportSize();
479 bool isAutoLod = functionHasAutoLod(m_isVertexCase ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT,
480 m_lookupSpec.function); // LOD can vary significantly
481
482 switch (m_textureSpec.type)
483 {
484 case TEXTURETYPE_2D:
485 {
486 float levelStep = isAutoLod ? 0.0f : 1.0f / (float)de::max(1, m_textureSpec.numLevels - 1);
487 Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
488 Vec4 cBias = fmtInfo.valueMin;
489 int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
490
491 m_texture2D = new glu::Texture2D(m_renderCtx, m_textureSpec.format, m_textureSpec.width, m_textureSpec.height);
492 for (int level = 0; level < m_textureSpec.numLevels; level++)
493 {
494 float fA = float(level) * levelStep;
495 float fB = 1.0f - fA;
496 Vec4 colorA = cBias + cScale * Vec4(fA, fB, fA, fB);
497 Vec4 colorB = cBias + cScale * Vec4(fB, fA, fB, fA);
498
499 m_texture2D->getRefTexture().allocLevel(level);
500 tcu::fillWithGrid(m_texture2D->getRefTexture().getLevel(level), de::max(1, baseCellSize >> level), colorA,
501 colorB);
502 }
503 m_texture2D->upload();
504
505 // Compute LOD.
506 float dudx =
507 (m_lookupSpec.maxCoord[0] - m_lookupSpec.minCoord[0]) * (float)m_textureSpec.width / (float)viewportSize[0];
508 float dvdy = (m_lookupSpec.maxCoord[1] - m_lookupSpec.minCoord[1]) * (float)m_textureSpec.height /
509 (float)viewportSize[1];
510 m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy);
511
512 // Append to texture list.
513 m_textures.push_back(TextureBinding(m_texture2D, m_textureSpec.sampler));
514 break;
515 }
516
517 case TEXTURETYPE_2D_ARRAY:
518 {
519 float layerStep = 1.0f / (float)m_textureSpec.depth;
520 float levelStep =
521 isAutoLod ? 0.0f : 1.0f / (float)(de::max(1, m_textureSpec.numLevels - 1) * m_textureSpec.depth);
522 Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
523 Vec4 cBias = fmtInfo.valueMin;
524 int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
525
526 m_texture2DArray = new glu::Texture2DArray(m_renderCtx, m_textureSpec.format, m_textureSpec.width,
527 m_textureSpec.height, m_textureSpec.depth);
528 for (int level = 0; level < m_textureSpec.numLevels; level++)
529 {
530 m_texture2DArray->getRefTexture().allocLevel(level);
531 tcu::PixelBufferAccess levelAccess = m_texture2DArray->getRefTexture().getLevel(level);
532
533 for (int layer = 0; layer < levelAccess.getDepth(); layer++)
534 {
535 float fA = (float)layer * layerStep + (float)level * levelStep;
536 float fB = 1.0f - fA;
537 Vec4 colorA = cBias + cScale * Vec4(fA, fB, fA, fB);
538 Vec4 colorB = cBias + cScale * Vec4(fB, fA, fB, fA);
539
540 tcu::fillWithGrid(
541 tcu::getSubregion(levelAccess, 0, 0, layer, levelAccess.getWidth(), levelAccess.getHeight(), 1),
542 de::max(1, baseCellSize >> level), colorA, colorB);
543 }
544 }
545 m_texture2DArray->upload();
546
547 // Compute LOD.
548 float dudx =
549 (m_lookupSpec.maxCoord[0] - m_lookupSpec.minCoord[0]) * (float)m_textureSpec.width / (float)viewportSize[0];
550 float dvdy = (m_lookupSpec.maxCoord[1] - m_lookupSpec.minCoord[1]) * (float)m_textureSpec.height /
551 (float)viewportSize[1];
552 m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy);
553
554 // Append to texture list.
555 m_textures.push_back(TextureBinding(m_texture2DArray, m_textureSpec.sampler));
556 break;
557 }
558
559 case TEXTURETYPE_CUBE_MAP:
560 {
561 float levelStep = isAutoLod ? 0.0f : 1.0f / (float)de::max(1, m_textureSpec.numLevels - 1);
562 Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
563 Vec4 cBias = fmtInfo.valueMin;
564 Vec4 cCorner = cBias + cScale * 0.5f;
565 int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
566
567 DE_ASSERT(m_textureSpec.width == m_textureSpec.height);
568 m_textureCube = new glu::TextureCube(m_renderCtx, m_textureSpec.format, m_textureSpec.width);
569 for (int level = 0; level < m_textureSpec.numLevels; level++)
570 {
571 float fA = float(level) * levelStep;
572 float fB = 1.0f - fA;
573 Vec2 f(fA, fB);
574
575 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
576 {
577 const IVec4 &swzA = texCubeSwz[face];
578 IVec4 swzB = 1 - swzA;
579 Vec4 colorA = cBias + cScale * f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]);
580 Vec4 colorB = cBias + cScale * f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]);
581
582 m_textureCube->getRefTexture().allocLevel((tcu::CubeFace)face, level);
583 {
584 const tcu::PixelBufferAccess access =
585 m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face);
586 const int lastPix = access.getWidth() - 1;
587
588 tcu::fillWithGrid(access, de::max(1, baseCellSize >> level), colorA, colorB);
589
590 // Ensure all corners have identical colors in order to avoid dealing with ambiguous corner texel filtering
591 access.setPixel(cCorner, 0, 0);
592 access.setPixel(cCorner, 0, lastPix);
593 access.setPixel(cCorner, lastPix, 0);
594 access.setPixel(cCorner, lastPix, lastPix);
595 }
596 }
597 }
598 m_textureCube->upload();
599
600 // Compute LOD \note Assumes that only single side is accessed and R is constant major axis.
601 DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005);
602 DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) &&
603 de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2]));
604 DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) &&
605 de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2]));
606
607 tcu::CubeFaceFloatCoords c00 =
608 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2]));
609 tcu::CubeFaceFloatCoords c10 =
610 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.maxCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2]));
611 tcu::CubeFaceFloatCoords c01 =
612 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.maxCoord[1], m_lookupSpec.minCoord[2]));
613 float dudx = (c10.s - c00.s) * (float)m_textureSpec.width / (float)viewportSize[0];
614 float dvdy = (c01.t - c00.t) * (float)m_textureSpec.height / (float)viewportSize[1];
615
616 m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy);
617
618 m_textures.push_back(TextureBinding(m_textureCube, m_textureSpec.sampler));
619 break;
620 }
621
622 case TEXTURETYPE_CUBE_MAP_ARRAY:
623 {
624 float layerStep = 1.0f / (float)m_textureSpec.depth;
625 float levelStep =
626 isAutoLod ? 0.0f : 1.0f / (float)(de::max(1, m_textureSpec.numLevels - 1) * m_textureSpec.depth);
627 Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
628 Vec4 cBias = fmtInfo.valueMin;
629 Vec4 cCorner = cBias + cScale * 0.5f;
630 int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4);
631
632 DE_ASSERT(m_textureSpec.width == m_textureSpec.height);
633 // I think size here means width/height of cube tex
634 m_textureCubeArray =
635 new glu::TextureCubeArray(m_renderCtx, m_textureSpec.format, m_textureSpec.width, m_textureSpec.depth * 6);
636 // mipmap level
637 for (int level = 0; level < m_textureSpec.numLevels; level++)
638 {
639 m_textureCubeArray->getRefTexture().allocLevel(level);
640 tcu::PixelBufferAccess levelAccess = m_textureCubeArray->getRefTexture().getLevel(level);
641
642 //array layer
643 DE_ASSERT((levelAccess.getDepth() % 6) == 0);
644
645 for (int layer = 0; layer < levelAccess.getDepth() / 6; ++layer)
646 {
647 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
648 {
649 float fA = (float)layer * layerStep + float(level) * levelStep;
650 float fB = 1.0f - fA;
651 Vec2 f(fA, fB);
652
653 const IVec4 &swzA = texCubeSwz[face];
654 IVec4 swzB = 1 - swzA;
655 Vec4 colorA = cBias + cScale * f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]);
656 Vec4 colorB = cBias + cScale * f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]);
657
658 {
659 const tcu::PixelBufferAccess access = m_textureCubeArray->getRefTexture().getLevel(level);
660 const int lastPix = access.getWidth() - 1;
661
662 int layerFaceNdx = face + layer * 6;
663
664 DE_ASSERT(levelAccess.getWidth() == levelAccess.getHeight());
665 tcu::fillWithGrid(tcu::getSubregion(access, 0, 0, layerFaceNdx, levelAccess.getWidth(),
666 levelAccess.getHeight(), 1),
667 de::max(1, baseCellSize >> level), colorA, colorB);
668
669 // Ensure all corners have identical colors in order to avoid dealing with ambiguous corner texel filtering
670 access.setPixel(cCorner, 0, 0, layer);
671 access.setPixel(cCorner, 0, lastPix, layer);
672 access.setPixel(cCorner, lastPix, 0, layer);
673 access.setPixel(cCorner, lastPix, lastPix, layer);
674 }
675 }
676 }
677 }
678 m_textureCubeArray->upload();
679
680 // Compute LOD \note Assumes that only single side is accessed and R is constant major axis.
681 DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005);
682 DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) &&
683 de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2]));
684 DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) &&
685 de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2]));
686
687 tcu::CubeFaceFloatCoords c00 =
688 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2]));
689 tcu::CubeFaceFloatCoords c10 =
690 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.maxCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2]));
691 tcu::CubeFaceFloatCoords c01 =
692 tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.maxCoord[1], m_lookupSpec.minCoord[2]));
693 float dudx = (c10.s - c00.s) * (float)m_textureSpec.width / (float)viewportSize[0];
694 float dvdy = (c01.t - c00.t) * (float)m_textureSpec.height / (float)viewportSize[1];
695
696 m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy);
697
698 m_textures.push_back(TextureBinding(m_textureCubeArray, m_textureSpec.sampler));
699 break;
700 }
701
702 default:
703 DE_ASSERT(false);
704 }
705
706 // Set lookup scale & bias
707 m_lookupParams.scale = fmtInfo.lookupScale;
708 m_lookupParams.bias = fmtInfo.lookupBias;
709 m_lookupParams.offset = m_lookupSpec.offset;
710 }
711
initShaderSources(void)712 void TextureShadowLodTestCase::initShaderSources(void)
713 {
714 Function function = m_lookupSpec.function;
715 bool isVtxCase = m_isVertexCase;
716 bool hasLodBias = functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias;
717 int texCoordComps = m_textureSpec.type == TEXTURETYPE_2D ? 2 : 3;
718 int extraCoordComps = 1; // For shadow ref
719 bool hasSepShadowRef = m_lookupSpec.useSepRef;
720 glu::DataType coordType = glu::getDataTypeFloatVec(texCoordComps + extraCoordComps);
721 glu::Precision coordPrec = glu::PRECISION_HIGHP;
722 const char *coordTypeName = glu::getDataTypeName(coordType);
723 const char *coordPrecName = glu::getPrecisionName(coordPrec);
724 glu::DataType samplerType = glu::TYPE_LAST;
725 const char *baseFuncName = DE_NULL;
726
727 switch (m_textureSpec.type)
728 {
729 case TEXTURETYPE_2D:
730 samplerType = glu::TYPE_SAMPLER_2D_SHADOW;
731 break;
732 case TEXTURETYPE_CUBE_MAP:
733 samplerType = glu::TYPE_SAMPLER_CUBE_SHADOW;
734 break;
735 case TEXTURETYPE_CUBE_MAP_ARRAY:
736 samplerType = glu::TYPE_SAMPLER_CUBE_ARRAY_SHADOW;
737 break;
738 case TEXTURETYPE_2D_ARRAY:
739 samplerType = glu::TYPE_SAMPLER_2D_ARRAY_SHADOW;
740 break;
741 default:
742 DE_ASSERT(false);
743 }
744
745 switch (m_lookupSpec.function)
746 {
747 case FUNCTION_TEXTURE:
748 baseFuncName = "texture";
749 break;
750 case FUNCTION_TEXTURELOD:
751 baseFuncName = "textureLod";
752 break;
753 default:
754 DE_ASSERT(false);
755 }
756
757 bool isGL = glu::isContextTypeGLCore(m_renderCtx.getType());
758 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_renderCtx.getType());
759
760 std::string shaderVersion = glu::getGLSLVersionDeclaration(glslVersion);
761
762 std::ostringstream vert;
763 std::ostringstream frag;
764 std::ostringstream &op = isVtxCase ? vert : frag;
765
766 std::string cubeMapArrayEXT = "";
767
768 // Check if we need to add the texture_cube_map_array extension.
769 if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY)
770 {
771 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 2)) &&
772 !glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 0)))
773 {
774 if (isGL)
775 {
776 cubeMapArrayEXT = "#extension GL_ARB_texture_cube_map_array : require\n";
777 }
778 else
779 {
780 glu::ContextInfo *info = glu::ContextInfo::create(m_renderCtx);
781 if (info->isExtensionSupported("GL_EXT_texture_cube_map_array"))
782 {
783 cubeMapArrayEXT = "#extension GL_EXT_texture_cube_map_array : require\n";
784 }
785 else
786 {
787 cubeMapArrayEXT = "#extension GL_OES_texture_cube_map_array : require\n";
788 }
789 }
790 }
791 }
792
793 vert << shaderVersion << "\n"
794 << "#extension GL_EXT_texture_shadow_lod : require\n\n";
795
796 vert << cubeMapArrayEXT;
797
798 vert << "in highp vec4 a_position;\n"
799 << "in " << coordPrecName << " " << coordTypeName << " a_in0;\n";
800
801 if (hasLodBias || hasSepShadowRef)
802 {
803 vert << "in " << coordPrecName << " vec4 a_in1;\n";
804 }
805
806 frag << shaderVersion << "\n"
807 << "#extension GL_EXT_texture_shadow_lod : require\n\n";
808
809 frag << cubeMapArrayEXT;
810
811 frag << "out mediump vec4 o_color;\n";
812
813 if (isVtxCase)
814 {
815 vert << "out mediump vec4 v_color;\n";
816 frag << "in mediump vec4 v_color;\n";
817 }
818 else
819 {
820 vert << "out " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
821 frag << "in " << coordPrecName << " " << coordTypeName << " v_texCoord;\n";
822
823 if (hasLodBias || hasSepShadowRef)
824 {
825 vert << "out " << coordPrecName << " vec4 v_lodShadowRef;\n";
826 frag << "in " << coordPrecName << " vec4 v_lodShadowRef;\n";
827 }
828 }
829
830 // Uniforms
831 op << "uniform highp " << glu::getDataTypeName(samplerType) << " u_sampler;\n"
832 << "uniform highp vec4 u_scale;\n"
833 << "uniform highp vec4 u_bias;\n";
834
835 vert << "\nvoid main()\n{\n"
836 << "\tgl_Position = a_position;\n";
837 frag << "\nvoid main()\n{\n";
838
839 if (isVtxCase)
840 vert << "\tv_color = ";
841 else
842 frag << "\to_color = ";
843
844 // Op.
845 {
846 const char *texCoord = isVtxCase ? "a_in0" : "v_texCoord";
847 const char *lodBias = isVtxCase ? "a_in1" : "v_lodShadowRef";
848
849 op << "vec4(" << baseFuncName;
850 if (m_lookupSpec.useOffset)
851 op << "Offset";
852 op << "(u_sampler, ";
853
854 op << texCoord;
855
856 if (m_lookupSpec.useSepRef)
857 {
858 op << ", " << lodBias << ".y";
859 }
860
861 if (functionHasLod(function))
862 {
863 op << ", " << lodBias << ".x";
864 }
865
866 if (m_lookupSpec.useOffset)
867 {
868 int offsetComps = 2;
869
870 op << ", ivec" << offsetComps << "(";
871 for (int ndx = 0; ndx < offsetComps; ndx++)
872 {
873 if (ndx != 0)
874 op << ", ";
875 op << m_lookupSpec.offset[ndx];
876 }
877 op << ")";
878 }
879
880 if (m_lookupSpec.useBias)
881 op << ", " << lodBias << ".x";
882
883 op << ")";
884
885 op << ", 0.0, 0.0, 1.0)";
886
887 op << ";\n";
888 }
889
890 if (isVtxCase)
891 frag << "\to_color = v_color;\n";
892 else
893 {
894 vert << "\tv_texCoord = a_in0;\n";
895
896 if (hasLodBias || hasSepShadowRef)
897 {
898 vert << "\tv_lodShadowRef = a_in1;\n";
899 }
900 }
901
902 vert << "}\n";
903 frag << "}\n";
904
905 m_vertShaderSource = vert.str();
906 m_fragShaderSource = frag.str();
907 }
908
deinit(void)909 void TextureShadowLodTestCase::deinit(void)
910 {
911 ShaderRenderCase::deinit();
912
913 delete m_texture2D;
914 delete m_textureCube;
915 delete m_texture2DArray;
916
917 m_texture2D = DE_NULL;
918 m_textureCube = DE_NULL;
919 m_texture2DArray = DE_NULL;
920 }
921
setupUniforms(uint32_t programID,const tcu::Vec4 &)922 void TextureShadowLodTestCase::setupUniforms(uint32_t programID, const tcu::Vec4 &)
923 {
924 const glw::Functions &gl = m_renderCtx.getFunctions();
925 gl.uniform1i(gl.getUniformLocation(programID, "u_sampler"), 0);
926 gl.uniform4fv(gl.getUniformLocation(programID, "u_scale"), 1, m_lookupParams.scale.getPtr());
927 gl.uniform4fv(gl.getUniformLocation(programID, "u_bias"), 1, m_lookupParams.bias.getPtr());
928 }
929
TextureShadowLodTest(Context & context)930 TextureShadowLodTest::TextureShadowLodTest(Context &context)
931 : TestCaseGroup(context, "ext_texture_shadow_lod", "Texture Access Function Tests")
932 {
933 }
934
~TextureShadowLodTest(void)935 TextureShadowLodTest::~TextureShadowLodTest(void)
936 {
937 }
938
939 enum CaseFlags
940 {
941 VERTEX = (1 << 0),
942 FRAGMENT = (1 << 1),
943 BOTH = VERTEX | FRAGMENT
944 };
945
946 struct TexFuncCaseSpec
947 {
948 const char *name;
949 TextureLookupSpec lookupSpec;
950 TextureSpec texSpec;
951 TexEvalFunc evalFunc;
952 uint32_t flags;
953 };
954
955 #define CASE_SPEC(NAME, FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, USEOFFSET, OFFSET, USESEPREF, MINSEPREF, \
956 MAXSEPREF, TEXSPEC, EVALFUNC, FLAGS) \
957 { \
958 #NAME, \
959 TextureLookupSpec(FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, USEOFFSET, OFFSET, USESEPREF, \
960 MINSEPREF, MAXSEPREF), \
961 TEXSPEC, EVALFUNC, FLAGS \
962 }
963
createCaseGroup(TestCaseGroup * parent,const char * groupName,const char * groupDesc,const TexFuncCaseSpec * cases,int numCases)964 static void createCaseGroup(TestCaseGroup *parent, const char *groupName, const char *groupDesc,
965 const TexFuncCaseSpec *cases, int numCases)
966 {
967 tcu::TestCaseGroup *group = new tcu::TestCaseGroup(parent->getTestContext(), groupName, groupDesc);
968 parent->addChild(group);
969
970 for (int ndx = 0; ndx < numCases; ndx++)
971 {
972 std::string name = cases[ndx].name;
973 if (cases[ndx].flags & VERTEX)
974 group->addChild(new TextureShadowLodTestCase(parent->getContext(), (name + "_vertex").c_str(), "",
975 cases[ndx].lookupSpec, cases[ndx].texSpec, cases[ndx].evalFunc,
976 true));
977 if (cases[ndx].flags & FRAGMENT)
978 group->addChild(new TextureShadowLodTestCase(parent->getContext(), (name + "_fragment").c_str(), "",
979 cases[ndx].lookupSpec, cases[ndx].texSpec, cases[ndx].evalFunc,
980 false));
981 }
982 }
983
init(void)984 void TextureShadowLodTest::init(void)
985 {
986 // Samplers
987 static const tcu::Sampler samplerShadowNoMipmap(
988 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::NEAREST,
989 tcu::Sampler::NEAREST, 0.0f /* LOD threshold */, true /* normalized coords */, tcu::Sampler::COMPAREMODE_LESS,
990 0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */);
991 static const tcu::Sampler samplerShadowMipmap(
992 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::NEAREST_MIPMAP_NEAREST,
993 tcu::Sampler::NEAREST, 0.0f /* LOD threshold */, true /* normalized coords */, tcu::Sampler::COMPAREMODE_LESS,
994 0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */);
995
996 // Default textures.
997 // Type Format W H D L Sampler
998
999 static const TextureSpec tex2DArrayShadow(TEXTURETYPE_2D_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 1,
1000 samplerShadowNoMipmap);
1001 static const TextureSpec texCubeShadow(TEXTURETYPE_CUBE_MAP, GL_DEPTH_COMPONENT16, 256, 256, 1, 1,
1002 samplerShadowNoMipmap);
1003 static const TextureSpec texCubeMipmapShadow(TEXTURETYPE_CUBE_MAP, GL_DEPTH_COMPONENT16, 256, 256, 1, 9,
1004 samplerShadowMipmap);
1005 static const TextureSpec texCubeArrayShadow(TEXTURETYPE_CUBE_MAP_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 1,
1006 samplerShadowNoMipmap);
1007 static const TextureSpec texCubeArrayMipmapShadow(TEXTURETYPE_CUBE_MAP_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 8,
1008 samplerShadowMipmap);
1009 static const TextureSpec tex2DArrayMipmapShadow(TEXTURETYPE_2D_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 8,
1010 samplerShadowMipmap);
1011
1012 // texture() cases
1013 static const TexFuncCaseSpec textureCases[] = {
1014 // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags
1015 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f),
1016 false, 0.0f, 0.0f, false, IVec3(0), false, 0.0f, 0.0f, tex2DArrayShadow, evalTexture2DArrayShadow,
1017 VERTEX),
1018 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f),
1019 false, 0.0f, 0.0f, false, IVec3(0), false, 0.0f, 0.0f, tex2DArrayMipmapShadow,
1020 evalTexture2DArrayShadow, FRAGMENT),
1021 CASE_SPEC(sampler2darrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f),
1022 Vec4(1.5f, 2.3f, 3.5f, 1.0f), true, -2.0f, 2.0f, false, IVec3(0), false, 0.0f, 0.0f,
1023 tex2DArrayMipmapShadow, evalTexture2DArrayShadowBias, FRAGMENT),
1024
1025 CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f),
1026 Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, 0.0f, 0.0f, false, IVec3(0), true, 0.0f, 1.0f,
1027 texCubeArrayShadow, evalTextureCubeArrayShadow, VERTEX),
1028 CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f),
1029 Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, 0.0f, 0.0f, false, IVec3(0), true, 0.0f, 1.0f,
1030 texCubeArrayMipmapShadow, evalTextureCubeArrayShadow, FRAGMENT),
1031 CASE_SPEC(samplercubearrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f),
1032 Vec4(1.0f, 1.0f, 1.01f, 3.5f), true, -2.0, 2.0f, false, IVec3(0), true, 0.0f, 1.0f,
1033 texCubeArrayMipmapShadow, evalTextureCubeArrayShadowBias, FRAGMENT),
1034 };
1035 createCaseGroup(this, "texture", "texture() Tests", textureCases, DE_LENGTH_OF_ARRAY(textureCases));
1036
1037 // textureOffset() cases
1038 // \note _bias variants are not using mipmap thanks to wide allowed range for LOD computation
1039 static const TexFuncCaseSpec textureOffsetCases[] = {
1040 // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags
1041 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f),
1042 false, 0.0f, 0.0f, true, IVec3(-8, 7, 0), false, 0.0f, 0.0f, tex2DArrayShadow,
1043 evalTexture2DArrayShadowOffset, VERTEX),
1044 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f),
1045 false, 0.0f, 0.0f, true, IVec3(7, -8, 0), false, 0.0f, 0.0f, tex2DArrayMipmapShadow,
1046 evalTexture2DArrayShadowOffset, FRAGMENT),
1047 CASE_SPEC(sampler2darrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f),
1048 Vec4(1.5f, 2.3f, 3.5f, 1.0f), true, -2.0f, 2.0f, true, IVec3(7, -8, 0), false, 0.0f, 0.0f,
1049 tex2DArrayMipmapShadow, evalTexture2DArrayShadowOffsetBias, FRAGMENT),
1050 };
1051 createCaseGroup(this, "textureoffset", "textureOffset() Tests", textureOffsetCases,
1052 DE_LENGTH_OF_ARRAY(textureOffsetCases));
1053
1054 // textureLod() cases
1055 static const TexFuncCaseSpec textureLodCases[] = {
1056 // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags
1057 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.2f, -0.4f, -0.5f, 0.0f),
1058 Vec4(1.5f, 2.3f, 3.5f, 1.0f), false, -1.0f, 8.0f, false, IVec3(0), false, 0.0f, 0.0f,
1059 tex2DArrayMipmapShadow, evalTexture2DArrayShadowLod, BOTH),
1060 CASE_SPEC(samplercubeshadow, FUNCTION_TEXTURELOD, Vec4(-1.0f, -1.0f, 1.01f, 0.0f),
1061 Vec4(1.0f, 1.0f, 1.01f, 1.0f), false, -1.0f, 8.0f, false, IVec3(0), false, 0.0f, 0.0f,
1062 texCubeMipmapShadow, evalTextureCubeShadowLod, BOTH),
1063 CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.0f, -1.0f, 1.01f, -0.5f),
1064 Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, -1.0f, 8.0f, false, IVec3(0), true, 0.0f, 1.0f,
1065 texCubeArrayMipmapShadow, evalTextureCubeArrayShadowLod, FRAGMENT)};
1066 createCaseGroup(this, "texturelod", "textureLod() Tests", textureLodCases, DE_LENGTH_OF_ARRAY(textureLodCases));
1067
1068 // textureLodOffset() cases
1069 static const TexFuncCaseSpec textureLodOffsetCases[] = {
1070 // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags
1071 CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.2f, -0.4f, -0.5f, 0.0f),
1072 Vec4(1.5f, 2.3f, 3.5f, 1.0f), false, -1.0f, 9.0f, true, IVec3(-8, 7, 0), false, 0.0f, 0.0f,
1073 tex2DArrayMipmapShadow, evalTexture2DArrayShadowLodOffset, BOTH),
1074 };
1075 createCaseGroup(this, "texturelodoffset", "textureLodOffset() Tests", textureLodOffsetCases,
1076 DE_LENGTH_OF_ARRAY(textureLodOffsetCases));
1077 }
1078 } // namespace Functional
1079 } // namespace deqp
1080