--- /dev/null
+/*-------------------------------------------------------------------------
+ * OpenGL Conformance Test Suite
+ * -----------------------------
+ *
+ * Copyright (c) 2017 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 glcTextureFilterAnisotropicTests.cpp
+ * \brief Conformance tests for the GL_EXT_texture_filter_anisotropic functionality.
+ */ /*-------------------------------------------------------------------*/
+
+#include "deMath.h"
+
+#include "glcTextureFilterAnisotropicTests.hpp"
+#include "gluContextInfo.hpp"
+#include "gluDefs.hpp"
+#include "gluShaderProgram.hpp"
+#include "gluStrUtil.hpp"
+#include "gluTextureUtil.hpp"
+#include "glwEnums.hpp"
+#include "glwFunctions.hpp"
+#include "tcuRGBA.hpp"
+#include "tcuRenderTarget.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuTexture.hpp"
+
+using namespace glw;
+using namespace glu;
+
+namespace glcts
+{
+
+namespace TextureFilterAnisotropicUtils
+{
+
+/** Replace all occurrence of <token> with <text> in <str>
+ *
+ * @param token Token string
+ * @param text String that will be used as replacement for <token>
+ * @param string String to work on
+ **/
+void replaceToken(const GLchar* token, const GLchar* text, std::string& str)
+{
+ const size_t text_length = strlen(text);
+ const size_t token_length = strlen(token);
+
+ size_t token_position;
+ while ((token_position = str.find(token, 0)) != std::string::npos)
+ {
+ str.replace(token_position, token_length, text, text_length);
+ }
+}
+
+/** Allocate storage for texture
+ *
+ * @param target Texture target
+ * @param refTexCoordType GLSL texture coord type
+ * @param refSamplerType GLSL texture sampler type
+ **/
+void generateTokens(GLenum target, std::string& refTexCoordType, std::string& refSamplerType)
+{
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ refTexCoordType = "vec2";
+ refSamplerType = "sampler2D";
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ refTexCoordType = "vec3";
+ refSamplerType = "sampler2DArray";
+ break;
+ default:
+ refTexCoordType = "vec2";
+ refSamplerType = "sampler2D";
+ break;
+ }
+}
+
+/** Set contents of texture
+ *
+ * @param gl GL functions
+ * @param target Texture target
+ * @param level Mipmap level
+ * @param internal_format Format of data
+ * @param width Width of texture
+ * @param height Height of texture
+ * @param depth Depth of texture
+ * @param format Format of data
+ * @param type Type of data
+ * @param data Buffer with image data
+ **/
+void texImage(const Functions& gl, GLenum target, GLint level, GLenum internal_format, GLuint width, GLuint height,
+ GLuint depth, GLenum format, GLenum type, const GLvoid* data)
+{
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ gl.texImage2D(target, level, internal_format, width, height, 0 /* border */, format, type, data);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "texImage");
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ gl.texImage3D(target, level, internal_format, width, height, depth, 0 /* border */, format, type, data);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "texImage");
+ break;
+ default:
+ TCU_FAIL("Invalid enum");
+ break;
+ }
+}
+
+/** Set contents of texture
+ *
+ * @param gl GL functions
+ * @param target Texture target
+ * @param level Mipmap level
+ * @param x X offset
+ * @param y Y offset
+ * @param z Z offset
+ * @param width Width of texture
+ * @param height Height of texture
+ * @param depth Depth of texture
+ * @param format Format of data
+ * @param type Type of data
+ * @param pixels Buffer with image data
+ **/
+void subImage(const Functions& gl, GLenum target, GLint level, GLint x, GLint y, GLint z, GLsizei width, GLsizei height,
+ GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ gl.texSubImage2D(target, level, x, y, width, height, format, type, pixels);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ gl.texSubImage3D(target, level, x, y, z, width, height, depth, format, type, pixels);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage3D");
+ break;
+ default:
+ TCU_FAIL("Invalid enum");
+ break;
+ }
+}
+
+} // TextureFilterAnisotropicUtils namespace
+
+/** Constructor.
+ *
+ * @param context Rendering context
+ */
+TextureFilterAnisotropicQueriesTestCase::TextureFilterAnisotropicQueriesTestCase(deqp::Context& context)
+ : TestCase(context, "queries", "Verifies if queries for GL_EXT_texture_filter_anisotropic tokens works as expected")
+{
+ /* Left blank intentionally */
+}
+
+/** Stub deinit method. */
+void TextureFilterAnisotropicQueriesTestCase::deinit()
+{
+}
+
+/** Stub init method */
+void TextureFilterAnisotropicQueriesTestCase::init()
+{
+ if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_filter_anisotropic"))
+ TCU_THROW(NotSupportedError, "GL_EXT_texture_filter_anisotropic not supported");
+}
+
+/** Executes test iteration.
+ *
+ * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
+ */
+tcu::TestNode::IterateResult TextureFilterAnisotropicQueriesTestCase::iterate()
+{
+ const glw::Functions& gl = m_context.getRenderContext().getFunctions();
+
+ GLuint texture;
+ gl.genTextures(1, &texture);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
+ gl.bindTexture(GL_TEXTURE_2D, texture);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
+ TextureFilterAnisotropicUtils::texImage(gl, GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ if (verifyTexParameters(gl) && verifyGet(gl))
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+ else
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+
+ gl.deleteTextures(1, &texture);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures");
+
+ return STOP;
+}
+
+/** Verify if texParameter*, getTexParameter* queries for GL_TEXTURE_MAX_ANISOTROPY_EXT pname works as expected.
+ *
+ * @param gl OpenGL functions wrapper
+ *
+ * @return Returns true if queries test passed, false otherwise.
+ */
+bool TextureFilterAnisotropicQueriesTestCase::verifyTexParameters(const glw::Functions& gl)
+{
+ GLint iValue;
+ gl.getTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &iValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getTexParameteriv");
+
+ // Verify initial integer value which should be equal to 1
+ if (iValue != 1)
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message
+ << "GetTexParameteriv failed. Expected value: 1, Queried value: " << iValue
+ << tcu::TestLog::EndMessage;
+ return false;
+ }
+
+ GLfloat fValue;
+ gl.getTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &fValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getTexParameterfv");
+
+ // Verify initial float value which should be equal to 1.0f
+ if (fValue != 1.0f)
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message
+ << "GetTexParameterfv failed. Expected value: 1.0, Queried value: " << iValue
+ << tcu::TestLog::EndMessage;
+ return false;
+ }
+
+ // Set custom integer value and verify it
+ iValue = 2;
+ gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, iValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri");
+
+ gl.getTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &iValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getTexParameteriv");
+
+ if (iValue != 2)
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message
+ << "texParameteri failed. Expected value: 2, Queried value: " << iValue
+ << tcu::TestLog::EndMessage;
+ return false;
+ }
+
+ // Set custom float value and verify it
+ fValue = 1.5f;
+ gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "texParameterf");
+
+ gl.getTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &fValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getTexParameterfv");
+
+ if (fValue != 1.5f)
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message
+ << "texParameterf failed. Expected value: 1.5, Queried value: " << fValue
+ << tcu::TestLog::EndMessage;
+ return false;
+ }
+
+ // Set custom integer value and verify it
+ iValue = 1;
+ gl.texParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &iValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteriv");
+
+ gl.getTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &iValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getTexParameteriv");
+
+ if (iValue != 1)
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message
+ << "texParameteriv failed. Expected value: 1, Queried value: " << iValue
+ << tcu::TestLog::EndMessage;
+ return false;
+ }
+
+ // Set custom float value and verify it
+ fValue = 2.0f;
+ gl.texParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &fValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "texParameterfv");
+
+ gl.getTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &fValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getTexParameterfv");
+
+ if (fValue != 2.0f)
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message
+ << "texParameterfv failed. Expected value: 2.0, Queried value: " << fValue
+ << tcu::TestLog::EndMessage;
+ return false;
+ }
+
+ // Set texture filter anisotropic to 0.9f and check if INVALID_VALUE error is generated
+ fValue = 0.9f;
+ gl.texParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &fValue);
+ GLint error = gl.getError();
+ if (error != GL_INVALID_VALUE)
+ {
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "texParameterfv failed for values less then 1.0f. Expected INVALID_VALUE error. Generated error: "
+ << glu::getErrorName(error) << tcu::TestLog::EndMessage;
+ return false;
+ }
+
+ return true;
+}
+
+/** Verify if get* queries for GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT pname works as expected.
+ *
+ * @param gl OpenGL functions wrapper
+ *
+ * @return Returns true if queries test passed, false otherwise.
+ */
+bool TextureFilterAnisotropicQueriesTestCase::verifyGet(const glw::Functions& gl)
+{
+ GLboolean bValue;
+ GLint iValue;
+ GLfloat fValue;
+ GLdouble dValue;
+
+ gl.getBooleanv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &bValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getBooleanv");
+
+ gl.getIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &iValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv");
+
+ gl.getFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getFloatv");
+
+ if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
+ {
+ gl.getDoublev(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dValue);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getDoublev");
+ }
+
+ return true;
+}
+
+/** Constructor.
+ *
+ * @param context Rendering context
+ */
+TextureFilterAnisotropicDrawingTestCase::TextureFilterAnisotropicDrawingTestCase(deqp::Context& context)
+ : TestCase(context, "drawing", "Verifies if drawing texture with anisotropic filtering is performed as expected")
+ , m_vertex(DE_NULL)
+ , m_fragment(DE_NULL)
+ , m_texture(0)
+{
+ /* Left blank intentionally */
+}
+
+/** Stub deinit method. */
+void TextureFilterAnisotropicDrawingTestCase::deinit()
+{
+ /* Left blank intentionally */
+}
+
+/** Stub init method */
+void TextureFilterAnisotropicDrawingTestCase::init()
+{
+ if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_filter_anisotropic"))
+ TCU_THROW(NotSupportedError, "GL_EXT_texture_filter_anisotropic not supported");
+
+ const tcu::RenderTarget& rt = m_context.getRenderTarget();
+
+ GLint width = rt.getWidth();
+ GLint height = rt.getHeight();
+
+ if (width < 32 || height < 32)
+ TCU_THROW(NotSupportedError, "Config not supported - render buffer size should be at least 32x32");
+
+ m_vertex = "#version <VERSION>\n"
+ "\n"
+ "in highp vec3 vertex;\n"
+ "in highp <TEXCOORD_TYPE> inTexCoord;\n"
+ "out highp <TEXCOORD_TYPE> commonTexCoord;\n"
+ "\n"
+ "uniform highp mat4 projectionMatrix;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " commonTexCoord = inTexCoord;\n"
+ " gl_Position = vec4(vertex, 1.0) * projectionMatrix;\n"
+ "}\n";
+
+ m_fragment = "#version <VERSION>\n"
+ "\n"
+ "in highp <TEXCOORD_TYPE> commonTexCoord;\n"
+ "out highp vec4 fragColor;\n"
+ "\n"
+ "uniform highp <SAMPLER_TYPE> tex;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = texture(tex, commonTexCoord);\n"
+ "}\n"
+ "\n";
+
+ m_supportedTargets.clear();
+ m_supportedTargets.push_back(GL_TEXTURE_2D);
+ m_supportedTargets.push_back(GL_TEXTURE_2D_ARRAY);
+
+ m_supportedInternalFormats.clear();
+ m_supportedInternalFormats.push_back(GL_R8);
+ m_supportedInternalFormats.push_back(GL_R8_SNORM);
+ m_supportedInternalFormats.push_back(GL_RG8);
+ m_supportedInternalFormats.push_back(GL_RG8_SNORM);
+ m_supportedInternalFormats.push_back(GL_RGB8);
+ m_supportedInternalFormats.push_back(GL_RGB8_SNORM);
+ m_supportedInternalFormats.push_back(GL_RGB565);
+ m_supportedInternalFormats.push_back(GL_RGBA4);
+ m_supportedInternalFormats.push_back(GL_RGB5_A1);
+ m_supportedInternalFormats.push_back(GL_RGBA8);
+ m_supportedInternalFormats.push_back(GL_RGBA8_SNORM);
+ m_supportedInternalFormats.push_back(GL_RGB10_A2);
+ m_supportedInternalFormats.push_back(GL_SRGB8);
+ m_supportedInternalFormats.push_back(GL_SRGB8_ALPHA8);
+ m_supportedInternalFormats.push_back(GL_R16F);
+ m_supportedInternalFormats.push_back(GL_RG16F);
+ m_supportedInternalFormats.push_back(GL_RGB16F);
+ m_supportedInternalFormats.push_back(GL_RGBA16F);
+ m_supportedInternalFormats.push_back(GL_R11F_G11F_B10F);
+ m_supportedInternalFormats.push_back(GL_RGB9_E5);
+}
+
+/** Executes test iteration.
+ *
+ * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
+ */
+tcu::TestNode::IterateResult TextureFilterAnisotropicDrawingTestCase::iterate()
+{
+ const glw::Functions& gl = m_context.getRenderContext().getFunctions();
+
+ bool result = true;
+
+ GLfloat maxAnisoDegree = 2.0;
+
+ gl.getFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisoDegree);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "getFloatv");
+
+ std::vector<GLfloat> anisoVec;
+ anisoVec.push_back(1.0f);
+ anisoVec.push_back(2.0f);
+ if (maxAnisoDegree > 2.0f)
+ anisoVec.push_back(maxAnisoDegree);
+
+ for (deUint32 iTarget = 0; iTarget < m_supportedTargets.size(); ++iTarget)
+ {
+ GLenum target = m_supportedTargets[iTarget];
+
+ for (deUint32 iFormat = 0; iFormat < m_supportedInternalFormats.size(); ++iFormat)
+ {
+ GLenum format = m_supportedInternalFormats[iFormat];
+
+ // Generate texture
+ generateTexture(gl, target);
+
+ // Fill texture with strips pattern
+ fillTexture(gl, target, format);
+
+ // Draw scene
+ GLuint lastPoints = 0xFFFFFFFF;
+ for (deUint32 i = 0; i < anisoVec.size(); ++i)
+ {
+ GLfloat aniso = anisoVec[i];
+
+ if (result)
+ result = result && drawTexture(gl, target, aniso);
+
+ // Verify result
+ if (result)
+ {
+ GLuint currentPoints = verifyScene(gl);
+
+ if (lastPoints <= currentPoints)
+ {
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Anisotropy verification failed (lastPoints <= currentPoints) for "
+ << "anisotropy: " << aniso << ", "
+ << "target: " << glu::getTextureTargetName(target) << ", "
+ << "internalFormat: " << glu::getUncompressedTextureFormatName(format) << ", "
+ << "lastPoints: " << lastPoints << ", "
+ << "currentPoints: " << currentPoints << tcu::TestLog::EndMessage;
+
+ result = false;
+ break;
+ }
+
+ lastPoints = currentPoints;
+ }
+ }
+
+ // Release texture
+ releaseTexture(gl);
+
+ if (!result)
+ {
+ // Stop loops
+ iTarget = m_supportedTargets.size();
+ iFormat = m_supportedInternalFormats.size();
+ }
+ }
+ }
+
+ if (result)
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+ else
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+ return STOP;
+}
+
+/** Generate texture and set filtering parameters.
+ *
+ * @param gl OpenGL functions wrapper
+ * @param target Texture target
+ * @param internalFormat Texture internal format
+ */
+void TextureFilterAnisotropicDrawingTestCase::generateTexture(const glw::Functions& gl, GLenum target)
+{
+ gl.genTextures(1, &m_texture);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures");
+ gl.bindTexture(target, m_texture);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture");
+
+ gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri");
+ gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri");
+ gl.texParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri");
+ gl.texParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri");
+ gl.texParameteri(target, GL_TEXTURE_MAX_LEVEL, 1);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri");
+}
+
+/** Fill texture with strips pattern.
+ *
+ * @param gl OpenGL functions wrapper
+ * @param target Texture target
+ * @param internalFormat Texture internal format
+ */
+void TextureFilterAnisotropicDrawingTestCase::fillTexture(const glw::Functions& gl, GLenum target,
+ GLenum internalFormat)
+{
+ tcu::TextureFormat texFormat = glu::mapGLInternalFormat(internalFormat);
+ glu::TransferFormat transFormat = glu::getTransferFormat(texFormat);
+
+ for (int l = 0; l < 2; ++l)
+ {
+ GLuint texSize = 32 / (l + 1);
+
+ std::vector<GLubyte> vecData;
+ vecData.resize(texSize * texSize * texFormat.getPixelSize() * 2);
+
+ tcu::PixelBufferAccess bufferAccess(texFormat, texSize, texSize, 1, vecData.data());
+
+ for (GLuint x = 0; x < texSize; ++x)
+ {
+ for (GLuint y = 0; y < texSize; ++y)
+ {
+ int value = ((x * (l + 1)) % 8 < 4) ? 255 : 0;
+ tcu::RGBA rgbaColor(value, value, value, 255);
+ tcu::Vec4 color = rgbaColor.toVec();
+ bufferAccess.setPixel(color, x, y);
+ }
+ }
+
+ TextureFilterAnisotropicUtils::texImage(gl, target, l, internalFormat, texSize, texSize, 1, transFormat.format,
+ transFormat.dataType, vecData.data());
+ }
+}
+
+/** Render polygon with anisotropic filtering.
+ *
+ * @param gl OpenGL functions wrapper
+ * @param target Texture target
+ * @param anisoDegree Degree of anisotropy
+ *
+ * @return Returns true if no error occured, false otherwise.
+ */
+bool TextureFilterAnisotropicDrawingTestCase::drawTexture(const glw::Functions& gl, GLenum target, GLfloat anisoDegree)
+{
+ const GLfloat vertices2[] = { -1.0f, 0.0f, -0.5f, 0.0f, 0.0f, -4.0f, 4.0f, -2.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, -0.5f, 1.0f, 0.0f, -2.0f, 4.0f, -2.0f, 1.0f, 1.0f };
+ const GLfloat vertices3[] = { -1.0f, 0.0f, -0.5f, 0.0f, 0.0f, 0.0f, -4.0f, 4.0f, -2.0f, 0.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, -0.5f, 1.0f, 0.0f, 0.0f, -2.0f, 4.0f, -2.0f, 1.0f, 1.0f, 0.0f };
+
+ // Projection values.
+ const GLfloat projectionMatrix[] = { 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f,
+ 0.0f, 0.0f, -2.5f / 1.5f, -2.0f / 1.5f, 0.0f, 0.0f, -1.0f, 0.0f };
+
+ gl.viewport(0, 0, 32, 32);
+
+ std::string vertexShader = m_vertex;
+ std::string fragmentShader = m_fragment;
+
+ std::string texCoordType;
+ std::string samplerType;
+ TextureFilterAnisotropicUtils::generateTokens(target, texCoordType, samplerType);
+
+ TextureFilterAnisotropicUtils::replaceToken("<TEXCOORD_TYPE>", texCoordType.c_str(), vertexShader);
+ TextureFilterAnisotropicUtils::replaceToken("<TEXCOORD_TYPE>", texCoordType.c_str(), fragmentShader);
+ TextureFilterAnisotropicUtils::replaceToken("<SAMPLER_TYPE>", samplerType.c_str(), vertexShader);
+ TextureFilterAnisotropicUtils::replaceToken("<SAMPLER_TYPE>", samplerType.c_str(), fragmentShader);
+
+ if (glu::isContextTypeGLCore(m_context.getRenderContext().getType()))
+ {
+ TextureFilterAnisotropicUtils::replaceToken("<VERSION>", "130", vertexShader);
+ TextureFilterAnisotropicUtils::replaceToken("<VERSION>", "130", fragmentShader);
+ }
+ else
+ {
+ TextureFilterAnisotropicUtils::replaceToken("<VERSION>", "300 es", vertexShader);
+ TextureFilterAnisotropicUtils::replaceToken("<VERSION>", "300 es", fragmentShader);
+ }
+
+ ProgramSources sources = makeVtxFragSources(vertexShader, fragmentShader);
+ ShaderProgram program(gl, sources);
+
+ if (!program.isOk())
+ {
+ m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n"
+ << "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
+ << vertexShader << "\n"
+ << "Fragment: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
+ << fragmentShader << "\n"
+ << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
+ return false;
+ }
+
+ GLuint vao;
+ gl.genVertexArrays(1, &vao);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays");
+ gl.bindVertexArray(vao);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray");
+
+ GLuint vbo;
+ gl.genBuffers(1, &vbo);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+ gl.bindBuffer(GL_ARRAY_BUFFER, vbo);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+ std::vector<GLfloat> vboData;
+ vboData.resize(24);
+
+ GLuint texCoordDim;
+ if (texCoordType == "vec2")
+ {
+ texCoordDim = 2;
+ deMemcpy((void*)vboData.data(), (void*)vertices2, sizeof(vertices2));
+ }
+ else
+ {
+ texCoordDim = 3;
+ deMemcpy((void*)vboData.data(), (void*)vertices3, sizeof(vertices3));
+ }
+
+ gl.bufferData(GL_ARRAY_BUFFER, vboData.size() * sizeof(GLfloat), (GLvoid*)vboData.data(), GL_DYNAMIC_DRAW);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+ gl.useProgram(program.getProgram());
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
+
+ GLuint matrixLocation = gl.getUniformLocation(program.getProgram(), "projectionMatrix");
+ GLuint texLocation = gl.getUniformLocation(program.getProgram(), "tex");
+
+ gl.activeTexture(GL_TEXTURE0);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture");
+ gl.bindTexture(target, m_texture);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture");
+ gl.uniformMatrix4fv(matrixLocation, 1, GL_FALSE, projectionMatrix);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformMatrix4fv");
+ gl.uniform1i(texLocation, 0);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i");
+
+ gl.texParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoDegree);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "texParameterfv");
+
+ gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor");
+ gl.clear(GL_COLOR_BUFFER_BIT);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glClear");
+
+ gl.enableVertexAttribArray(0);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray");
+ gl.enableVertexAttribArray(1);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray");
+
+ GLint attrLocationVertex = gl.getAttribLocation(program.getProgram(), "vertex");
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation");
+ GLint attrLocationInTexCoord = gl.getAttribLocation(program.getProgram(), "inTexCoord");
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation");
+
+ GLuint strideSize = (3 + texCoordDim) * sizeof(GLfloat);
+ gl.vertexAttribPointer(attrLocationVertex, 3, GL_FLOAT, GL_FALSE, strideSize, DE_NULL);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer");
+ gl.vertexAttribPointer(attrLocationInTexCoord, texCoordDim, GL_FLOAT, GL_FALSE, strideSize,
+ (GLvoid*)(3 * sizeof(GLfloat)));
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer");
+
+ gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray");
+
+ gl.disableVertexAttribArray(0);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray");
+ gl.disableVertexAttribArray(1);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray");
+
+ if (vbo)
+ {
+ gl.deleteBuffers(1, &vbo);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers");
+ }
+
+ if (vao)
+ {
+ gl.deleteVertexArrays(1, &vao);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays");
+ }
+
+ return true;
+}
+
+/** Verify rendered polygon anisotropy.
+ *
+ * @param gl OpenGL functions wrapper
+ *
+ * @return Returns points value. Less points means better anisotropy (smoother strips).
+ */
+GLuint TextureFilterAnisotropicDrawingTestCase::verifyScene(const glw::Functions& gl)
+{
+ std::vector<GLubyte> pixels;
+ pixels.resize(32 * 8 * 4);
+
+ gl.readPixels(0, 23, 32, 8, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+ GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels");
+
+ GLuint sum = 0;
+
+ GLubyte last = 0;
+ GLubyte current = 0;
+ for (int j = 0; j < 8; ++j)
+ {
+ for (int i = 0; i < 32; ++i)
+ {
+ current = pixels[(i + j * 32) * 4];
+
+ if (i > 0)
+ sum += deAbs32((int)current - (int)last);
+
+ last = current;
+ }
+ }
+
+ return sum;
+}
+
+/** Release texture.
+ *
+ * @param gl OpenGL functions wrapper
+ */
+void TextureFilterAnisotropicDrawingTestCase::releaseTexture(const glw::Functions& gl)
+{
+ if (m_texture)
+ gl.deleteTextures(1, &m_texture);
+
+ m_texture = 0;
+}
+
+/** Constructor.
+ *
+ * @param context Rendering context.
+ */
+TextureFilterAnisotropicTests::TextureFilterAnisotropicTests(deqp::Context& context)
+ : TestCaseGroup(context, "texture_filter_anisotropic",
+ "Verify conformance of CTS_EXT_texture_filter_anisotropic implementation")
+{
+}
+
+/** Initializes the test group contents. */
+void TextureFilterAnisotropicTests::init()
+{
+ addChild(new TextureFilterAnisotropicQueriesTestCase(m_context));
+ addChild(new TextureFilterAnisotropicDrawingTestCase(m_context));
+}
+
+} /* glcts namespace */