| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2014-2019 The Khronos Group Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ /*! |
| * \file |
| * \brief |
| */ /*-------------------------------------------------------------------*/ |
| |
| /*! |
| * \file esextcTextureShadowLodFunctionsTest.cpp |
| * \brief EXT_texture_shadow_lod extension testing |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "esextcTextureShadowLodFunctionsTest.hpp" |
| #include "deMath.h" |
| #include "glcShaderLibrary.hpp" |
| #include "glcShaderRenderCase.hpp" |
| #include "glsTextureTestUtil.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluStrUtil.hpp" |
| #include "gluTexture.hpp" |
| #include "gluTextureUtil.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuMatrix.hpp" |
| #include "tcuMatrixUtil.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuTextureUtil.hpp" |
| |
| #include <sstream> |
| |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| |
| namespace deqp |
| { |
| namespace Functional |
| { |
| namespace |
| { |
| |
| using glu::TextureTestUtil::computeLodFromDerivates; |
| |
| enum Function |
| { |
| FUNCTION_TEXTURE = 0, //!< texture(), textureOffset() |
| FUNCTION_TEXTURELOD, // ... |
| FUNCTION_LAST |
| }; |
| |
| // For texture(..., [bias]) functions. |
| inline bool functionHasAutoLod(glu::ShaderType shaderType, Function function) |
| { |
| return (shaderType == glu::SHADERTYPE_FRAGMENT) && (function == FUNCTION_TEXTURE); |
| } |
| |
| // For textureLod* functions. |
| inline bool functionHasLod(Function function) |
| { |
| return function == FUNCTION_TEXTURELOD; |
| } |
| |
| struct TextureLookupSpec |
| { |
| // The texture function to use. |
| Function function; |
| |
| // Min/max texture coordinates. |
| tcu::Vec4 minCoord; |
| tcu::Vec4 maxCoord; |
| |
| // Bias |
| bool useBias; |
| |
| // Bias or Lod for *Lod* functions |
| float minLodBias; |
| float maxLodBias; |
| |
| // For *Offset variants |
| bool useOffset; |
| tcu::IVec3 offset; |
| |
| // Do we require an additional shadow ref "compare" |
| // parameter in the texture function's parameter list? (used for |
| // shadow cube array textures). |
| bool useSepRef; |
| float minSepRef; |
| float maxSepRef; |
| |
| TextureLookupSpec(void) |
| : function(FUNCTION_LAST) |
| , minCoord(0.0f) |
| , maxCoord(1.0f) |
| , useBias(false) |
| , minLodBias(0.0f) |
| , maxLodBias(0.0f) |
| , useOffset(false) |
| , offset(0) |
| , useSepRef(false) |
| , minSepRef(0.0f) |
| , maxSepRef(0.0f) |
| { |
| } |
| |
| TextureLookupSpec(Function function_, const tcu::Vec4& minCoord_, const tcu::Vec4& maxCoord_, bool useBias_, |
| float minLodBias_, float maxLodBias_, bool useOffset_, const tcu::IVec3& offset_, bool useSepRef_, |
| float minSepRef_, float maxSepRef_) |
| : function(function_) |
| , minCoord(minCoord_) |
| , maxCoord(maxCoord_) |
| , useBias(useBias_) |
| , minLodBias(minLodBias_) |
| , maxLodBias(maxLodBias_) |
| , useOffset(useOffset_) |
| , offset(offset_) |
| , useSepRef(useSepRef_) |
| , minSepRef(minSepRef_) |
| , maxSepRef(maxSepRef_) |
| { |
| } |
| }; |
| |
| // Only shadow texture types contained in EXT_texture_shadow_lod will be tested. |
| enum TextureType |
| { |
| TEXTURETYPE_2D, |
| TEXTURETYPE_CUBE_MAP, |
| TEXTURETYPE_CUBE_MAP_ARRAY, |
| TEXTURETYPE_2D_ARRAY, |
| |
| TEXTURETYPE_LAST |
| }; |
| |
| struct TextureSpec |
| { |
| TextureType type; //!< Texture type (2D, cubemap, ...) |
| deUint32 format; //!< Internal format. |
| int width; |
| int height; |
| int depth; |
| int numLevels; |
| tcu::Sampler sampler; |
| |
| TextureSpec(void) : type(TEXTURETYPE_LAST), format(GL_NONE), width(0), height(0), depth(0), numLevels(0) |
| { |
| } |
| |
| TextureSpec(TextureType type_, deUint32 format_, int width_, int height_, int depth_, int numLevels_, |
| const tcu::Sampler& sampler_) |
| : type(type_) |
| , format(format_) |
| , width(width_) |
| , height(height_) |
| , depth(depth_) |
| , numLevels(numLevels_) |
| , sampler(sampler_) |
| { |
| } |
| }; |
| |
| struct TexLookupParams |
| { |
| float lod; |
| tcu::IVec3 offset; |
| tcu::Vec4 scale; |
| tcu::Vec4 bias; |
| |
| TexLookupParams(void) : lod(0.0f), offset(0), scale(1.0f), bias(0.0f) |
| { |
| } |
| }; |
| |
| } // namespace |
| |
| using tcu::IVec2; |
| using tcu::IVec3; |
| using tcu::IVec4; |
| using tcu::Vec2; |
| using tcu::Vec3; |
| using tcu::Vec4; |
| |
| static const glu::TextureTestUtil::LodMode DEFAULT_LOD_MODE = glu::TextureTestUtil::LODMODE_EXACT; |
| |
| typedef void (*TexEvalFunc)(ShaderEvalContext& c, const TexLookupParams& lookupParams); |
| |
| inline float texture2DShadow(const ShaderEvalContext& c, float ref, float s, float t, float lod) |
| { |
| return c.textures[0].tex2D->sampleCompare(c.textures[0].sampler, ref, s, t, lod); |
| } |
| inline float texture2DArrayShadow(const ShaderEvalContext& c, float ref, float s, float t, float r, float lod) |
| { |
| return c.textures[0].tex2DArray->sampleCompare(c.textures[0].sampler, ref, s, t, r, lod); |
| } |
| inline float textureCubeShadow(const ShaderEvalContext& c, float ref, float s, float t, float r, float lod) |
| { |
| return c.textures[0].texCube->sampleCompare(c.textures[0].sampler, ref, s, t, r, lod); |
| } |
| inline float textureCubeArrayShadow(const ShaderEvalContext& c, float ref, float s, float t, float r, float q, |
| float lod) |
| { |
| return c.textures[0].texCubeArray->sampleCompare(c.textures[0].sampler, ref, s, t, r, q, lod); |
| } |
| inline float texture2DShadowOffset(const ShaderEvalContext& c, float ref, float s, float t, float lod, IVec2 offset) |
| { |
| return c.textures[0].tex2D->sampleCompareOffset(c.textures[0].sampler, ref, s, t, lod, offset); |
| } |
| inline float texture2DArrayShadowOffset(const ShaderEvalContext& c, float ref, float s, float t, float r, float lod, |
| IVec2 offset) |
| { |
| return c.textures[0].tex2DArray->sampleCompareOffset(c.textures[0].sampler, ref, s, t, r, lod, offset); |
| } |
| |
| // Shadow evaluation functions |
| static void evalTexture2DArrayShadow(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| c.color.x() = texture2DArrayShadow(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod); |
| } |
| static void evalTexture2DArrayShadowBias(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| 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()); |
| } |
| static void evalTexture2DArrayShadowOffset(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| c.color.x() = texture2DArrayShadowOffset(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod, |
| p.offset.swizzle(0, 1)); |
| } |
| static void evalTexture2DArrayShadowOffsetBias(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| 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(), |
| p.offset.swizzle(0, 1)); |
| } |
| |
| static void evalTexture2DArrayShadowLod(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| (void)p; |
| 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()); |
| } |
| static void evalTexture2DArrayShadowLodOffset(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| 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(), |
| p.offset.swizzle(0, 1)); |
| } |
| |
| static void evalTextureCubeShadow(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| c.color.x() = textureCubeShadow(c, c.in[0].w(), c.in[0].x(), c.in[0].y(), c.in[0].z(), p.lod); |
| } |
| static void evalTextureCubeShadowBias(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| 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()); |
| } |
| static void evalTextureCubeShadowLod(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| (void)p; |
| 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()); |
| } |
| |
| static void evalTextureCubeArrayShadow(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| 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); |
| } |
| static void evalTextureCubeArrayShadowBias(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| 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 + c.in[1].x()); |
| } |
| static void evalTextureCubeArrayShadowLod(ShaderEvalContext& c, const TexLookupParams& p) |
| { |
| (void)p; |
| 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(), c.in[1].x()); |
| } |
| |
| class TexLookupEvaluator : public ShaderEvaluator |
| { |
| public: |
| TexLookupEvaluator(TexEvalFunc evalFunc, const TexLookupParams& lookupParams) |
| : m_evalFunc(evalFunc), m_lookupParams(lookupParams) |
| { |
| } |
| |
| virtual void evaluate(ShaderEvalContext& ctx) |
| { |
| m_evalFunc(ctx, m_lookupParams); |
| } |
| |
| private: |
| TexEvalFunc m_evalFunc; |
| const TexLookupParams& m_lookupParams; |
| }; |
| |
| class TextureShadowLodTestCase : public ShaderRenderCase |
| { |
| public: |
| TextureShadowLodTestCase(Context& context, const char* name, const char* desc, const TextureLookupSpec& lookup, |
| const TextureSpec& texture, TexEvalFunc evalFunc, bool isVertexCase); |
| ~TextureShadowLodTestCase(void); |
| |
| void init(void); |
| void deinit(void); |
| |
| protected: |
| void setupUniforms(deUint32 programID, const tcu::Vec4& constCoords); |
| |
| private: |
| void initTexture(void); |
| void initShaderSources(void); |
| |
| TextureLookupSpec m_lookupSpec; |
| TextureSpec m_textureSpec; |
| |
| TexLookupParams m_lookupParams; |
| TexLookupEvaluator m_evaluator; |
| |
| glu::Texture2D* m_texture2D; |
| glu::TextureCube* m_textureCube; |
| glu::TextureCubeArray* m_textureCubeArray; |
| glu::Texture2DArray* m_texture2DArray; |
| }; |
| |
| TextureShadowLodTestCase::TextureShadowLodTestCase(Context& context, const char* name, const char* desc, |
| const TextureLookupSpec& lookup, const TextureSpec& texture, |
| TexEvalFunc evalFunc, bool isVertexCase) |
| : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, |
| isVertexCase, m_evaluator) |
| , m_lookupSpec(lookup) |
| , m_textureSpec(texture) |
| , m_evaluator(evalFunc, m_lookupParams) |
| , m_texture2D(DE_NULL) |
| , m_textureCube(DE_NULL) |
| , m_textureCubeArray(DE_NULL) |
| , m_texture2DArray(DE_NULL) |
| { |
| } |
| |
| TextureShadowLodTestCase::~TextureShadowLodTestCase(void) |
| { |
| delete m_texture2D; |
| delete m_textureCube; |
| delete m_textureCubeArray; |
| delete m_texture2DArray; |
| } |
| |
| void TextureShadowLodTestCase::init(void) |
| { |
| // Check extension and other features are supported with this context/platform. |
| { |
| glu::ContextInfo* info = glu::ContextInfo::create(m_renderCtx); |
| |
| // First check if extension is available. |
| if (!info->isExtensionSupported("GL_EXT_texture_shadow_lod")) |
| { |
| throw tcu::NotSupportedError("EXT_texture_shadow_lod is not supported on the platform"); |
| } |
| |
| // Check that API support and that the various texture_cube_map_array extension is supported based on GL / ES versions. |
| |
| if (glu::isContextTypeES(m_renderCtx.getType())) |
| { |
| // ES |
| if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 0))) |
| { |
| throw tcu::NotSupportedError( |
| "EXT_texture_shadow_lod is not supported due to minimum ES version requirements"); |
| } |
| |
| // Check if cube map array is supported. For ES, it is supported |
| // as of ES 3.2, or with OES_texture_cube_map_array for |
| // 3.1. |
| if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY) |
| { |
| if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 2)) && |
| !(glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 1)) && |
| (info->isExtensionSupported("GL_OES_texture_cube_map_array") || |
| info->isExtensionSupported("GL_EXT_texture_cube_map_array")))) |
| { |
| throw tcu::NotSupportedError("GL_OES_texture_cube_map_array or GL_EXT_texture_cube_map_array is " |
| "required for this configuration and is not available."); |
| } |
| } |
| } |
| else |
| { |
| // GL |
| if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(2, 0))) |
| { |
| throw tcu::NotSupportedError( |
| "EXT_texture_shadow_lod is not supported due to minimum GL version requirements"); |
| } |
| |
| // Check if cube map array is supported. For GL, it is supported |
| // as of GL 4.0 core, or with ARB_texture_cube_map_array prior. |
| if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY) |
| { |
| if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 0)) && |
| !info->isExtensionSupported("GL_ARB_texture_cube_map_array")) |
| { |
| throw tcu::NotSupportedError( |
| "ARB_texture_cube_map_array is required for this configuration and is not available."); |
| } |
| } |
| } |
| } |
| |
| // Set up the user attributes. |
| // The user attributes are set up as matrices where each row represents a component |
| // in the attribute transformed against the vertex's interpolated position across the grid. |
| { |
| // Base coord scale & bias |
| Vec4 s = m_lookupSpec.maxCoord - m_lookupSpec.minCoord; |
| Vec4 b = m_lookupSpec.minCoord; |
| |
| float baseCoordTrans[] = { s.x(), 0.0f, 0.f, b.x(), |
| 0.f, s.y(), 0.f, b.y(), |
| s.z() / 2.f, -s.z() / 2.f, 0.f, s.z() / 2.f + b.z(), |
| -s.w() / 2.f, s.w() / 2.f, 0.f, s.w() / 2.f + b.w() }; |
| |
| //a_in0 |
| m_userAttribTransforms.push_back(tcu::Mat4(baseCoordTrans)); |
| } |
| |
| bool hasLodBias = functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias; |
| |
| if (hasLodBias || m_lookupSpec.useSepRef) |
| { |
| float s = 0.0f; |
| float b = 0.0f; |
| float sepRefS = 0.0f; |
| float sepRefB = 0.0f; |
| |
| if (hasLodBias) |
| { |
| s = m_lookupSpec.maxLodBias - m_lookupSpec.minLodBias; |
| b = m_lookupSpec.minLodBias; |
| } |
| |
| if (m_lookupSpec.useSepRef) |
| { |
| sepRefS = m_lookupSpec.maxSepRef - m_lookupSpec.minSepRef; |
| sepRefB = m_lookupSpec.minSepRef; |
| } |
| float lodCoordTrans[] = { s / 2.0f, s / 2.0f, 0.f, b, sepRefS / 2.0f, sepRefS / 2.0f, 0.0f, sepRefB, |
| 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; |
| |
| //a_in1 |
| m_userAttribTransforms.push_back(tcu::Mat4(lodCoordTrans)); |
| } |
| |
| initShaderSources(); |
| initTexture(); |
| |
| ShaderRenderCase::init(); |
| } |
| |
| void TextureShadowLodTestCase::initTexture(void) |
| { |
| static const IVec4 texCubeSwz[] = { IVec4(0, 0, 1, 1), IVec4(1, 1, 0, 0), IVec4(0, 1, 0, 1), |
| IVec4(1, 0, 1, 0), IVec4(0, 1, 1, 0), IVec4(1, 0, 0, 1) }; |
| DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(texCubeSwz) == tcu::CUBEFACE_LAST); |
| |
| tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_textureSpec.format); |
| tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); |
| tcu::IVec2 viewportSize = getViewportSize(); |
| bool isAutoLod = functionHasAutoLod(m_isVertexCase ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT, |
| m_lookupSpec.function); // LOD can vary significantly |
| |
| switch (m_textureSpec.type) |
| { |
| case TEXTURETYPE_2D: |
| { |
| float levelStep = isAutoLod ? 0.0f : 1.0f / (float)de::max(1, m_textureSpec.numLevels - 1); |
| Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin; |
| Vec4 cBias = fmtInfo.valueMin; |
| int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4); |
| |
| m_texture2D = new glu::Texture2D(m_renderCtx, m_textureSpec.format, m_textureSpec.width, m_textureSpec.height); |
| for (int level = 0; level < m_textureSpec.numLevels; level++) |
| { |
| float fA = float(level) * levelStep; |
| float fB = 1.0f - fA; |
| Vec4 colorA = cBias + cScale * Vec4(fA, fB, fA, fB); |
| Vec4 colorB = cBias + cScale * Vec4(fB, fA, fB, fA); |
| |
| m_texture2D->getRefTexture().allocLevel(level); |
| tcu::fillWithGrid(m_texture2D->getRefTexture().getLevel(level), de::max(1, baseCellSize >> level), colorA, |
| colorB); |
| } |
| m_texture2D->upload(); |
| |
| // Compute LOD. |
| float dudx = |
| (m_lookupSpec.maxCoord[0] - m_lookupSpec.minCoord[0]) * (float)m_textureSpec.width / (float)viewportSize[0]; |
| float dvdy = (m_lookupSpec.maxCoord[1] - m_lookupSpec.minCoord[1]) * (float)m_textureSpec.height / |
| (float)viewportSize[1]; |
| m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy); |
| |
| // Append to texture list. |
| m_textures.push_back(TextureBinding(m_texture2D, m_textureSpec.sampler)); |
| break; |
| } |
| |
| case TEXTURETYPE_2D_ARRAY: |
| { |
| float layerStep = 1.0f / (float)m_textureSpec.depth; |
| float levelStep = |
| isAutoLod ? 0.0f : 1.0f / (float)(de::max(1, m_textureSpec.numLevels - 1) * m_textureSpec.depth); |
| Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin; |
| Vec4 cBias = fmtInfo.valueMin; |
| int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4); |
| |
| m_texture2DArray = new glu::Texture2DArray(m_renderCtx, m_textureSpec.format, m_textureSpec.width, |
| m_textureSpec.height, m_textureSpec.depth); |
| for (int level = 0; level < m_textureSpec.numLevels; level++) |
| { |
| m_texture2DArray->getRefTexture().allocLevel(level); |
| tcu::PixelBufferAccess levelAccess = m_texture2DArray->getRefTexture().getLevel(level); |
| |
| for (int layer = 0; layer < levelAccess.getDepth(); layer++) |
| { |
| float fA = (float)layer * layerStep + (float)level * levelStep; |
| float fB = 1.0f - fA; |
| Vec4 colorA = cBias + cScale * Vec4(fA, fB, fA, fB); |
| Vec4 colorB = cBias + cScale * Vec4(fB, fA, fB, fA); |
| |
| tcu::fillWithGrid( |
| tcu::getSubregion(levelAccess, 0, 0, layer, levelAccess.getWidth(), levelAccess.getHeight(), 1), |
| de::max(1, baseCellSize >> level), colorA, colorB); |
| } |
| } |
| m_texture2DArray->upload(); |
| |
| // Compute LOD. |
| float dudx = |
| (m_lookupSpec.maxCoord[0] - m_lookupSpec.minCoord[0]) * (float)m_textureSpec.width / (float)viewportSize[0]; |
| float dvdy = (m_lookupSpec.maxCoord[1] - m_lookupSpec.minCoord[1]) * (float)m_textureSpec.height / |
| (float)viewportSize[1]; |
| m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy); |
| |
| // Append to texture list. |
| m_textures.push_back(TextureBinding(m_texture2DArray, m_textureSpec.sampler)); |
| break; |
| } |
| |
| case TEXTURETYPE_CUBE_MAP: |
| { |
| float levelStep = isAutoLod ? 0.0f : 1.0f / (float)de::max(1, m_textureSpec.numLevels - 1); |
| Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin; |
| Vec4 cBias = fmtInfo.valueMin; |
| Vec4 cCorner = cBias + cScale * 0.5f; |
| int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4); |
| |
| DE_ASSERT(m_textureSpec.width == m_textureSpec.height); |
| m_textureCube = new glu::TextureCube(m_renderCtx, m_textureSpec.format, m_textureSpec.width); |
| for (int level = 0; level < m_textureSpec.numLevels; level++) |
| { |
| float fA = float(level) * levelStep; |
| float fB = 1.0f - fA; |
| Vec2 f(fA, fB); |
| |
| for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
| { |
| const IVec4& swzA = texCubeSwz[face]; |
| IVec4 swzB = 1 - swzA; |
| Vec4 colorA = cBias + cScale * f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]); |
| Vec4 colorB = cBias + cScale * f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]); |
| |
| m_textureCube->getRefTexture().allocLevel((tcu::CubeFace)face, level); |
| { |
| const tcu::PixelBufferAccess access = |
| m_textureCube->getRefTexture().getLevelFace(level, (tcu::CubeFace)face); |
| const int lastPix = access.getWidth() - 1; |
| |
| tcu::fillWithGrid(access, de::max(1, baseCellSize >> level), colorA, colorB); |
| |
| // Ensure all corners have identical colors in order to avoid dealing with ambiguous corner texel filtering |
| access.setPixel(cCorner, 0, 0); |
| access.setPixel(cCorner, 0, lastPix); |
| access.setPixel(cCorner, lastPix, 0); |
| access.setPixel(cCorner, lastPix, lastPix); |
| } |
| } |
| } |
| m_textureCube->upload(); |
| |
| // Compute LOD \note Assumes that only single side is accessed and R is constant major axis. |
| DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005); |
| DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) && |
| de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2])); |
| DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) && |
| de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2])); |
| |
| tcu::CubeFaceFloatCoords c00 = |
| tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2])); |
| tcu::CubeFaceFloatCoords c10 = |
| tcu::getCubeFaceCoords(Vec3(m_lookupSpec.maxCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2])); |
| tcu::CubeFaceFloatCoords c01 = |
| tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.maxCoord[1], m_lookupSpec.minCoord[2])); |
| float dudx = (c10.s - c00.s) * (float)m_textureSpec.width / (float)viewportSize[0]; |
| float dvdy = (c01.t - c00.t) * (float)m_textureSpec.height / (float)viewportSize[1]; |
| |
| m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy); |
| |
| m_textures.push_back(TextureBinding(m_textureCube, m_textureSpec.sampler)); |
| break; |
| } |
| |
| case TEXTURETYPE_CUBE_MAP_ARRAY: |
| { |
| float layerStep = 1.0f / (float)m_textureSpec.depth; |
| float levelStep = |
| isAutoLod ? 0.0f : 1.0f / (float)(de::max(1, m_textureSpec.numLevels - 1) * m_textureSpec.depth); |
| Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin; |
| Vec4 cBias = fmtInfo.valueMin; |
| Vec4 cCorner = cBias + cScale * 0.5f; |
| int baseCellSize = de::min(m_textureSpec.width / 4, m_textureSpec.height / 4); |
| |
| DE_ASSERT(m_textureSpec.width == m_textureSpec.height); |
| // I think size here means width/height of cube tex |
| m_textureCubeArray = |
| new glu::TextureCubeArray(m_renderCtx, m_textureSpec.format, m_textureSpec.width, m_textureSpec.depth * 6); |
| // mipmap level |
| for (int level = 0; level < m_textureSpec.numLevels; level++) |
| { |
| m_textureCubeArray->getRefTexture().allocLevel(level); |
| tcu::PixelBufferAccess levelAccess = m_textureCubeArray->getRefTexture().getLevel(level); |
| |
| //array layer |
| DE_ASSERT((levelAccess.getDepth() % 6) == 0); |
| |
| for (int layer = 0; layer < levelAccess.getDepth() / 6; ++layer) |
| { |
| for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
| { |
| float fA = (float)layer * layerStep + float(level) * levelStep; |
| float fB = 1.0f - fA; |
| Vec2 f(fA, fB); |
| |
| const IVec4& swzA = texCubeSwz[face]; |
| IVec4 swzB = 1 - swzA; |
| Vec4 colorA = cBias + cScale * f.swizzle(swzA[0], swzA[1], swzA[2], swzA[3]); |
| Vec4 colorB = cBias + cScale * f.swizzle(swzB[0], swzB[1], swzB[2], swzB[3]); |
| |
| { |
| const tcu::PixelBufferAccess access = m_textureCubeArray->getRefTexture().getLevel(level); |
| const int lastPix = access.getWidth() - 1; |
| |
| int layerFaceNdx = face + layer * 6; |
| |
| DE_ASSERT(levelAccess.getWidth() == levelAccess.getHeight()); |
| tcu::fillWithGrid(tcu::getSubregion(access, 0, 0, layerFaceNdx, levelAccess.getWidth(), |
| levelAccess.getHeight(), 1), |
| de::max(1, baseCellSize >> level), colorA, colorB); |
| |
| // Ensure all corners have identical colors in order to avoid dealing with ambiguous corner texel filtering |
| access.setPixel(cCorner, 0, 0, layer); |
| access.setPixel(cCorner, 0, lastPix, layer); |
| access.setPixel(cCorner, lastPix, 0, layer); |
| access.setPixel(cCorner, lastPix, lastPix, layer); |
| } |
| } |
| } |
| } |
| m_textureCubeArray->upload(); |
| |
| // Compute LOD \note Assumes that only single side is accessed and R is constant major axis. |
| DE_ASSERT(de::abs(m_lookupSpec.minCoord[2] - m_lookupSpec.maxCoord[2]) < 0.005); |
| DE_ASSERT(de::abs(m_lookupSpec.minCoord[0]) < de::abs(m_lookupSpec.minCoord[2]) && |
| de::abs(m_lookupSpec.maxCoord[0]) < de::abs(m_lookupSpec.minCoord[2])); |
| DE_ASSERT(de::abs(m_lookupSpec.minCoord[1]) < de::abs(m_lookupSpec.minCoord[2]) && |
| de::abs(m_lookupSpec.maxCoord[1]) < de::abs(m_lookupSpec.minCoord[2])); |
| |
| tcu::CubeFaceFloatCoords c00 = |
| tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2])); |
| tcu::CubeFaceFloatCoords c10 = |
| tcu::getCubeFaceCoords(Vec3(m_lookupSpec.maxCoord[0], m_lookupSpec.minCoord[1], m_lookupSpec.minCoord[2])); |
| tcu::CubeFaceFloatCoords c01 = |
| tcu::getCubeFaceCoords(Vec3(m_lookupSpec.minCoord[0], m_lookupSpec.maxCoord[1], m_lookupSpec.minCoord[2])); |
| float dudx = (c10.s - c00.s) * (float)m_textureSpec.width / (float)viewportSize[0]; |
| float dvdy = (c01.t - c00.t) * (float)m_textureSpec.height / (float)viewportSize[1]; |
| |
| m_lookupParams.lod = computeLodFromDerivates(DEFAULT_LOD_MODE, dudx, 0.0f, 0.0f, dvdy); |
| |
| m_textures.push_back(TextureBinding(m_textureCubeArray, m_textureSpec.sampler)); |
| break; |
| } |
| |
| default: |
| DE_ASSERT(DE_FALSE); |
| } |
| |
| // Set lookup scale & bias |
| m_lookupParams.scale = fmtInfo.lookupScale; |
| m_lookupParams.bias = fmtInfo.lookupBias; |
| m_lookupParams.offset = m_lookupSpec.offset; |
| } |
| |
| void TextureShadowLodTestCase::initShaderSources(void) |
| { |
| Function function = m_lookupSpec.function; |
| bool isVtxCase = m_isVertexCase; |
| bool hasLodBias = functionHasLod(m_lookupSpec.function) || m_lookupSpec.useBias; |
| int texCoordComps = m_textureSpec.type == TEXTURETYPE_2D ? 2 : 3; |
| int extraCoordComps = 1; // For shadow ref |
| bool hasSepShadowRef = m_lookupSpec.useSepRef; |
| glu::DataType coordType = glu::getDataTypeFloatVec(texCoordComps + extraCoordComps); |
| glu::Precision coordPrec = glu::PRECISION_HIGHP; |
| const char* coordTypeName = glu::getDataTypeName(coordType); |
| const char* coordPrecName = glu::getPrecisionName(coordPrec); |
| glu::DataType samplerType = glu::TYPE_LAST; |
| const char* baseFuncName = DE_NULL; |
| |
| switch (m_textureSpec.type) |
| { |
| case TEXTURETYPE_2D: |
| samplerType = glu::TYPE_SAMPLER_2D_SHADOW; |
| break; |
| case TEXTURETYPE_CUBE_MAP: |
| samplerType = glu::TYPE_SAMPLER_CUBE_SHADOW; |
| break; |
| case TEXTURETYPE_CUBE_MAP_ARRAY: |
| samplerType = glu::TYPE_SAMPLER_CUBE_ARRAY_SHADOW; |
| break; |
| case TEXTURETYPE_2D_ARRAY: |
| samplerType = glu::TYPE_SAMPLER_2D_ARRAY_SHADOW; |
| break; |
| default: |
| DE_ASSERT(DE_FALSE); |
| } |
| |
| switch (m_lookupSpec.function) |
| { |
| case FUNCTION_TEXTURE: |
| baseFuncName = "texture"; |
| break; |
| case FUNCTION_TEXTURELOD: |
| baseFuncName = "textureLod"; |
| break; |
| default: |
| DE_ASSERT(DE_FALSE); |
| } |
| |
| bool isGL = glu::isContextTypeGLCore(m_renderCtx.getType()); |
| glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_renderCtx.getType()); |
| |
| std::string shaderVersion = glu::getGLSLVersionDeclaration(glslVersion); |
| |
| std::ostringstream vert; |
| std::ostringstream frag; |
| std::ostringstream& op = isVtxCase ? vert : frag; |
| |
| std::string cubeMapArrayEXT = ""; |
| |
| // Check if we need to add the texture_cube_map_array extension. |
| if (m_textureSpec.type == TEXTURETYPE_CUBE_MAP_ARRAY) |
| { |
| if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 2)) && |
| !glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 0))) |
| { |
| if (isGL) |
| { |
| cubeMapArrayEXT = "#extension GL_ARB_texture_cube_map_array : require\n"; |
| } |
| else |
| { |
| glu::ContextInfo* info = glu::ContextInfo::create(m_renderCtx); |
| if (info->isExtensionSupported("GL_EXT_texture_cube_map_array")) |
| { |
| cubeMapArrayEXT = "#extension GL_EXT_texture_cube_map_array : require\n"; |
| } |
| else |
| { |
| cubeMapArrayEXT = "#extension GL_OES_texture_cube_map_array : require\n"; |
| } |
| } |
| } |
| } |
| |
| vert << shaderVersion << "\n" |
| << "#extension GL_EXT_texture_shadow_lod : require\n\n"; |
| |
| vert << cubeMapArrayEXT; |
| |
| vert << "in highp vec4 a_position;\n" |
| << "in " << coordPrecName << " " << coordTypeName << " a_in0;\n"; |
| |
| if (hasLodBias || hasSepShadowRef) |
| { |
| vert << "in " << coordPrecName << " vec4 a_in1;\n"; |
| } |
| |
| frag << shaderVersion << "\n" |
| << "#extension GL_EXT_texture_shadow_lod : require\n\n"; |
| |
| frag << cubeMapArrayEXT; |
| |
| frag << "out mediump vec4 o_color;\n"; |
| |
| if (isVtxCase) |
| { |
| vert << "out mediump vec4 v_color;\n"; |
| frag << "in mediump vec4 v_color;\n"; |
| } |
| else |
| { |
| vert << "out " << coordPrecName << " " << coordTypeName << " v_texCoord;\n"; |
| frag << "in " << coordPrecName << " " << coordTypeName << " v_texCoord;\n"; |
| |
| if (hasLodBias || hasSepShadowRef) |
| { |
| vert << "out " << coordPrecName << " vec4 v_lodShadowRef;\n"; |
| frag << "in " << coordPrecName << " vec4 v_lodShadowRef;\n"; |
| } |
| } |
| |
| // Uniforms |
| op << "uniform highp " << glu::getDataTypeName(samplerType) << " u_sampler;\n" |
| << "uniform highp vec4 u_scale;\n" |
| << "uniform highp vec4 u_bias;\n"; |
| |
| vert << "\nvoid main()\n{\n" |
| << "\tgl_Position = a_position;\n"; |
| frag << "\nvoid main()\n{\n"; |
| |
| if (isVtxCase) |
| vert << "\tv_color = "; |
| else |
| frag << "\to_color = "; |
| |
| // Op. |
| { |
| const char* texCoord = isVtxCase ? "a_in0" : "v_texCoord"; |
| const char* lodBias = isVtxCase ? "a_in1" : "v_lodShadowRef"; |
| |
| op << "vec4(" << baseFuncName; |
| if (m_lookupSpec.useOffset) |
| op << "Offset"; |
| op << "(u_sampler, "; |
| |
| op << texCoord; |
| |
| if (m_lookupSpec.useSepRef) |
| { |
| op << ", " << lodBias << ".y"; |
| } |
| |
| if (functionHasLod(function)) |
| { |
| op << ", " << lodBias << ".x"; |
| } |
| |
| if (m_lookupSpec.useOffset) |
| { |
| int offsetComps = 2; |
| |
| op << ", ivec" << offsetComps << "("; |
| for (int ndx = 0; ndx < offsetComps; ndx++) |
| { |
| if (ndx != 0) |
| op << ", "; |
| op << m_lookupSpec.offset[ndx]; |
| } |
| op << ")"; |
| } |
| |
| if (m_lookupSpec.useBias) |
| op << ", " << lodBias << ".x"; |
| |
| op << ")"; |
| |
| op << ", 0.0, 0.0, 1.0)"; |
| |
| op << ";\n"; |
| } |
| |
| if (isVtxCase) |
| frag << "\to_color = v_color;\n"; |
| else |
| { |
| vert << "\tv_texCoord = a_in0;\n"; |
| |
| if (hasLodBias || hasSepShadowRef) |
| { |
| vert << "\tv_lodShadowRef = a_in1;\n"; |
| } |
| } |
| |
| vert << "}\n"; |
| frag << "}\n"; |
| |
| m_vertShaderSource = vert.str(); |
| m_fragShaderSource = frag.str(); |
| } |
| |
| void TextureShadowLodTestCase::deinit(void) |
| { |
| ShaderRenderCase::deinit(); |
| |
| delete m_texture2D; |
| delete m_textureCube; |
| delete m_texture2DArray; |
| |
| m_texture2D = DE_NULL; |
| m_textureCube = DE_NULL; |
| m_texture2DArray = DE_NULL; |
| } |
| |
| void TextureShadowLodTestCase::setupUniforms(deUint32 programID, const tcu::Vec4&) |
| { |
| const glw::Functions& gl = m_renderCtx.getFunctions(); |
| gl.uniform1i(gl.getUniformLocation(programID, "u_sampler"), 0); |
| gl.uniform4fv(gl.getUniformLocation(programID, "u_scale"), 1, m_lookupParams.scale.getPtr()); |
| gl.uniform4fv(gl.getUniformLocation(programID, "u_bias"), 1, m_lookupParams.bias.getPtr()); |
| } |
| |
| TextureShadowLodTest::TextureShadowLodTest(Context& context) |
| : TestCaseGroup(context, "ext_texture_shadow_lod", "Texture Access Function Tests") |
| { |
| } |
| |
| TextureShadowLodTest::~TextureShadowLodTest(void) |
| { |
| } |
| |
| enum CaseFlags |
| { |
| VERTEX = (1 << 0), |
| FRAGMENT = (1 << 1), |
| BOTH = VERTEX | FRAGMENT |
| }; |
| |
| struct TexFuncCaseSpec |
| { |
| const char* name; |
| TextureLookupSpec lookupSpec; |
| TextureSpec texSpec; |
| TexEvalFunc evalFunc; |
| deUint32 flags; |
| }; |
| |
| #define CASE_SPEC(NAME, FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, USEOFFSET, OFFSET, USESEPREF, MINSEPREF, \ |
| MAXSEPREF, TEXSPEC, EVALFUNC, FLAGS) \ |
| { \ |
| #NAME, TextureLookupSpec(FUNC, MINCOORD, MAXCOORD, USEBIAS, MINLOD, MAXLOD, USEOFFSET, OFFSET, USESEPREF, \ |
| MINSEPREF, MAXSEPREF), \ |
| TEXSPEC, EVALFUNC, FLAGS \ |
| } |
| |
| static void createCaseGroup(TestCaseGroup* parent, const char* groupName, const char* groupDesc, |
| const TexFuncCaseSpec* cases, int numCases) |
| { |
| tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), groupName, groupDesc); |
| parent->addChild(group); |
| |
| for (int ndx = 0; ndx < numCases; ndx++) |
| { |
| std::string name = cases[ndx].name; |
| if (cases[ndx].flags & VERTEX) |
| group->addChild(new TextureShadowLodTestCase(parent->getContext(), (name + "_vertex").c_str(), "", |
| cases[ndx].lookupSpec, cases[ndx].texSpec, cases[ndx].evalFunc, |
| true)); |
| if (cases[ndx].flags & FRAGMENT) |
| group->addChild(new TextureShadowLodTestCase(parent->getContext(), (name + "_fragment").c_str(), "", |
| cases[ndx].lookupSpec, cases[ndx].texSpec, cases[ndx].evalFunc, |
| false)); |
| } |
| } |
| |
| void TextureShadowLodTest::init(void) |
| { |
| // Samplers |
| static const tcu::Sampler samplerShadowNoMipmap( |
| tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::NEAREST, |
| tcu::Sampler::NEAREST, 0.0f /* LOD threshold */, true /* normalized coords */, tcu::Sampler::COMPAREMODE_LESS, |
| 0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */); |
| static const tcu::Sampler samplerShadowMipmap( |
| tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::NEAREST_MIPMAP_NEAREST, |
| tcu::Sampler::NEAREST, 0.0f /* LOD threshold */, true /* normalized coords */, tcu::Sampler::COMPAREMODE_LESS, |
| 0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */); |
| |
| // Default textures. |
| // Type Format W H D L Sampler |
| |
| static const TextureSpec tex2DArrayShadow(TEXTURETYPE_2D_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 1, |
| samplerShadowNoMipmap); |
| static const TextureSpec texCubeShadow(TEXTURETYPE_CUBE_MAP, GL_DEPTH_COMPONENT16, 256, 256, 1, 1, |
| samplerShadowNoMipmap); |
| static const TextureSpec texCubeMipmapShadow(TEXTURETYPE_CUBE_MAP, GL_DEPTH_COMPONENT16, 256, 256, 1, 9, |
| samplerShadowMipmap); |
| static const TextureSpec texCubeArrayShadow(TEXTURETYPE_CUBE_MAP_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 1, |
| samplerShadowNoMipmap); |
| static const TextureSpec texCubeArrayMipmapShadow(TEXTURETYPE_CUBE_MAP_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 8, |
| samplerShadowMipmap); |
| static const TextureSpec tex2DArrayMipmapShadow(TEXTURETYPE_2D_ARRAY, GL_DEPTH_COMPONENT16, 128, 128, 4, 8, |
| samplerShadowMipmap); |
| |
| // texture() cases |
| static const TexFuncCaseSpec textureCases[] = { |
| // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags |
| CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f), |
| false, 0.0f, 0.0f, false, IVec3(0), false, 0.0f, 0.0f, tex2DArrayShadow, evalTexture2DArrayShadow, |
| VERTEX), |
| CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f), |
| false, 0.0f, 0.0f, false, IVec3(0), false, 0.0f, 0.0f, tex2DArrayMipmapShadow, |
| evalTexture2DArrayShadow, FRAGMENT), |
| CASE_SPEC(sampler2darrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), |
| Vec4(1.5f, 2.3f, 3.5f, 1.0f), true, -2.0f, 2.0f, false, IVec3(0), false, 0.0f, 0.0f, |
| tex2DArrayMipmapShadow, evalTexture2DArrayShadowBias, FRAGMENT), |
| |
| CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f), |
| Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, 0.0f, 0.0f, false, IVec3(0), true, 0.0f, 1.0f, |
| texCubeArrayShadow, evalTextureCubeArrayShadow, VERTEX), |
| CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f), |
| Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, 0.0f, 0.0f, false, IVec3(0), true, 0.0f, 1.0f, |
| texCubeArrayMipmapShadow, evalTextureCubeArrayShadow, FRAGMENT), |
| CASE_SPEC(samplercubearrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.0f, -1.0f, 1.01f, -0.5f), |
| Vec4(1.0f, 1.0f, 1.01f, 3.5f), true, -2.0, 2.0f, false, IVec3(0), true, 0.0f, 1.0f, |
| texCubeArrayMipmapShadow, evalTextureCubeArrayShadowBias, FRAGMENT), |
| }; |
| createCaseGroup(this, "texture", "texture() Tests", textureCases, DE_LENGTH_OF_ARRAY(textureCases)); |
| |
| // textureOffset() cases |
| // \note _bias variants are not using mipmap thanks to wide allowed range for LOD computation |
| static const TexFuncCaseSpec textureOffsetCases[] = { |
| // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags |
| CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f), |
| false, 0.0f, 0.0f, true, IVec3(-8, 7, 0), false, 0.0f, 0.0f, tex2DArrayShadow, |
| evalTexture2DArrayShadowOffset, VERTEX), |
| CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), Vec4(1.5f, 2.3f, 3.5f, 1.0f), |
| false, 0.0f, 0.0f, true, IVec3(7, -8, 0), false, 0.0f, 0.0f, tex2DArrayMipmapShadow, |
| evalTexture2DArrayShadowOffset, FRAGMENT), |
| CASE_SPEC(sampler2darrayshadow_bias, FUNCTION_TEXTURE, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), |
| Vec4(1.5f, 2.3f, 3.5f, 1.0f), true, -2.0f, 2.0f, true, IVec3(7, -8, 0), false, 0.0f, 0.0f, |
| tex2DArrayMipmapShadow, evalTexture2DArrayShadowOffsetBias, FRAGMENT), |
| }; |
| createCaseGroup(this, "textureoffset", "textureOffset() Tests", textureOffsetCases, |
| DE_LENGTH_OF_ARRAY(textureOffsetCases)); |
| |
| // textureLod() cases |
| static const TexFuncCaseSpec textureLodCases[] = { |
| // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags |
| CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), |
| Vec4(1.5f, 2.3f, 3.5f, 1.0f), false, -1.0f, 8.0f, false, IVec3(0), false, 0.0f, 0.0f, |
| tex2DArrayMipmapShadow, evalTexture2DArrayShadowLod, BOTH), |
| CASE_SPEC(samplercubeshadow, FUNCTION_TEXTURELOD, Vec4(-1.0f, -1.0f, 1.01f, 0.0f), |
| Vec4(1.0f, 1.0f, 1.01f, 1.0f), false, -1.0f, 8.0f, false, IVec3(0), false, 0.0f, 0.0f, |
| texCubeMipmapShadow, evalTextureCubeShadowLod, BOTH), |
| CASE_SPEC(samplercubearrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.0f, -1.0f, 1.01f, -0.5f), |
| Vec4(1.0f, 1.0f, 1.01f, 3.5f), false, -1.0f, 8.0f, false, IVec3(0), true, 0.0f, 1.0f, |
| texCubeArrayMipmapShadow, evalTextureCubeArrayShadowLod, FRAGMENT) |
| }; |
| createCaseGroup(this, "texturelod", "textureLod() Tests", textureLodCases, DE_LENGTH_OF_ARRAY(textureLodCases)); |
| |
| // textureLodOffset() cases |
| static const TexFuncCaseSpec textureLodOffsetCases[] = { |
| // Name Function MinCoord MaxCoord Bias? MinLod MaxLod Offset? Offset Format EvalFunc Flags |
| CASE_SPEC(sampler2darrayshadow, FUNCTION_TEXTURELOD, Vec4(-1.2f, -0.4f, -0.5f, 0.0f), |
| Vec4(1.5f, 2.3f, 3.5f, 1.0f), false, -1.0f, 9.0f, true, IVec3(-8, 7, 0), false, 0.0f, 0.0f, |
| tex2DArrayMipmapShadow, evalTexture2DArrayShadowLodOffset, BOTH), |
| }; |
| createCaseGroup(this, "texturelodoffset", "textureLodOffset() Tests", textureLodOffsetCases, |
| DE_LENGTH_OF_ARRAY(textureLodOffsetCases)); |
| } |
| } // namespace Functional |
| } // namespace deqp |