/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES 3.1 Module
 * -------------------------------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * 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 Integer state query tests
 *//*--------------------------------------------------------------------*/

#include "es31fIntegerStateQueryTests.hpp"
#include "tcuTestLog.hpp"
#include "gluRenderContext.hpp"
#include "gluCallLogWrapper.hpp"
#include "gluContextInfo.hpp"
#include "gluObjectWrapper.hpp"
#include "gluShaderProgram.hpp"
#include "gluStrUtil.hpp"
#include "glwFunctions.hpp"
#include "glwEnums.hpp"
#include "glsStateQueryUtil.hpp"
#include "deRandom.hpp"
#include "deStringUtil.hpp"

namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace
{

using namespace gls::StateQueryUtil;

const int MAX_FRAG_ATOMIC_COUNTER_BUFFERS_GLES32 = 1;
const int MAX_FRAG_ATOMIC_COUNTERS_GLES32        = 8;
const int MAX_FRAG_SHADER_STORAGE_BLOCKS_GLES32  = 4;

static const char *getVerifierSuffix(QueryType type)
{
    switch (type)
    {
    case QUERY_BOOLEAN:
        return "getboolean";
    case QUERY_INTEGER:
        return "getinteger";
    case QUERY_INTEGER64:
        return "getinteger64";
    case QUERY_FLOAT:
        return "getfloat";
    default:
        DE_ASSERT(false);
        return DE_NULL;
    }
}

class MaxSamplesCase : public TestCase
{
public:
    MaxSamplesCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                   QueryType verifierType);

private:
    IterateResult iterate(void);

    const glw::GLenum m_target;
    const int m_minValue;
    const QueryType m_verifierType;
};

MaxSamplesCase::MaxSamplesCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                               QueryType verifierType)
    : TestCase(context, name, desc)
    , m_target(target)
    , m_minValue(minValue)
    , m_verifierType(verifierType)
{
}

MaxSamplesCase::IterateResult MaxSamplesCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    gl.enableLogging(true);
    verifyStateIntegerMin(result, gl, m_target, m_minValue, m_verifierType);

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class TexBindingCase : public TestCase
{
public:
    TexBindingCase(Context &context, const char *name, const char *desc, glw::GLenum texTarget, glw::GLenum bindTarget,
                   QueryType verifierType);

private:
    void init(void);
    IterateResult iterate(void);

    const glw::GLenum m_texTarget;
    const glw::GLenum m_bindTarget;
    const QueryType m_verifierType;
};

TexBindingCase::TexBindingCase(Context &context, const char *name, const char *desc, glw::GLenum texTarget,
                               glw::GLenum bindTarget, QueryType verifierType)
    : TestCase(context, name, desc)
    , m_texTarget(texTarget)
    , m_bindTarget(bindTarget)
    , m_verifierType(verifierType)
{
}

void TexBindingCase::init(void)
{
    auto ctxType = m_context.getRenderContext().getType();
    if (contextSupports(ctxType, glu::ApiType::es(3, 2)) || contextSupports(ctxType, glu::ApiType::core(4, 5)))
        return;

    if (m_texTarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY &&
        !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
        throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension");
    if (m_texTarget == GL_TEXTURE_CUBE_MAP_ARRAY &&
        !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
        throw tcu::NotSupportedError("Test requires GL_EXT_texture_cube_map_array extension");
    if (m_texTarget == GL_TEXTURE_BUFFER && !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_buffer"))
        throw tcu::NotSupportedError("Test requires GL_EXT_texture_buffer extension");
}

TexBindingCase::IterateResult TexBindingCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    gl.enableLogging(true);

    // initial
    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "initial", "Initial value");

        verifyStateInteger(result, gl, m_bindTarget, 0, m_verifierType);
    }

    // bind
    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "bind", "After bind");

        glw::GLuint texture;

        gl.glGenTextures(1, &texture);
        gl.glBindTexture(m_texTarget, texture);
        GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "bind texture");

        verifyStateInteger(result, gl, m_bindTarget, texture, m_verifierType);

        gl.glDeleteTextures(1, &texture);
    }

    // after delete
    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "bind", "After delete");

        verifyStateInteger(result, gl, m_bindTarget, 0, m_verifierType);
    }

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class MinimumValueCase : public TestCase
{
public:
    MinimumValueCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                     QueryType verifierType);
    MinimumValueCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                     QueryType verifierType, glu::ApiType minVersion);

private:
    IterateResult iterate(void);

    const glw::GLenum m_target;
    const int m_minValue;
    const QueryType m_verifierType;
    const glu::ApiType m_minimumVersion;
};

MinimumValueCase::MinimumValueCase(Context &context, const char *name, const char *desc, glw::GLenum target,
                                   int minValue, QueryType verifierType)
    : TestCase(context, name, desc)
    , m_target(target)
    , m_minValue(minValue)
    , m_verifierType(verifierType)
    , m_minimumVersion(glu::ApiType::es(3, 1))
{
}

MinimumValueCase::MinimumValueCase(Context &context, const char *name, const char *desc, glw::GLenum target,
                                   int minValue, QueryType verifierType, glu::ApiType minVersion)
    : TestCase(context, name, desc)
    , m_target(target)
    , m_minValue(minValue)
    , m_verifierType(verifierType)
    , m_minimumVersion(minVersion)
{
}

MinimumValueCase::IterateResult MinimumValueCase::iterate(void)
{
    if (!contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
        TCU_CHECK_AND_THROW(NotSupportedError,
                            contextSupports(m_context.getRenderContext().getType(), m_minimumVersion),
                            "Test not supported in this context version.");

    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    // \note: In GL ES 3.2, the following targets have different limits as in 3.1
    const int value =
        contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ?
            (m_target == GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS ? MAX_FRAG_ATOMIC_COUNTER_BUFFERS_GLES32 // 1
             :
             m_target == GL_MAX_FRAGMENT_ATOMIC_COUNTERS ? MAX_FRAG_ATOMIC_COUNTERS_GLES32 // 8
             :
             m_target == GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS ? MAX_FRAG_SHADER_STORAGE_BLOCKS_GLES32 // 4
                                                                 :
                                                                 m_minValue) :
            m_minValue;

    gl.enableLogging(true);
    verifyStateIntegerMin(result, gl, m_target, value, m_verifierType);

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class AlignmentCase : public TestCase
{
public:
    AlignmentCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                  QueryType verifierType);
    AlignmentCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                  QueryType verifierType, glu::ApiType minVersion);

private:
    IterateResult iterate(void);

    const glw::GLenum m_target;
    const int m_minValue;
    const QueryType m_verifierType;
    const glu::ApiType m_minimumVersion;
};

AlignmentCase::AlignmentCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                             QueryType verifierType)
    : TestCase(context, name, desc)
    , m_target(target)
    , m_minValue(minValue)
    , m_verifierType(verifierType)
    , m_minimumVersion(glu::ApiType::es(3, 1))
{
}

AlignmentCase::AlignmentCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                             QueryType verifierType, glu::ApiType minVersion)
    : TestCase(context, name, desc)
    , m_target(target)
    , m_minValue(minValue)
    , m_verifierType(verifierType)
    , m_minimumVersion(minVersion)
{
}

AlignmentCase::IterateResult AlignmentCase::iterate(void)
{
    if (!contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
        TCU_CHECK_AND_THROW(NotSupportedError,
                            contextSupports(m_context.getRenderContext().getType(), m_minimumVersion),
                            "Test not supported in this context.");

    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    gl.enableLogging(true);
    verifyStateIntegerMax(result, gl, m_target, m_minValue, m_verifierType);

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class BufferBindingCase : public TestCase
{
public:
    BufferBindingCase(Context &context, const char *name, const char *desc, glw::GLenum queryTarget,
                      glw::GLenum bindingPoint, QueryType verifierType);

private:
    IterateResult iterate(void);

    const glw::GLenum m_queryTarget;
    const glw::GLenum m_bindingPoint;
    const QueryType m_verifierType;
};

BufferBindingCase::BufferBindingCase(Context &context, const char *name, const char *desc, glw::GLenum queryTarget,
                                     glw::GLenum bindingPoint, QueryType verifierType)
    : TestCase(context, name, desc)
    , m_queryTarget(queryTarget)
    , m_bindingPoint(bindingPoint)
    , m_verifierType(verifierType)
{
}

BufferBindingCase::IterateResult BufferBindingCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    gl.enableLogging(true);

    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial value");

        verifyStateInteger(result, gl, m_queryTarget, 0, m_verifierType);
    }

    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "AfterBinding", "After binding");
        glu::Buffer buf(m_context.getRenderContext());

        gl.glBindBuffer(m_bindingPoint, *buf);
        GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "setup");

        verifyStateInteger(result, gl, m_queryTarget, *buf, m_verifierType);
    }

    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "AfterDelete", "After deleting");
        glw::GLuint buf = 0;

        gl.glGenBuffers(1, &buf);
        gl.glBindBuffer(m_bindingPoint, buf);
        gl.glDeleteBuffers(1, &buf);
        GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "setup");

        verifyStateInteger(result, gl, m_queryTarget, 0, m_verifierType);
    }

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class ProgramPipelineBindingCase : public TestCase
{
public:
    ProgramPipelineBindingCase(Context &context, const char *name, const char *desc, QueryType verifierType);

private:
    IterateResult iterate(void);

    const QueryType m_verifierType;
};

ProgramPipelineBindingCase::ProgramPipelineBindingCase(Context &context, const char *name, const char *desc,
                                                       QueryType verifierType)
    : TestCase(context, name, desc)
    , m_verifierType(verifierType)
{
}

ProgramPipelineBindingCase::IterateResult ProgramPipelineBindingCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    gl.enableLogging(true);

    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial value");

        verifyStateInteger(result, gl, GL_PROGRAM_PIPELINE_BINDING, 0, m_verifierType);
    }

    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "AfterBinding", "After binding");
        glu::ProgramPipeline pipeline(m_context.getRenderContext());

        gl.glBindProgramPipeline(pipeline.getPipeline());
        GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "setup");

        verifyStateInteger(result, gl, GL_PROGRAM_PIPELINE_BINDING, pipeline.getPipeline(), m_verifierType);
    }

    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "AfterDelete", "After deleting");
        glw::GLuint pipeline = 0;

        gl.glGenProgramPipelines(1, &pipeline);
        gl.glBindProgramPipeline(pipeline);
        gl.glDeleteProgramPipelines(1, &pipeline);
        GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "setup");

        verifyStateInteger(result, gl, GL_PROGRAM_PIPELINE_BINDING, 0, m_verifierType);
    }

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class FramebufferMinimumValueCase : public TestCase
{
public:
    FramebufferMinimumValueCase(Context &context, const char *name, const char *desc, glw::GLenum target, int minValue,
                                glw::GLenum tiedTo, QueryType verifierType);

private:
    IterateResult iterate(void);

    const glw::GLenum m_target;
    const glw::GLenum m_tiedTo;
    const int m_minValue;
    const QueryType m_verifierType;
};

FramebufferMinimumValueCase::FramebufferMinimumValueCase(Context &context, const char *name, const char *desc,
                                                         glw::GLenum target, int minValue, glw::GLenum tiedTo,
                                                         QueryType verifierType)
    : TestCase(context, name, desc)
    , m_target(target)
    , m_tiedTo(tiedTo)
    , m_minValue(minValue)
    , m_verifierType(verifierType)
{
}

FramebufferMinimumValueCase::IterateResult FramebufferMinimumValueCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    gl.enableLogging(true);

    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "Minimum",
                                            "Specified minimum is " + de::toString(m_minValue));

        verifyStateIntegerMin(result, gl, m_target, m_minValue, m_verifierType);
    }
    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "Ties",
                                            "The limit is tied to the value of " +
                                                de::toString(glu::getGettableStateStr(m_tiedTo)));
        StateQueryMemoryWriteGuard<glw::GLint> tiedToValue;

        gl.glGetIntegerv(m_tiedTo, &tiedToValue);
        GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");

        if (tiedToValue.verifyValidity(result))
            verifyStateIntegerMin(result, gl, m_target, tiedToValue, m_verifierType);
    }

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class LegacyVectorLimitCase : public TestCase
{
public:
    LegacyVectorLimitCase(Context &context, const char *name, const char *desc, glw::GLenum legacyTarget,
                          glw::GLenum componentTarget, QueryType verifierType);

private:
    IterateResult iterate(void);

    const glw::GLenum m_legacyTarget;
    const glw::GLenum m_componentTarget;
    const QueryType m_verifierType;
};

LegacyVectorLimitCase::LegacyVectorLimitCase(Context &context, const char *name, const char *desc,
                                             glw::GLenum legacyTarget, glw::GLenum componentTarget,
                                             QueryType verifierType)
    : TestCase(context, name, desc)
    , m_legacyTarget(legacyTarget)
    , m_componentTarget(componentTarget)
    , m_verifierType(verifierType)
{
}

LegacyVectorLimitCase::IterateResult LegacyVectorLimitCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    gl.enableLogging(true);

    {
        const tcu::ScopedLogSection section(m_testCtx.getLog(), "TiedTo",
                                            de::toString(glu::getGettableStateStr(m_legacyTarget)) + " is " +
                                                de::toString(glu::getGettableStateStr(m_componentTarget)) +
                                                " divided by four");

        StateQueryMemoryWriteGuard<glw::GLint> value;
        gl.glGetIntegerv(m_componentTarget, &value);
        GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");

        if (value.verifyValidity(result))
            verifyStateInteger(result, gl, m_legacyTarget, ((int)value) / 4, m_verifierType);
    }

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class CombinedUniformComponentsCase : public TestCase
{
public:
    CombinedUniformComponentsCase(Context &context, const char *name, const char *desc, glw::GLenum target,
                                  QueryType verifierType);
    CombinedUniformComponentsCase(Context &context, const char *name, const char *desc, glw::GLenum target,
                                  QueryType verifierType, glu::ApiType minVersion);

private:
    IterateResult iterate(void);
    const glw::GLenum m_target;
    const QueryType m_verifierType;
    const glu::ApiType m_minimumVersion;
};

CombinedUniformComponentsCase::CombinedUniformComponentsCase(Context &context, const char *name, const char *desc,
                                                             glw::GLenum target, QueryType verifierType)
    : TestCase(context, name, desc)
    , m_target(target)
    , m_verifierType(verifierType)
    , m_minimumVersion(glu::ApiType::es(3, 1))
{
}

CombinedUniformComponentsCase::CombinedUniformComponentsCase(Context &context, const char *name, const char *desc,
                                                             glw::GLenum target, QueryType verifierType,
                                                             glu::ApiType minVersion)
    : TestCase(context, name, desc)
    , m_target(target)
    , m_verifierType(verifierType)
    , m_minimumVersion(minVersion)
{
}

CombinedUniformComponentsCase::IterateResult CombinedUniformComponentsCase::iterate(void)
{
    if (!contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
        TCU_CHECK_AND_THROW(NotSupportedError,
                            contextSupports(m_context.getRenderContext().getType(), m_minimumVersion),
                            "Test not supported in this context.");

    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    const glw::GLenum maxUniformBlocksEnum =
        (m_target == GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS)         ? GL_MAX_COMPUTE_UNIFORM_BLOCKS :
        (m_target == GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS)    ? GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS :
        (m_target == GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS) ? GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS :
        (m_target == GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS)        ? GL_MAX_GEOMETRY_UNIFORM_BLOCKS :
                                                                           -1;

    const glw::GLenum maxUniformComponentsEnum =
        (m_target == GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS)         ? GL_MAX_COMPUTE_UNIFORM_COMPONENTS :
        (m_target == GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS)    ? GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS :
        (m_target == GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS) ? GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS :
        (m_target == GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS)        ? GL_MAX_GEOMETRY_UNIFORM_COMPONENTS :
                                                                           -1;

    gl.enableLogging(true);

    m_testCtx.getLog() << tcu::TestLog::Message
                       << "The minimum value of MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS is MAX_COMPUTE_UNIFORM_BLOCKS "
                          "x MAX_UNIFORM_BLOCK_SIZE / 4 + MAX_COMPUTE_UNIFORM_COMPONENTS"
                       << tcu::TestLog::EndMessage;

    StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlocks;
    gl.glGetIntegerv(maxUniformBlocksEnum, &maxUniformBlocks);
    GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");

    StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlockSize;
    gl.glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
    GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");

    StateQueryMemoryWriteGuard<glw::GLint> maxUniformComponents;
    gl.glGetIntegerv(maxUniformComponentsEnum, &maxUniformComponents);
    GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");

    if (maxUniformBlocks.verifyValidity(result) && maxUniformBlockSize.verifyValidity(result) &&
        maxUniformComponents.verifyValidity(result))
        verifyStateIntegerMin(result, gl, m_target,
                              ((int)maxUniformBlocks) * ((int)maxUniformBlockSize) / 4 + (int)maxUniformComponents,
                              m_verifierType);

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class TextureGatherLimitCase : public TestCase
{
public:
    TextureGatherLimitCase(Context &context, const char *name, const char *desc, bool isMaxCase,
                           QueryType verifierType);

private:
    IterateResult iterate(void);

    const bool m_isMaxCase;
    const QueryType m_verifierType;
};

TextureGatherLimitCase::TextureGatherLimitCase(Context &context, const char *name, const char *desc, bool isMaxCase,
                                               QueryType verifierType)
    : TestCase(context, name, desc)
    , m_isMaxCase(isMaxCase)
    , m_verifierType(verifierType)
{
}

TextureGatherLimitCase::IterateResult TextureGatherLimitCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");

    gl.enableLogging(true);

    if (m_isMaxCase)
    {
        // range [0, inf)
        verifyStateIntegerMin(result, gl, GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, 0, m_verifierType);
    }
    else
    {
        // range (-inf, 0]
        verifyStateIntegerMax(result, gl, GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, 0, m_verifierType);
    }

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class MaxUniformBufferBindingsCase : public TestCase
{
public:
    MaxUniformBufferBindingsCase(Context &context, const char *name, const char *desc, QueryType verifierType);

private:
    IterateResult iterate(void);

    const QueryType m_verifierType;
};

MaxUniformBufferBindingsCase::MaxUniformBufferBindingsCase(Context &context, const char *name, const char *desc,
                                                           QueryType verifierType)
    : TestCase(context, name, desc)
    , m_verifierType(verifierType)
{
}

MaxUniformBufferBindingsCase::IterateResult MaxUniformBufferBindingsCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
    int minMax;

    gl.enableLogging(true);

    if (contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
    {
        minMax = 72;
    }
    else
    {
        if (m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
        {
            m_testCtx.getLog()
                << tcu::TestLog::Message
                << "GL_EXT_tessellation_shader increases the minimum value of GL_MAX_UNIFORM_BUFFER_BINDINGS to 72"
                << tcu::TestLog::EndMessage;
            minMax = 72;
        }
        else if (m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
        {
            m_testCtx.getLog()
                << tcu::TestLog::Message
                << "GL_EXT_geometry_shader increases the minimum value of GL_MAX_UNIFORM_BUFFER_BINDINGS to 48"
                << tcu::TestLog::EndMessage;
            minMax = 48;
        }
        else
        {
            minMax = 36;
        }
    }

    // range [0, inf)
    verifyStateIntegerMin(result, gl, GL_MAX_UNIFORM_BUFFER_BINDINGS, minMax, m_verifierType);

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class MaxCombinedUniformBlocksCase : public TestCase
{
public:
    MaxCombinedUniformBlocksCase(Context &context, const char *name, const char *desc, QueryType verifierType);

private:
    IterateResult iterate(void);

    const QueryType m_verifierType;
};

MaxCombinedUniformBlocksCase::MaxCombinedUniformBlocksCase(Context &context, const char *name, const char *desc,
                                                           QueryType verifierType)
    : TestCase(context, name, desc)
    , m_verifierType(verifierType)
{
}

MaxCombinedUniformBlocksCase::IterateResult MaxCombinedUniformBlocksCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
    int minMax;

    gl.enableLogging(true);

    if (contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
    {
        minMax = 60;
    }
    else
    {
        if (m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
        {
            m_testCtx.getLog()
                << tcu::TestLog::Message
                << "GL_EXT_tessellation_shader increases the minimum value of GL_MAX_COMBINED_UNIFORM_BLOCKS to 60"
                << tcu::TestLog::EndMessage;
            minMax = 60;
        }
        else if (m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
        {
            m_testCtx.getLog()
                << tcu::TestLog::Message
                << "GL_EXT_geometry_shader increases the minimum value of GL_MAX_COMBINED_UNIFORM_BLOCKS to 36"
                << tcu::TestLog::EndMessage;
            minMax = 36;
        }
        else
        {
            minMax = 24;
        }
    }

    // range [0, inf)
    verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_UNIFORM_BLOCKS, minMax, m_verifierType);

    result.setTestContextResult(m_testCtx);
    return STOP;
}

class MaxCombinedTexImageUnitsCase : public TestCase
{
public:
    MaxCombinedTexImageUnitsCase(Context &context, const char *name, const char *desc, QueryType verifierType);

private:
    IterateResult iterate(void);

    const QueryType m_verifierType;
};

MaxCombinedTexImageUnitsCase::MaxCombinedTexImageUnitsCase(Context &context, const char *name, const char *desc,
                                                           QueryType verifierType)
    : TestCase(context, name, desc)
    , m_verifierType(verifierType)
{
}

MaxCombinedTexImageUnitsCase::IterateResult MaxCombinedTexImageUnitsCase::iterate(void)
{
    glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    tcu::ResultCollector result(m_testCtx.getLog(), " // ERROR: ");
    int minMax;

    gl.enableLogging(true);
    if (contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
    {
        minMax = 96;
    }
    else
    {
        if (m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
        {
            m_testCtx.getLog()
                << tcu::TestLog::Message
                << "GL_EXT_tessellation_shader increases the minimum value of GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS to 96"
                << tcu::TestLog::EndMessage;
            minMax = 96;
        }
        else if (m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
        {
            m_testCtx.getLog()
                << tcu::TestLog::Message
                << "GL_EXT_geometry_shader increases the minimum value of GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS to 36"
                << tcu::TestLog::EndMessage;
            minMax = 64;
        }
        else
        {
            minMax = 48;
        }
    }

    // range [0, inf)
    verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, minMax, m_verifierType);

    result.setTestContextResult(m_testCtx);
    return STOP;
}

} // namespace

IntegerStateQueryTests::IntegerStateQueryTests(Context &context)
    : TestCaseGroup(context, "integer", "Integer state query tests")
{
}

IntegerStateQueryTests::~IntegerStateQueryTests(void)
{
}

void IntegerStateQueryTests::init(void)
{
    // Verifiers
    const QueryType verifiers[] = {QUERY_BOOLEAN, QUERY_INTEGER, QUERY_INTEGER64, QUERY_FLOAT};

#define FOR_EACH_VERIFIER(X)                                                              \
    for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(verifiers); ++verifierNdx) \
    {                                                                                     \
        const char *verifierSuffix = getVerifierSuffix(verifiers[verifierNdx]);           \
        const QueryType verifier   = verifiers[verifierNdx];                              \
        this->addChild(X);                                                                \
    }

    FOR_EACH_VERIFIER(
        new MaxSamplesCase(m_context, (std::string() + "max_color_texture_samples_" + verifierSuffix).c_str(),
                           "Test GL_MAX_COLOR_TEXTURE_SAMPLES", GL_MAX_COLOR_TEXTURE_SAMPLES, 1, verifier))
    FOR_EACH_VERIFIER(
        new MaxSamplesCase(m_context, (std::string() + "max_depth_texture_samples_" + verifierSuffix).c_str(),
                           "Test GL_MAX_DEPTH_TEXTURE_SAMPLES", GL_MAX_DEPTH_TEXTURE_SAMPLES, 1, verifier))
    FOR_EACH_VERIFIER(new MaxSamplesCase(m_context, (std::string() + "max_integer_samples_" + verifierSuffix).c_str(),
                                         "Test GL_MAX_INTEGER_SAMPLES", GL_MAX_INTEGER_SAMPLES, 1, verifier))

    FOR_EACH_VERIFIER(new TexBindingCase(
        m_context, (std::string() + "texture_binding_2d_multisample_" + verifierSuffix).c_str(),
        "Test TEXTURE_BINDING_2D_MULTISAMPLE", GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_BINDING_2D_MULTISAMPLE, verifier))
    FOR_EACH_VERIFIER(new TexBindingCase(
        m_context, (std::string() + "texture_binding_2d_multisample_array_" + verifierSuffix).c_str(),
        "Test TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY", GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
        GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, verifier))
    FOR_EACH_VERIFIER(new TexBindingCase(
        m_context, (std::string() + "texture_binding_cube_map_array_" + verifierSuffix).c_str(),
        "Test TEXTURE_BINDING_CUBE_MAP_ARRAY", GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, verifier))
    FOR_EACH_VERIFIER(
        new TexBindingCase(m_context, (std::string() + "texture_binding_buffer_" + verifierSuffix).c_str(),
                           "Test TEXTURE_BINDING_BUFFER", GL_TEXTURE_BUFFER, GL_TEXTURE_BINDING_BUFFER, verifier))

    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_vertex_attrib_relative_offset_" + verifierSuffix).c_str(),
        "Test MAX_VERTEX_ATTRIB_RELATIVE_OFFSET", GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, 2047, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_vertex_attrib_bindings_" + verifierSuffix).c_str(),
                             "Test MAX_VERTEX_ATTRIB_BINDINGS", GL_MAX_VERTEX_ATTRIB_BINDINGS, 16, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_vertex_attrib_stride_" + verifierSuffix).c_str(),
                             "Test MAX_VERTEX_ATTRIB_STRIDE", GL_MAX_VERTEX_ATTRIB_STRIDE, 2048, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(m_context,
                                           (std::string() + "max_sample_mask_words_" + verifierSuffix).c_str(),
                                           "Test MAX_SAMPLE_MASK_WORDS", GL_MAX_SAMPLE_MASK_WORDS, 1, verifier))

    FOR_EACH_VERIFIER(new AlignmentCase(
        m_context, (std::string() + "shader_storage_buffer_offset_alignment_" + verifierSuffix).c_str(),
        "Test SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT", GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, 256, verifier))

    FOR_EACH_VERIFIER(new BufferBindingCase(
        m_context, (std::string() + "draw_indirect_buffer_binding_" + verifierSuffix).c_str(),
        "Test DRAW_INDIRECT_BUFFER_BINDING", GL_DRAW_INDIRECT_BUFFER_BINDING, GL_DRAW_INDIRECT_BUFFER, verifier))
    FOR_EACH_VERIFIER(new BufferBindingCase(
        m_context, (std::string() + "atomic_counter_buffer_binding_" + verifierSuffix).c_str(),
        "Test ATOMIC_COUNTER_BUFFER_BINDING", GL_ATOMIC_COUNTER_BUFFER_BINDING, GL_ATOMIC_COUNTER_BUFFER, verifier))
    FOR_EACH_VERIFIER(new BufferBindingCase(
        m_context, (std::string() + "shader_storage_buffer_binding_" + verifierSuffix).c_str(),
        "Test SHADER_STORAGE_BUFFER_BINDING", GL_SHADER_STORAGE_BUFFER_BINDING, GL_SHADER_STORAGE_BUFFER, verifier))
    FOR_EACH_VERIFIER(
        new BufferBindingCase(m_context, (std::string() + "dispatch_indirect_buffer_binding_" + verifierSuffix).c_str(),
                              "Test DISPATCH_INDIRECT_BUFFER_BINDING", GL_DISPATCH_INDIRECT_BUFFER_BINDING,
                              GL_DISPATCH_INDIRECT_BUFFER, verifier))

    FOR_EACH_VERIFIER(new FramebufferMinimumValueCase(
        m_context, (std::string() + "max_framebuffer_width_" + verifierSuffix).c_str(), "Test MAX_FRAMEBUFFER_WIDTH",
        GL_MAX_FRAMEBUFFER_WIDTH, 2048, GL_MAX_TEXTURE_SIZE, verifier))
    FOR_EACH_VERIFIER(new FramebufferMinimumValueCase(
        m_context, (std::string() + "max_framebuffer_height_" + verifierSuffix).c_str(), "Test MAX_FRAMEBUFFER_HEIGHT",
        GL_MAX_FRAMEBUFFER_HEIGHT, 2048, GL_MAX_TEXTURE_SIZE, verifier))
    FOR_EACH_VERIFIER(new FramebufferMinimumValueCase(
        m_context, (std::string() + "max_framebuffer_samples_" + verifierSuffix).c_str(),
        "Test MAX_FRAMEBUFFER_SAMPLES", GL_MAX_FRAMEBUFFER_SAMPLES, 4, GL_MAX_SAMPLES, verifier))

    FOR_EACH_VERIFIER(new ProgramPipelineBindingCase(
        m_context, (std::string() + "program_pipeline_binding_" + verifierSuffix).c_str(),
        "Test PROGRAM_PIPELINE_BINDING", verifier))

    // vertex
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_vertex_atomic_counter_buffers_" + verifierSuffix).c_str(),
        "Test MAX_VERTEX_ATOMIC_COUNTER_BUFFERS", GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, 0, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_vertex_atomic_counters_" + verifierSuffix).c_str(),
                             "Test MAX_VERTEX_ATOMIC_COUNTERS", GL_MAX_VERTEX_ATOMIC_COUNTERS, 0, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(m_context,
                                           (std::string() + "max_vertex_image_uniforms_" + verifierSuffix).c_str(),
                                           "Test MAX_VERTEX_IMAGE_UNIFORMS", GL_MAX_VERTEX_IMAGE_UNIFORMS, 0, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_vertex_shader_storage_blocks_" + verifierSuffix).c_str(),
                             "Test MAX_VERTEX_SHADER_STORAGE_BLOCKS", GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, 0, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_vertex_uniform_components_" + verifierSuffix).c_str(),
                             "Test MAX_VERTEX_UNIFORM_COMPONENTS", GL_MAX_VERTEX_UNIFORM_COMPONENTS, 1024, verifier))

    // fragment
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_fragment_atomic_counter_buffers_" + verifierSuffix).c_str(),
        "Test MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS", GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, 0, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_fragment_atomic_counters_" + verifierSuffix).c_str(),
                             "Test MAX_FRAGMENT_ATOMIC_COUNTERS", GL_MAX_FRAGMENT_ATOMIC_COUNTERS, 0, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_fragment_image_uniforms_" + verifierSuffix).c_str(),
                             "Test MAX_FRAGMENT_IMAGE_UNIFORMS", GL_MAX_FRAGMENT_IMAGE_UNIFORMS, 0, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_fragment_shader_storage_blocks_" + verifierSuffix).c_str(),
        "Test MAX_FRAGMENT_SHADER_STORAGE_BLOCKS", GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, 0, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_fragment_uniform_components_" + verifierSuffix).c_str(),
        "Test MAX_FRAGMENT_UNIFORM_COMPONENTS", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, 1024, verifier))

    // compute
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_compute_work_group_invocations_" + verifierSuffix).c_str(),
        "Test MAX_COMPUTE_WORK_GROUP_INVOCATIONS", GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, 128, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_compute_uniform_blocks_" + verifierSuffix).c_str(),
                             "Test MAX_COMPUTE_UNIFORM_BLOCKS", GL_MAX_COMPUTE_UNIFORM_BLOCKS, 12, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_compute_texture_image_units_" + verifierSuffix).c_str(),
                             "Test MAX_COMPUTE_TEXTURE_IMAGE_UNITS", GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, 16, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_compute_shared_memory_size_" + verifierSuffix).c_str(),
                             "Test MAX_COMPUTE_SHARED_MEMORY_SIZE", GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, 16384, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_compute_uniform_components_" + verifierSuffix).c_str(),
                             "Test MAX_COMPUTE_UNIFORM_COMPONENTS", GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 1024, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_compute_atomic_counter_buffers_" + verifierSuffix).c_str(),
        "Test MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS", GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, 1, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_compute_atomic_counters_" + verifierSuffix).c_str(),
                             "Test MAX_COMPUTE_ATOMIC_COUNTERS", GL_MAX_COMPUTE_ATOMIC_COUNTERS, 8, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_compute_image_uniforms_" + verifierSuffix).c_str(),
                             "Test MAX_COMPUTE_IMAGE_UNIFORMS", GL_MAX_COMPUTE_IMAGE_UNIFORMS, 4, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_compute_shader_storage_blocks_" + verifierSuffix).c_str(),
        "Test MAX_COMPUTE_SHADER_STORAGE_BLOCKS", GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, 4, verifier))

    FOR_EACH_VERIFIER(new MinimumValueCase(m_context,
                                           (std::string() + "max_uniform_locations_" + verifierSuffix).c_str(),
                                           "Test MAX_UNIFORM_LOCATIONS", GL_MAX_UNIFORM_LOCATIONS, 1024, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_atomic_counter_buffer_bindings_" + verifierSuffix).c_str(),
        "Test MAX_ATOMIC_COUNTER_BUFFER_BINDINGS", GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, 1, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_atomic_counter_buffer_size_" + verifierSuffix).c_str(),
                             "Test MAX_ATOMIC_COUNTER_BUFFER_SIZE", GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, 32, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_combined_atomic_counter_buffers_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_ATOMIC_COUNTER_BUFFERS", GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, 1, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_combined_atomic_counters_" + verifierSuffix).c_str(),
                             "Test MAX_COMBINED_ATOMIC_COUNTERS", GL_MAX_COMBINED_ATOMIC_COUNTERS, 8, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(m_context, (std::string() + "max_image_units_" + verifierSuffix).c_str(),
                                           "Test MAX_IMAGE_UNITS", GL_MAX_IMAGE_UNITS, 4, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_combined_image_uniforms_" + verifierSuffix).c_str(),
                             "Test MAX_COMBINED_IMAGE_UNIFORMS", GL_MAX_COMBINED_IMAGE_UNIFORMS, 4, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_shader_storage_buffer_bindings_" + verifierSuffix).c_str(),
        "Test MAX_SHADER_STORAGE_BUFFER_BINDINGS", GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, 4, verifier))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_shader_storage_block_size_" + verifierSuffix).c_str(),
                             "Test MAX_SHADER_STORAGE_BLOCK_SIZE", GL_MAX_SHADER_STORAGE_BLOCK_SIZE, 1 << 27, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_combined_shader_storage_blocks_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_SHADER_STORAGE_BLOCKS", GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, 4, verifier))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_combined_shader_output_resources_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_SHADER_OUTPUT_RESOURCES", GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, 4, verifier))

    FOR_EACH_VERIFIER(new MaxUniformBufferBindingsCase(
        m_context, (std::string() + "max_uniform_buffer_bindings_" + verifierSuffix).c_str(),
        "Test MAX_UNIFORM_BUFFER_BINDINGS", verifier))
    FOR_EACH_VERIFIER(new MaxCombinedUniformBlocksCase(
        m_context, (std::string() + "max_combined_uniform_blocks_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_UNIFORM_BLOCKS", verifier))
    FOR_EACH_VERIFIER(new MaxCombinedTexImageUnitsCase(
        m_context, (std::string() + "max_combined_texture_image_units_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_TEXTURE_IMAGE_UNITS", verifier))
    FOR_EACH_VERIFIER(new CombinedUniformComponentsCase(
        m_context, (std::string() + "max_combined_compute_uniform_components_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS", GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, verifier))

    FOR_EACH_VERIFIER(new LegacyVectorLimitCase(
        m_context, (std::string() + "max_vertex_uniform_vectors_" + verifierSuffix).c_str(),
        "Test MAX_VERTEX_UNIFORM_VECTORS", GL_MAX_VERTEX_UNIFORM_VECTORS, GL_MAX_VERTEX_UNIFORM_COMPONENTS, verifier))
    FOR_EACH_VERIFIER(
        new LegacyVectorLimitCase(m_context, (std::string() + "max_fragment_uniform_vectors_" + verifierSuffix).c_str(),
                                  "Test MAX_FRAGMENT_UNIFORM_VECTORS", GL_MAX_FRAGMENT_UNIFORM_VECTORS,
                                  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, verifier))

    FOR_EACH_VERIFIER(new TextureGatherLimitCase(
        m_context, (std::string() + "min_program_texture_gather_offset_" + verifierSuffix).c_str(),
        "Test MIN_PROGRAM_TEXTURE_GATHER_OFFSET", false, verifier))
    FOR_EACH_VERIFIER(new TextureGatherLimitCase(
        m_context, (std::string() + "max_program_texture_gather_offset_" + verifierSuffix).c_str(),
        "Test MAX_PROGRAM_TEXTURE_GATHER_OFFSET", true, verifier))

    // GL ES 3.2 tests
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_framebuffer_layers_" + verifierSuffix).c_str(), "Test MAX_FRAMEBUFFER_LAYERS",
        GL_MAX_FRAMEBUFFER_LAYERS, 256, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "fragment_interpolation_offset_bits_" + verifierSuffix).c_str(),
        "Test FRAGMENT_INTERPOLATION_OFFSET_BITS", GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, 4, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_texture_buffer_size_" + verifierSuffix).c_str(),
        "Test MAX_TEXTURE_BUFFER_SIZE", GL_MAX_TEXTURE_BUFFER_SIZE, 65536, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new AlignmentCase(m_context,
                                        (std::string() + "texture_buffer_offset_alignment_" + verifierSuffix).c_str(),
                                        "Test TEXTURE_BUFFER_OFFSET_ALIGNMENT", GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, 256,
                                        verifier, glu::ApiType::es(3, 2)))

    FOR_EACH_VERIFIER(new MinimumValueCase(m_context, (std::string() + "max_tess_gen_level_" + verifierSuffix).c_str(),
                                           "Test MAX_TESS_GEN_LEVEL", GL_MAX_TESS_GEN_LEVEL, 64, verifier,
                                           glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(m_context, (std::string() + "max_patch_vertices_" + verifierSuffix).c_str(),
                                           "Test MAX_PATCH_VERTICES", GL_MAX_PATCH_VERTICES, 32, verifier,
                                           glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_patch_components_" + verifierSuffix).c_str(),
        "Test MAX_TESS_PATCH_COMPONENTS", GL_MAX_TESS_PATCH_COMPONENTS, 120, verifier, glu::ApiType::es(3, 2)))

    // tess control
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_control_uniform_components_" + verifierSuffix).c_str(),
        "Test MAX_TESS_CONTROL_UNIFORM_COMPONENTS", GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS, 1024, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_control_texture_image_units_" + verifierSuffix).c_str(),
        "Test MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS", GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS, 16, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_control_output_components_" + verifierSuffix).c_str(),
        "Test MAX_TESS_CONTROL_OUTPUT_COMPONENTS", GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS, 64, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_control_total_output_components_" + verifierSuffix).c_str(),
        "Test MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS", GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS, 2048, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_tess_control_input_components_" + verifierSuffix).c_str(),
                             "Test MAX_TESS_CONTROL_INPUT_COMPONENTS", GL_MAX_TESS_CONTROL_INPUT_COMPONENTS, 64,
                             verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_tess_control_uniform_blocks_" + verifierSuffix).c_str(),
                             "Test MAX_TESS_CONTROL_UNIFORM_BLOCKS", GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, 12, verifier,
                             glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_control_atomic_counter_buffers_" + verifierSuffix).c_str(),
        "Test MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS", GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, 0, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_tess_control_atomic_counters_" + verifierSuffix).c_str(),
                             "Test MAX_TESS_CONTROL_ATOMIC_COUNTERS", GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, 0, verifier,
                             glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_control_shader_storage_blocks_" + verifierSuffix).c_str(),
        "Test MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS", GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, 0, verifier,
        glu::ApiType::es(3, 2)))

    // tess evaluation
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_uniform_components_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_UNIFORM_COMPONENTS", GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS, 1024, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_texture_image_units_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS", GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, 16, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_output_components_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_OUTPUT_COMPONENTS", GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS, 64, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_input_components_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_INPUT_COMPONENTS", GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS, 64, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_uniform_blocks_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_UNIFORM_BLOCKS", GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, 12, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_atomic_counter_buffers_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS", GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, 0, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_atomic_counters_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_ATOMIC_COUNTERS", GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, 0, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_shader_storage_blocks_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS", GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, 0, verifier,
        glu::ApiType::es(3, 2)))

    // geometry
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_geometry_uniform_components_" + verifierSuffix).c_str(),
                             "Test MAX_GEOMETRY_UNIFORM_COMPONENTS", GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, 1024, verifier,
                             glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_uniform_blocks_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_UNIFORM_BLOCKS", GL_MAX_GEOMETRY_UNIFORM_BLOCKS, 12, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_input_components_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_INPUT_COMPONENTS", GL_MAX_GEOMETRY_INPUT_COMPONENTS, 64, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_output_components_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_OUTPUT_COMPONENTS", GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, 64, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_output_vertices_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_OUTPUT_VERTICES", GL_MAX_GEOMETRY_OUTPUT_VERTICES, 256, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_total_output_components_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS", GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, 1024, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_geometry_texture_image_units_" + verifierSuffix).c_str(),
                             "Test MAX_GEOMETRY_TEXTURE_IMAGE_UNITS", GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, 16, verifier,
                             glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_geometry_shader_invocations_" + verifierSuffix).c_str(),
                             "Test MAX_GEOMETRY_SHADER_INVOCATIONS", GL_MAX_GEOMETRY_SHADER_INVOCATIONS, 32, verifier,
                             glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_atomic_counter_buffers_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS", GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, 0, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_atomic_counters_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_ATOMIC_COUNTERS", GL_MAX_GEOMETRY_ATOMIC_COUNTERS, 0, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_shader_storage_blocks_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_SHADER_STORAGE_BLOCKS", GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, 0, verifier,
        glu::ApiType::es(3, 2)))

    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "max_tess_control_image_uniforms_" + verifierSuffix).c_str(),
                             "Test MAX_TESS_CONTROL_IMAGE_UNIFORMS", GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, 0, verifier,
                             glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_tess_evaluation_image_uniforms_" + verifierSuffix).c_str(),
        "Test MAX_TESS_EVALUATION_IMAGE_UNIFORMS", GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, 0, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_geometry_image_uniforms_" + verifierSuffix).c_str(),
        "Test MAX_GEOMETRY_IMAGE_UNIFORMS", GL_MAX_GEOMETRY_IMAGE_UNIFORMS, 0, verifier, glu::ApiType::es(3, 2)))

    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "debug_logged_messages_" + verifierSuffix).c_str(), "Test DEBUG_LOGGED_MESSAGES",
        GL_DEBUG_LOGGED_MESSAGES, 0, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(
        new MinimumValueCase(m_context, (std::string() + "debug_next_logged_message_length_" + verifierSuffix).c_str(),
                             "Test DEBUG_NEXT_LOGGED_MESSAGE_LENGTH", GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, 0, verifier,
                             glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "debug_group_stack_depth_" + verifierSuffix).c_str(),
        "Test DEBUG_GROUP_STACK_DEPTH", GL_DEBUG_GROUP_STACK_DEPTH, 0, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_debug_message_length_" + verifierSuffix).c_str(),
        "Test MAX_DEBUG_MESSAGE_LENGTH", GL_MAX_DEBUG_MESSAGE_LENGTH, 1, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_debug_logged_messages_" + verifierSuffix).c_str(),
        "Test MAX_DEBUG_LOGGED_MESSAGES", GL_MAX_DEBUG_LOGGED_MESSAGES, 1, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "max_debug_group_stack_depth_" + verifierSuffix).c_str(),
        "Test MAX_DEBUG_GROUP_STACK_DEPTH", GL_MAX_DEBUG_GROUP_STACK_DEPTH, 64, verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new MinimumValueCase(m_context, (std::string() + "max_label_length_" + verifierSuffix).c_str(),
                                           "Test MAX_LABEL_LENGTH", GL_MAX_LABEL_LENGTH, 256, verifier,
                                           glu::ApiType::es(3, 2)))

    FOR_EACH_VERIFIER(new MinimumValueCase(
        m_context, (std::string() + "texture_buffer_binding_" + verifierSuffix).c_str(), "Test TEXTURE_BUFFER_BINDING",
        GL_TEXTURE_BUFFER_BINDING, 0, verifier, glu::ApiType::es(3, 2)))

    FOR_EACH_VERIFIER(new CombinedUniformComponentsCase(
        m_context, (std::string() + "max_combined_tess_control_uniform_components_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS", GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS, verifier,
        glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new CombinedUniformComponentsCase(
        m_context, (std::string() + "max_combined_tess_evaluation_uniform_components_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS", GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS,
        verifier, glu::ApiType::es(3, 2)))
    FOR_EACH_VERIFIER(new CombinedUniformComponentsCase(
        m_context, (std::string() + "max_combined_geometry_uniform_components_" + verifierSuffix).c_str(),
        "Test MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS", GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, verifier,
        glu::ApiType::es(3, 2)))

#undef FOR_EACH_VERIFIER
}

} // namespace Functional
} // namespace gles31
} // namespace deqp
