Add CTS_ARB_indirect_parameters implementation

This is CTS_ARB_indirect_parameters tests implementation

Affects:

GL45-CTS.indirect_parameters_tests.*

Components: OpenGL, Framework

VK-GL-CTS issue: 194

Change-Id: Ibddff6daf485a9d673cf1b09554c01b8b83958e1
diff --git a/external/openglcts/modules/gl/CMakeLists.txt b/external/openglcts/modules/gl/CMakeLists.txt
index ca93752..a606bc2 100644
--- a/external/openglcts/modules/gl/CMakeLists.txt
+++ b/external/openglcts/modules/gl/CMakeLists.txt
@@ -112,6 +112,8 @@
 	gl4cParallelShaderCompileTests.hpp
 	gl4cPostDepthCoverageTests.cpp
 	gl4cPostDepthCoverageTests.hpp
+	gl4cIndirectParametersTests.cpp
+	gl4cIndirectParametersTests.hpp
 	)
 
 set(GLCTS_GL_LIBS
diff --git a/external/openglcts/modules/gl/gl4cIndirectParametersTests.cpp b/external/openglcts/modules/gl/gl4cIndirectParametersTests.cpp
new file mode 100644
index 0000000..dfb39bf
--- /dev/null
+++ b/external/openglcts/modules/gl/gl4cIndirectParametersTests.cpp
@@ -0,0 +1,703 @@
+/*-------------------------------------------------------------------------
+ * 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  gl4cIndirectParametersTests.cpp
+ * \brief Conformance tests for the GL_ARB_indirect_parameters functionality.
+ */ /*-------------------------------------------------------------------*/
+
+#include "gl4cIndirectParametersTests.hpp"
+#include "gluContextInfo.hpp"
+#include "gluDefs.hpp"
+#include "gluDrawUtil.hpp"
+#include "gluShaderProgram.hpp"
+#include "glwEnums.hpp"
+#include "glwFunctions.hpp"
+#include "tcuRenderTarget.hpp"
+#include "tcuTestLog.hpp"
+
+using namespace glw;
+using namespace glu;
+
+namespace gl4cts
+{
+
+static const char* c_vertShader = "#version 430\n"
+								  "\n"
+								  "in vec3 vertex;\n"
+								  "\n"
+								  "void main()\n"
+								  "{\n"
+								  "    gl_Position = vec4(vertex, 1);\n"
+								  "}\n";
+
+static const char* c_fragShader = "#version 430\n"
+								  "\n"
+								  "out vec4 fragColor;\n"
+								  "\n"
+								  "void main()\n"
+								  "{\n"
+								  "    fragColor = vec4(1, 1, 1, 0.5);\n"
+								  "}\n";
+
+/** Constructor.
+ *
+ *  @param context     Rendering context
+ */
+ParameterBufferOperationsCase::ParameterBufferOperationsCase(deqp::Context& context)
+	: TestCase(context, "ParameterBufferOperations",
+			   "Verifies if operations on new buffer object PARAMETER_BUFFER_ARB works as expected.")
+{
+	/* Left blank intentionally */
+}
+
+/** Stub init method */
+void ParameterBufferOperationsCase::init()
+{
+}
+
+/** Executes test iteration.
+ *
+ *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
+ */
+tcu::TestNode::IterateResult ParameterBufferOperationsCase::iterate()
+{
+	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_indirect_parameters"))
+	{
+		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
+		return STOP;
+	}
+
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	GLuint paramBuffer;
+
+	GLint data[]	= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+	GLint subData[] = { 10, 11, 12, 13, 14 };
+	GLint expData[] = { 0, 1, 10, 11, 12, 13, 14, 7, 8, 9 };
+
+	bool result = true;
+
+	// Test buffer generating and binding
+	gl.genBuffers(1, &paramBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+	gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, paramBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	GLint paramBinding;
+	gl.getIntegerv(GL_PARAMETER_BUFFER_BINDING_ARB, &paramBinding);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
+
+	if ((GLuint)paramBinding != paramBuffer)
+	{
+		result = false;
+		m_testCtx.getLog() << tcu::TestLog::Message << "Buffer binding mismatch" << tcu::TestLog::EndMessage;
+	}
+	else
+	{
+		// Test filling buffer with data
+		gl.bufferData(GL_PARAMETER_BUFFER_ARB, 10 * sizeof(GLint), data, GL_DYNAMIC_DRAW);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+		gl.bufferSubData(GL_PARAMETER_BUFFER_ARB, 2 * sizeof(GLint), 5 * sizeof(GLint), subData);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+		// Test buffer mapping
+		GLvoid* buffer = gl.mapBuffer(GL_PARAMETER_BUFFER_ARB, GL_READ_ONLY);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer");
+
+		if (memcmp(buffer, expData, 10 * sizeof(GLint)) != 0)
+		{
+			result = false;
+			m_testCtx.getLog() << tcu::TestLog::Message << "Buffer data mismatch" << tcu::TestLog::EndMessage;
+		}
+		else
+		{
+			GLvoid* bufferPointer;
+			gl.getBufferPointerv(GL_PARAMETER_BUFFER_ARB, GL_BUFFER_MAP_POINTER, &bufferPointer);
+			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBufferPointerv");
+
+			if (buffer != bufferPointer)
+			{
+				result = false;
+				m_testCtx.getLog() << tcu::TestLog::Message << "Buffer pointer mismatch" << tcu::TestLog::EndMessage;
+			}
+			else
+			{
+				GLint bufferSize;
+				GLint bufferUsage;
+				gl.getBufferParameteriv(GL_PARAMETER_BUFFER_ARB, GL_BUFFER_SIZE, &bufferSize);
+				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBufferParameteriv");
+				gl.getBufferParameteriv(GL_PARAMETER_BUFFER_ARB, GL_BUFFER_USAGE, &bufferUsage);
+				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBufferParameteriv");
+
+				if (bufferSize != 10 * sizeof(GLint))
+				{
+					result = false;
+					m_testCtx.getLog() << tcu::TestLog::Message << "Buffer size mismatch" << tcu::TestLog::EndMessage;
+				}
+				else if (bufferUsage != GL_DYNAMIC_DRAW)
+				{
+					result = false;
+					m_testCtx.getLog() << tcu::TestLog::Message << "Buffer usage mismatch" << tcu::TestLog::EndMessage;
+				}
+			}
+		}
+
+		gl.unmapBuffer(GL_PARAMETER_BUFFER_ARB);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer");
+
+		// Test buffer ranged mapping
+		buffer =
+			gl.mapBufferRange(GL_PARAMETER_BUFFER_ARB, 0, sizeof(GLint), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange");
+
+		// Test buffer flushing
+		GLint* bufferInt = (GLint*)buffer;
+
+		bufferInt[0] = 100;
+		gl.flushMappedBufferRange(GL_PARAMETER_BUFFER_ARB, 0, sizeof(GLint));
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glFlushMappedBufferRange");
+
+		gl.unmapBuffer(GL_PARAMETER_BUFFER_ARB);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer");
+
+		// Test buffers data copying
+		GLuint arrayBuffer;
+		gl.genBuffers(1, &arrayBuffer);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+		gl.bindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+		gl.bufferData(GL_ARRAY_BUFFER, 10 * sizeof(GLint), data, GL_DYNAMIC_DRAW);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+		gl.copyBufferSubData(GL_PARAMETER_BUFFER_ARB, GL_ARRAY_BUFFER, 0, 0, sizeof(GLint));
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glCopyBufferSubData");
+
+		gl.mapBufferRange(GL_ARRAY_BUFFER, 0, 1, GL_MAP_READ_BIT);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange");
+
+		bufferInt = (GLint*)buffer;
+		if (bufferInt[0] != 100)
+		{
+			result = false;
+			m_testCtx.getLog() << tcu::TestLog::Message << "Buffer copy operation failed" << tcu::TestLog::EndMessage;
+		}
+
+		gl.unmapBuffer(GL_ARRAY_BUFFER);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer");
+
+		// Release array buffer
+		gl.deleteBuffers(1, &arrayBuffer);
+		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers");
+	}
+
+	// Release parameter buffer
+	gl.deleteBuffers(1, &paramBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers");
+
+	if (result)
+		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+	else
+		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+
+	return STOP;
+}
+
+/** Constructor.
+ *
+ *  @param context     Rendering context
+ */
+VertexArrayIndirectDrawingBaseCase::VertexArrayIndirectDrawingBaseCase(deqp::Context& context, const char* name,
+																	   const char* description)
+	: TestCase(context, name, description)
+{
+	/* Left blank intentionally */
+}
+
+/** Executes test iteration.
+ *
+ *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
+ */
+tcu::TestNode::IterateResult VertexArrayIndirectDrawingBaseCase::iterate()
+{
+	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_indirect_parameters"))
+	{
+		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
+		return STOP;
+	}
+
+	if (draw() && verify())
+		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+	else
+		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+
+	return STOP;
+}
+
+/** This method verifies if drawn quads are as expected.
+ *
+ *  @return Returns true if quads are drawn properly, false otherwise.
+ */
+bool VertexArrayIndirectDrawingBaseCase::verify()
+{
+	const Functions&		 gl = m_context.getRenderContext().getFunctions();
+	const tcu::RenderTarget& rt = m_context.getRenderContext().getRenderTarget();
+
+	const int width  = rt.getWidth();
+	const int height = rt.getHeight();
+
+	std::vector<GLubyte> pixels;
+	pixels.resize(width * height);
+
+	gl.readPixels(0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, pixels.data());
+
+	//Verify first quad
+	for (int y = 2; y < height - 2; ++y)
+	{
+		for (int x = 2; x < width / 2 - 2; ++x)
+		{
+			GLubyte value = pixels[x + y * width];
+			if (value < 190 || value > 194)
+			{
+				m_testCtx.getLog() << tcu::TestLog::Message << "First quad verification failed. "
+								   << "Wrong value read from framebuffer at " << x << "/" << y << " value: " << value
+								   << ", expected: <190-194>" << tcu::TestLog::EndMessage;
+				return false;
+			}
+		}
+	}
+
+	//Verify second quad
+	for (int y = 2; y < height - 2; ++y)
+	{
+		for (int x = width / 2 + 2; x < width - 2; ++x)
+		{
+			GLubyte value = pixels[x + y * width];
+			if (value < 126 || value > 130)
+			{
+				m_testCtx.getLog() << tcu::TestLog::Message << "Second quad verification failed. "
+								   << "Wrong value read from framebuffer at " << x << "/" << y << " value: " << value
+								   << ", expected: <126-130>" << tcu::TestLog::EndMessage;
+				return false;
+			}
+		}
+	}
+
+	return verifyErrors();
+}
+
+/** Constructor.
+ *
+ *  @param context     Rendering context
+ */
+MultiDrawArraysIndirectCountCase::MultiDrawArraysIndirectCountCase(deqp::Context& context)
+	: VertexArrayIndirectDrawingBaseCase(context, "MultiDrawArraysIndirectCount",
+										 "Test verifies if MultiDrawArraysIndirectCountARB function works as expected.")
+	, m_vao(0)
+	, m_arrayBuffer(0)
+	, m_drawIndirectBuffer(0)
+	, m_parameterBuffer(0)
+{
+	/* Left blank intentionally */
+}
+
+/** Stub init method */
+void MultiDrawArraysIndirectCountCase::init()
+{
+	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_indirect_parameters"))
+		return;
+
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, -1.0f, 1.0f,  0.0f, 0.0f, -1.0f, 0.0f,
+								 0.0f,  1.0f,  0.0f, 1.0f,  -1.0f, 0.0f, 1.0f, 1.0f,  0.0f };
+
+	const DrawArraysIndirectCommand indirect[] = {
+		{ 4, 2, 0, 0 }, //4 vertices, 2 instanceCount, 0 first, 0 baseInstance
+		{ 4, 1, 2, 0 }  //4 vertices, 1 instanceCount, 2 first, 0 baseInstance
+	};
+
+	const GLushort parameters[] = { 2, 1 };
+
+	// Generate vertex array object
+	gl.genVertexArrays(1, &m_vao);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays");
+
+	gl.bindVertexArray(m_vao);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray");
+
+	// Setup vertex array buffer
+	gl.genBuffers(1, &m_arrayBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+	gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	gl.bufferData(GL_ARRAY_BUFFER, 24 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+	// Setup indirect command buffer
+	gl.genBuffers(1, &m_drawIndirectBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+	gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_drawIndirectBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	gl.bufferData(GL_DRAW_INDIRECT_BUFFER, 2 * sizeof(DrawArraysIndirectCommand), indirect, GL_STATIC_DRAW);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+	// Setup parameter buffer
+	gl.genBuffers(1, &m_parameterBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+	gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, m_parameterBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	gl.bufferData(GL_PARAMETER_BUFFER_ARB, 100 * sizeof(GLushort), parameters, GL_STATIC_DRAW);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+}
+
+/** Stub deinit method */
+void MultiDrawArraysIndirectCountCase::deinit()
+{
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	if (m_vao)
+		gl.deleteVertexArrays(1, &m_vao);
+	if (m_arrayBuffer)
+		gl.deleteBuffers(1, &m_arrayBuffer);
+	if (m_drawIndirectBuffer)
+		gl.deleteBuffers(1, &m_drawIndirectBuffer);
+	if (m_parameterBuffer)
+		gl.deleteBuffers(1, &m_parameterBuffer);
+}
+
+/** Drawing quads method using drawArrays.
+ */
+bool MultiDrawArraysIndirectCountCase::draw()
+{
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	ProgramSources sources = makeVtxFragSources(c_vertShader, c_fragShader);
+	ShaderProgram  program(gl, sources);
+
+	if (!program.isOk())
+	{
+		m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n"
+						   << "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
+						   << "Fragment: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
+						   << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
+		return false;
+	}
+
+	gl.useProgram(program.getProgram());
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
+
+	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
+	gl.clear(GL_COLOR_BUFFER_BIT);
+
+	gl.enable(GL_BLEND);
+	gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	gl.enableVertexAttribArray(0);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray");
+	gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer");
+
+	gl.multiDrawArraysIndirectCountARB(GL_TRIANGLE_STRIP, 0, 0, 2, 0);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glMultiDrawArraysIndirectCountARB");
+
+	gl.disableVertexAttribArray(0);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray");
+
+	gl.disable(GL_BLEND);
+
+	return true;
+}
+
+/** Verify MultiDrawArrayIndirectCountARB errors
+ */
+bool MultiDrawArraysIndirectCountCase::verifyErrors()
+{
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	GLint errorCode;
+
+	bool result = true;
+
+	// INVALID_VALUE - drawcount offset not multiple of 4
+	gl.multiDrawArraysIndirectCountARB(GL_TRIANGLE_STRIP, 0, 2, 1, 0);
+	errorCode = gl.getError();
+	if (errorCode != GL_INVALID_VALUE)
+	{
+		m_testCtx.getLog() << tcu::TestLog::Message
+						   << "MultiDrawArraysIndirectCount error verifying failed (1). Expected code: "
+						   << GL_INVALID_VALUE << ", current code: " << errorCode << tcu::TestLog::EndMessage;
+		result = false;
+	}
+
+	// INVALID_OPERATION - maxdrawcount greater then parameter buffer size
+	gl.multiDrawArraysIndirectCountARB(GL_TRIANGLE_STRIP, 0, 0, 4, 0);
+	errorCode = gl.getError();
+	if (errorCode != GL_INVALID_OPERATION)
+	{
+		m_testCtx.getLog() << tcu::TestLog::Message
+						   << "MultiDrawArraysIndirectCount error verifying failed (2). Expected code: "
+						   << GL_INVALID_OPERATION << ", current code: " << errorCode << tcu::TestLog::EndMessage;
+		result = false;
+	}
+
+	gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, 0);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	// INVALID_OPERATION - GL_PARAMETER_BUFFER_ARB not bound
+	gl.multiDrawArraysIndirectCountARB(GL_TRIANGLE_STRIP, 0, 0, 2, 0);
+	errorCode = gl.getError();
+	if (errorCode != GL_INVALID_OPERATION)
+	{
+		m_testCtx.getLog() << tcu::TestLog::Message
+						   << "MultiDrawArraysIndirectCount error verifying failed (3). Expected code: "
+						   << GL_INVALID_OPERATION << ", current code: " << errorCode << tcu::TestLog::EndMessage;
+		result = false;
+	}
+
+	return result;
+}
+
+/** Constructor.
+ *
+ *  @param context     Rendering context
+ */
+MultiDrawElementsIndirectCountCase::MultiDrawElementsIndirectCountCase(deqp::Context& context)
+	: VertexArrayIndirectDrawingBaseCase(
+		  context, "MultiDrawElementsIndirectCount",
+		  "Test verifies if MultiDrawElementsIndirectCountARB function works as expected.")
+	, m_vao(0)
+	, m_arrayBuffer(0)
+	, m_drawIndirectBuffer(0)
+	, m_parameterBuffer(0)
+{
+	/* Left blank intentionally */
+}
+
+/** Stub init method */
+void MultiDrawElementsIndirectCountCase::init()
+{
+	if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_indirect_parameters"))
+		return;
+
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, -1.0f, 1.0f,  0.0f, 0.0f, -1.0f, 0.0f,
+								 0.0f,  1.0f,  0.0f, 1.0f,  -1.0f, 0.0f, 1.0f, 1.0f,  0.0f };
+
+	const GLushort elements[] = { 0, 1, 2, 3, 4, 5 };
+
+	const DrawElementsIndirectCommand indirect[] = {
+		{ 4, 2, 0, 0, 0 }, //4 indices, 2 instanceCount, 0 firstIndex, 0 baseVertex, 0 baseInstance
+		{ 4, 1, 2, 0, 0 }  //4 indices, 1 instanceCount, 2 firstIndex, 0 baseVertex, 0 baseInstance
+	};
+
+	const GLushort parameters[] = { 2, 1 };
+
+	// Generate vertex array object
+	gl.genVertexArrays(1, &m_vao);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays");
+
+	gl.bindVertexArray(m_vao);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray");
+
+	// Setup vertex array buffer
+	gl.genBuffers(1, &m_arrayBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+	gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	gl.bufferData(GL_ARRAY_BUFFER, 24 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+	// Setup element array buffer
+	gl.genBuffers(1, &m_elementBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLushort), elements, GL_STATIC_DRAW);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+	// Setup indirect command buffer
+	gl.genBuffers(1, &m_drawIndirectBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+	gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_drawIndirectBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	gl.bufferData(GL_DRAW_INDIRECT_BUFFER, 3 * sizeof(DrawElementsIndirectCommand), indirect, GL_STATIC_DRAW);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+
+	// Setup parameters Re: buffer
+	gl.genBuffers(1, &m_parameterBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
+
+	gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, m_parameterBuffer);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	gl.bufferData(GL_PARAMETER_BUFFER_ARB, 2 * sizeof(GLushort), parameters, GL_STATIC_DRAW);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
+}
+
+/** Stub deinit method */
+void MultiDrawElementsIndirectCountCase::deinit()
+{
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	if (m_vao)
+		gl.deleteVertexArrays(1, &m_vao);
+	if (m_arrayBuffer)
+		gl.deleteBuffers(1, &m_arrayBuffer);
+	if (m_elementBuffer)
+		gl.deleteBuffers(1, &m_elementBuffer);
+	if (m_drawIndirectBuffer)
+		gl.deleteBuffers(1, &m_drawIndirectBuffer);
+	if (m_parameterBuffer)
+		gl.deleteBuffers(1, &m_parameterBuffer);
+}
+
+/** Drawing quads method using drawArrays.
+ */
+bool MultiDrawElementsIndirectCountCase::draw()
+{
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	ProgramSources sources = makeVtxFragSources(c_vertShader, c_fragShader);
+	ShaderProgram  program(gl, sources);
+
+	if (!program.isOk())
+	{
+		m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n"
+						   << "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
+						   << "Fragment: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
+						   << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
+		return false;
+	}
+
+	gl.useProgram(program.getProgram());
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
+
+	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
+	gl.clear(GL_COLOR_BUFFER_BIT);
+
+	gl.enable(GL_BLEND);
+	gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	gl.enableVertexAttribArray(0);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray");
+	gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer");
+
+	gl.multiDrawElementsIndirectCountARB(GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT, 0, 0, 2, 0);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glMultiDrawElementsIndirectCountARB");
+
+	gl.disableVertexAttribArray(0);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray");
+
+	gl.disable(GL_BLEND);
+
+	return true;
+}
+
+/** Verify MultiDrawElementsIndirectCountARB errors
+ */
+bool MultiDrawElementsIndirectCountCase::verifyErrors()
+{
+	const Functions& gl = m_context.getRenderContext().getFunctions();
+
+	GLint errorCode;
+
+	bool result = true;
+
+	// INVALID_VALUE - drawcount offset not multiple of 4
+	gl.multiDrawElementsIndirectCountARB(GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE, 0, 2, 1, 0);
+	errorCode = gl.getError();
+	if (errorCode != GL_INVALID_VALUE)
+	{
+		m_testCtx.getLog() << tcu::TestLog::Message
+						   << "MultiDrawElementIndirectCount error verifying failed (1). Expected code: "
+						   << GL_INVALID_VALUE << ", current code: " << errorCode << tcu::TestLog::EndMessage;
+		result = false;
+	}
+
+	// INVALID_OPERATION - maxdrawcount greater then parameter buffer size
+	gl.multiDrawElementsIndirectCountARB(GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE, 0, 0, 4, 0);
+	errorCode = gl.getError();
+	if (errorCode != GL_INVALID_OPERATION)
+	{
+		m_testCtx.getLog() << tcu::TestLog::Message
+						   << "MultiDrawElementIndirectCount error verifying failed (2). Expected code: "
+						   << GL_INVALID_OPERATION << ", current code: " << errorCode << tcu::TestLog::EndMessage;
+		result = false;
+	}
+
+	gl.bindBuffer(GL_PARAMETER_BUFFER_ARB, 0);
+	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
+
+	// INVALID_OPERATION - GL_PARAMETER_BUFFER_ARB not bound
+	gl.multiDrawElementsIndirectCountARB(GL_TRIANGLE_STRIP, GL_UNSIGNED_BYTE, 0, 0, 3, 0);
+	errorCode = gl.getError();
+	if (errorCode != GL_INVALID_OPERATION)
+	{
+		m_testCtx.getLog() << tcu::TestLog::Message
+						   << "MultiDrawElementIndirectCount error verifying failed (3). Expected code: "
+						   << GL_INVALID_OPERATION << ", current code: " << errorCode << tcu::TestLog::EndMessage;
+		result = false;
+	}
+
+	return result;
+}
+
+/** Constructor.
+ *
+ *  @param context Rendering context.
+ */
+IndirectParametersTests::IndirectParametersTests(deqp::Context& context)
+	: TestCaseGroup(context, "indirect_parameters_tests",
+					"Verify conformance of CTS_ARB_indirect_parameters implementation")
+{
+}
+
+/** Initializes the test group contents. */
+void IndirectParametersTests::init()
+{
+	addChild(new ParameterBufferOperationsCase(m_context));
+	addChild(new MultiDrawArraysIndirectCountCase(m_context));
+	addChild(new MultiDrawElementsIndirectCountCase(m_context));
+}
+
+} /* gl4cts namespace */
diff --git a/external/openglcts/modules/gl/gl4cIndirectParametersTests.hpp b/external/openglcts/modules/gl/gl4cIndirectParametersTests.hpp
new file mode 100644
index 0000000..09728db
--- /dev/null
+++ b/external/openglcts/modules/gl/gl4cIndirectParametersTests.hpp
@@ -0,0 +1,157 @@
+#ifndef _GL4CINDIRECTPARAMETERSTESTS_HPP
+#define _GL4CINDIRECTPARAMETERSTESTS_HPP
+/*-------------------------------------------------------------------------
+ * 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  gl4cIndirectParametersTests.hpp
+ * \brief Conformance tests for the GL_ARB_indirect_parameters functionality.
+ */ /*-------------------------------------------------------------------*/
+
+#include "glcTestCase.hpp"
+#include "glwDefs.hpp"
+#include "tcuDefs.hpp"
+
+using namespace glw;
+using namespace glu;
+
+namespace gl4cts
+{
+
+typedef struct
+{
+	GLuint count;
+	GLuint instanceCount;
+	GLuint first;
+	GLuint baseInstance;
+} DrawArraysIndirectCommand;
+
+typedef struct
+{
+	GLuint count;
+	GLuint instanceCount;
+	GLuint firstIndex;
+	GLuint baseVertex;
+	GLuint baseInstance;
+} DrawElementsIndirectCommand;
+
+/** Test verifies if operations on new buffer object PARAMETER_BUFFER_ARB works as expected.
+ **/
+class ParameterBufferOperationsCase : public deqp::TestCase
+{
+public:
+	/* Public methods */
+	ParameterBufferOperationsCase(deqp::Context& context);
+
+	virtual void						 init();
+	virtual tcu::TestNode::IterateResult iterate();
+
+private:
+	/* Private methods */
+	/* Private members */
+};
+
+/** Base class for specific vertex array indirect drawing classes.
+ **/
+class VertexArrayIndirectDrawingBaseCase : public deqp::TestCase
+{
+public:
+	/* Public methods */
+	VertexArrayIndirectDrawingBaseCase(deqp::Context& context, const char* name, const char* description);
+
+	virtual void						 init()   = DE_NULL;
+	virtual void						 deinit() = DE_NULL;
+	virtual tcu::TestNode::IterateResult iterate();
+
+protected:
+	/* Protected methods */
+	virtual bool draw() = DE_NULL;
+	virtual bool verify();
+	virtual bool verifyErrors() = DE_NULL;
+};
+
+/** Test verifies if MultiDrawArraysIndirectCountARB function works properly.
+ **/
+class MultiDrawArraysIndirectCountCase : public VertexArrayIndirectDrawingBaseCase
+{
+public:
+	/* Public methods */
+	MultiDrawArraysIndirectCountCase(deqp::Context& context);
+
+	virtual void init();
+	virtual void deinit();
+
+protected:
+	/* Protected methods */
+	virtual bool draw();
+	virtual bool verifyErrors();
+
+	/* Protected methods */
+	GLuint m_vao;
+	GLuint m_arrayBuffer;
+	GLuint m_drawIndirectBuffer;
+	GLuint m_parameterBuffer;
+};
+
+/** Test verifies if MultiDrawArraysIndirectCountARB function works properly.
+ **/
+class MultiDrawElementsIndirectCountCase : public VertexArrayIndirectDrawingBaseCase
+{
+public:
+	/* Public methods */
+	MultiDrawElementsIndirectCountCase(deqp::Context& context);
+
+	virtual void init();
+	virtual void deinit();
+
+protected:
+	/* Protected methods */
+	virtual bool draw();
+	virtual bool verifyErrors();
+
+	/* Protected methods */
+	GLuint m_vao;
+	GLuint m_arrayBuffer;
+	GLuint m_elementBuffer;
+	GLuint m_drawIndirectBuffer;
+	GLuint m_parameterBuffer;
+};
+
+/** Test group which encapsulates all sparse buffer conformance tests */
+class IndirectParametersTests : public deqp::TestCaseGroup
+{
+public:
+	/* Public methods */
+	IndirectParametersTests(deqp::Context& context);
+
+	void init();
+
+private:
+	IndirectParametersTests(const IndirectParametersTests& other);
+	IndirectParametersTests& operator=(const IndirectParametersTests& other);
+};
+
+} /* glcts namespace */
+
+#endif // _GL4CINDIRECTPARAMETERSTESTS_HPP
diff --git a/external/openglcts/modules/gl/gl4cTestPackages.cpp b/external/openglcts/modules/gl/gl4cTestPackages.cpp
index e59b552..9166d86 100644
--- a/external/openglcts/modules/gl/gl4cTestPackages.cpp
+++ b/external/openglcts/modules/gl/gl4cTestPackages.cpp
@@ -36,6 +36,7 @@
 #include "gl4cGPUShaderFP64Tests.hpp"
 #include "gl4cGetTextureSubImageTests.hpp"
 #include "gl4cIncompleteTextureAccessTests.hpp"
+#include "gl4cIndirectParametersTests.hpp"
 #include "gl4cKHRDebugTests.hpp"
 #include "gl4cMapBufferAlignmentTests.hpp"
 #include "gl4cMultiBindTests.hpp"
@@ -228,6 +229,7 @@
 		addChild(new gl4cts::StencilTexturingTests(getContext()));
 		addChild(new gl4cts::SparseBufferTests(getContext()));
 		addChild(new gl4cts::SparseTextureTests(getContext()));
+		addChild(new gl4cts::IndirectParametersTests(getContext()));
 	}
 	catch (...)
 	{
diff --git a/framework/opengl/gluCallLogWrapper.inl b/framework/opengl/gluCallLogWrapper.inl
index 814f980..7e3d23c 100644
--- a/framework/opengl/gluCallLogWrapper.inl
+++ b/framework/opengl/gluCallLogWrapper.inl
@@ -3341,6 +3341,13 @@
 	m_gl.multiDrawArraysIndirect(mode, indirect, drawcount, stride);
 }
 
+void CallLogWrapper::glMultiDrawArraysIndirectCountARB (glw::GLenum mode, glw::GLintptr indirect, glw::GLintptr drawcount, glw::GLsizei maxdrawcount, glw::GLsizei stride)
+{
+	if (m_enableLog)
+		m_log << TestLog::Message << "glMultiDrawArraysIndirectCountARB(" << toHex(mode) << ", " << indirect << ", " << drawcount << ", " << maxdrawcount << ", " << stride << ");" << TestLog::EndMessage;
+	m_gl.multiDrawArraysIndirectCountARB(mode, indirect, drawcount, maxdrawcount, stride);
+}
+
 void CallLogWrapper::glMultiDrawElements (glw::GLenum mode, const glw::GLsizei *count, glw::GLenum type, const void *const*indices, glw::GLsizei drawcount)
 {
 	if (m_enableLog)
@@ -3362,6 +3369,13 @@
 	m_gl.multiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
 }
 
+void CallLogWrapper::glMultiDrawElementsIndirectCountARB (glw::GLenum mode, glw::GLenum type, glw::GLintptr indirect, glw::GLintptr drawcount, glw::GLsizei maxdrawcount, glw::GLsizei stride)
+{
+	if (m_enableLog)
+		m_log << TestLog::Message << "glMultiDrawElementsIndirectCountARB(" << toHex(mode) << ", " << toHex(type) << ", " << indirect << ", " << drawcount << ", " << maxdrawcount << ", " << stride << ");" << TestLog::EndMessage;
+	m_gl.multiDrawElementsIndirectCountARB(mode, type, indirect, drawcount, maxdrawcount, stride);
+}
+
 void CallLogWrapper::glMultiTexBufferEXT (glw::GLenum texunit, glw::GLenum target, glw::GLenum internalformat, glw::GLuint buffer)
 {
 	if (m_enableLog)
diff --git a/framework/opengl/gluCallLogWrapperApi.inl b/framework/opengl/gluCallLogWrapperApi.inl
index 9b5a1a0..7d93902 100644
--- a/framework/opengl/gluCallLogWrapperApi.inl
+++ b/framework/opengl/gluCallLogWrapperApi.inl
@@ -447,9 +447,11 @@
 void					glMinSampleShading									(glw::GLfloat value);
 void					glMultiDrawArrays									(glw::GLenum mode, const glw::GLint *first, const glw::GLsizei *count, glw::GLsizei drawcount);
 void					glMultiDrawArraysIndirect							(glw::GLenum mode, const void *indirect, glw::GLsizei drawcount, glw::GLsizei stride);
+void					glMultiDrawArraysIndirectCountARB					(glw::GLenum mode, glw::GLintptr indirect, glw::GLintptr drawcount, glw::GLsizei maxdrawcount, glw::GLsizei stride);
 void					glMultiDrawElements									(glw::GLenum mode, const glw::GLsizei *count, glw::GLenum type, const void *const*indices, glw::GLsizei drawcount);
 void					glMultiDrawElementsBaseVertex						(glw::GLenum mode, const glw::GLsizei *count, glw::GLenum type, const void *const*indices, glw::GLsizei drawcount, const glw::GLint *basevertex);
 void					glMultiDrawElementsIndirect							(glw::GLenum mode, glw::GLenum type, const void *indirect, glw::GLsizei drawcount, glw::GLsizei stride);
+void					glMultiDrawElementsIndirectCountARB					(glw::GLenum mode, glw::GLenum type, glw::GLintptr indirect, glw::GLintptr drawcount, glw::GLsizei maxdrawcount, glw::GLsizei stride);
 void					glMultiTexBufferEXT									(glw::GLenum texunit, glw::GLenum target, glw::GLenum internalformat, glw::GLuint buffer);
 void					glMultiTexCoordPointerEXT							(glw::GLenum texunit, glw::GLint size, glw::GLenum type, glw::GLsizei stride, const void *pointer);
 void					glMultiTexEnvfEXT									(glw::GLenum texunit, glw::GLenum target, glw::GLenum pname, glw::GLfloat param);
diff --git a/framework/opengl/wrapper/glwApi.inl b/framework/opengl/wrapper/glwApi.inl
index 6d8f204..aea410b 100644
--- a/framework/opengl/wrapper/glwApi.inl
+++ b/framework/opengl/wrapper/glwApi.inl
@@ -447,9 +447,11 @@
 #define			glMinSampleShading									glwMinSampleShading
 #define			glMultiDrawArrays									glwMultiDrawArrays
 #define			glMultiDrawArraysIndirect							glwMultiDrawArraysIndirect
+#define			glMultiDrawArraysIndirectCountARB					glwMultiDrawArraysIndirectCountARB
 #define			glMultiDrawElements									glwMultiDrawElements
 #define			glMultiDrawElementsBaseVertex						glwMultiDrawElementsBaseVertex
 #define			glMultiDrawElementsIndirect							glwMultiDrawElementsIndirect
+#define			glMultiDrawElementsIndirectCountARB					glwMultiDrawElementsIndirectCountARB
 #define			glMultiTexBufferEXT									glwMultiTexBufferEXT
 #define			glMultiTexCoordPointerEXT							glwMultiTexCoordPointerEXT
 #define			glMultiTexEnvfEXT									glwMultiTexEnvfEXT
@@ -1284,9 +1286,11 @@
 void			glwMinSampleShading									(GLfloat value);
 void			glwMultiDrawArrays									(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
 void			glwMultiDrawArraysIndirect							(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+void			glwMultiDrawArraysIndirectCountARB					(GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
 void			glwMultiDrawElements								(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
 void			glwMultiDrawElementsBaseVertex						(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
 void			glwMultiDrawElementsIndirect						(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+void			glwMultiDrawElementsIndirectCountARB				(GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
 void			glwMultiTexBufferEXT								(GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);
 void			glwMultiTexCoordPointerEXT							(GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);
 void			glwMultiTexEnvfEXT									(GLenum texunit, GLenum target, GLenum pname, GLfloat param);
diff --git a/framework/opengl/wrapper/glwEnums.inl b/framework/opengl/wrapper/glwEnums.inl
index 7dac350..6048c6b 100644
--- a/framework/opengl/wrapper/glwEnums.inl
+++ b/framework/opengl/wrapper/glwEnums.inl
@@ -357,6 +357,8 @@
 #define GL_BGRA_EXT														0x80E1
 #define GL_MAX_ELEMENTS_VERTICES										0x80E8
 #define GL_MAX_ELEMENTS_INDICES											0x80E9
+#define GL_PARAMETER_BUFFER_ARB											0x80EE
+#define GL_PARAMETER_BUFFER_BINDING_ARB									0x80EF
 #define GL_POINT_FADE_THRESHOLD_SIZE									0x8128
 #define GL_CLAMP_TO_BORDER												0x812D
 #define GL_CLAMP_TO_BORDER_EXT											0x812D
diff --git a/framework/opengl/wrapper/glwFunctionTypes.inl b/framework/opengl/wrapper/glwFunctionTypes.inl
index 5d2c3f4..cf1f98b 100644
--- a/framework/opengl/wrapper/glwFunctionTypes.inl
+++ b/framework/opengl/wrapper/glwFunctionTypes.inl
@@ -447,9 +447,11 @@
 typedef GLW_APICALL void			(GLW_APIENTRY* glMinSampleShadingFunc)									(GLfloat value);
 typedef GLW_APICALL void			(GLW_APIENTRY* glMultiDrawArraysFunc)									(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
 typedef GLW_APICALL void			(GLW_APIENTRY* glMultiDrawArraysIndirectFunc)							(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef GLW_APICALL void			(GLW_APIENTRY* glMultiDrawArraysIndirectCountARBFunc)					(GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
 typedef GLW_APICALL void			(GLW_APIENTRY* glMultiDrawElementsFunc)									(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
 typedef GLW_APICALL void			(GLW_APIENTRY* glMultiDrawElementsBaseVertexFunc)						(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
 typedef GLW_APICALL void			(GLW_APIENTRY* glMultiDrawElementsIndirectFunc)							(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef GLW_APICALL void			(GLW_APIENTRY* glMultiDrawElementsIndirectCountARBFunc)					(GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
 typedef GLW_APICALL void			(GLW_APIENTRY* glMultiTexBufferEXTFunc)									(GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);
 typedef GLW_APICALL void			(GLW_APIENTRY* glMultiTexCoordPointerEXTFunc)							(GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);
 typedef GLW_APICALL void			(GLW_APIENTRY* glMultiTexEnvfEXTFunc)									(GLenum texunit, GLenum target, GLenum pname, GLfloat param);
diff --git a/framework/opengl/wrapper/glwFunctions.inl b/framework/opengl/wrapper/glwFunctions.inl
index 807e17e..68f7df3 100644
--- a/framework/opengl/wrapper/glwFunctions.inl
+++ b/framework/opengl/wrapper/glwFunctions.inl
@@ -447,9 +447,11 @@
 glMinSampleShadingFunc									minSampleShading;
 glMultiDrawArraysFunc									multiDrawArrays;
 glMultiDrawArraysIndirectFunc							multiDrawArraysIndirect;
+glMultiDrawArraysIndirectCountARBFunc					multiDrawArraysIndirectCountARB;
 glMultiDrawElementsFunc									multiDrawElements;
 glMultiDrawElementsBaseVertexFunc						multiDrawElementsBaseVertex;
 glMultiDrawElementsIndirectFunc							multiDrawElementsIndirect;
+glMultiDrawElementsIndirectCountARBFunc					multiDrawElementsIndirectCountARB;
 glMultiTexBufferEXTFunc									multiTexBufferEXT;
 glMultiTexCoordPointerEXTFunc							multiTexCoordPointerEXT;
 glMultiTexEnvfEXTFunc									multiTexEnvfEXT;
diff --git a/framework/opengl/wrapper/glwImpl.inl b/framework/opengl/wrapper/glwImpl.inl
index ab9d124..3f412d8 100644
--- a/framework/opengl/wrapper/glwImpl.inl
+++ b/framework/opengl/wrapper/glwImpl.inl
@@ -3556,6 +3556,14 @@
 	gl->multiDrawArraysIndirect(mode, indirect, drawcount, stride);
 }
 
+void glwMultiDrawArraysIndirectCountARB (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride)
+{
+	const glw::Functions* gl = glw::getCurrentThreadFunctions();
+	if (!gl)
+		return;
+	gl->multiDrawArraysIndirectCountARB(mode, indirect, drawcount, maxdrawcount, stride);
+}
+
 void glwMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount)
 {
 	const glw::Functions* gl = glw::getCurrentThreadFunctions();
@@ -3580,6 +3588,14 @@
 	gl->multiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
 }
 
+void glwMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride)
+{
+	const glw::Functions* gl = glw::getCurrentThreadFunctions();
+	if (!gl)
+		return;
+	gl->multiDrawElementsIndirectCountARB(mode, type, indirect, drawcount, maxdrawcount, stride);
+}
+
 void glwMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer)
 {
 	const glw::Functions* gl = glw::getCurrentThreadFunctions();
diff --git a/framework/opengl/wrapper/glwInitExtGL.inl b/framework/opengl/wrapper/glwInitExtGL.inl
index 74f5226..5462ae9 100644
--- a/framework/opengl/wrapper/glwInitExtGL.inl
+++ b/framework/opengl/wrapper/glwInitExtGL.inl
@@ -695,6 +695,12 @@
 	gl->programParameteri	= (glProgramParameteriFunc)	loader->get("glProgramParameteri");
 }
 
+if (de::contains(extSet, "GL_ARB_indirect_parameters"))
+{
+	gl->multiDrawArraysIndirectCountARB		= (glMultiDrawArraysIndirectCountARBFunc)	loader->get("glMultiDrawArraysIndirectCountARB");
+	gl->multiDrawElementsIndirectCountARB	= (glMultiDrawElementsIndirectCountARBFunc)	loader->get("glMultiDrawElementsIndirectCountARB");
+}
+
 if (de::contains(extSet, "GL_ARB_internalformat_query"))
 {
 	gl->getInternalformativ	= (glGetInternalformativFunc)	loader->get("glGetInternalformativ");
diff --git a/framework/platform/null/tcuNullRenderContextFuncs.inl b/framework/platform/null/tcuNullRenderContextFuncs.inl
index f9b7cb7..cd77ffc 100644
--- a/framework/platform/null/tcuNullRenderContextFuncs.inl
+++ b/framework/platform/null/tcuNullRenderContextFuncs.inl
@@ -3729,6 +3729,16 @@
 
 }
 
+GLW_APICALL void GLW_APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride)
+{
+	DE_UNREF(mode);
+	DE_UNREF(indirect);
+	DE_UNREF(drawcount);
+	DE_UNREF(maxdrawcount);
+	DE_UNREF(stride);
+
+}
+
 GLW_APICALL void GLW_APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount)
 {
 	DE_UNREF(mode);
@@ -3760,6 +3770,17 @@
 
 }
 
+GLW_APICALL void GLW_APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride)
+{
+	DE_UNREF(mode);
+	DE_UNREF(type);
+	DE_UNREF(indirect);
+	DE_UNREF(drawcount);
+	DE_UNREF(maxdrawcount);
+	DE_UNREF(stride);
+
+}
+
 GLW_APICALL void GLW_APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer)
 {
 	DE_UNREF(texunit);
diff --git a/framework/platform/null/tcuNullRenderContextInitFuncs.inl b/framework/platform/null/tcuNullRenderContextInitFuncs.inl
index 9942f05..6eb8e50 100644
--- a/framework/platform/null/tcuNullRenderContextInitFuncs.inl
+++ b/framework/platform/null/tcuNullRenderContextInitFuncs.inl
@@ -447,9 +447,11 @@
 gl->minSampleShading								= glMinSampleShading;
 gl->multiDrawArrays									= glMultiDrawArrays;
 gl->multiDrawArraysIndirect							= glMultiDrawArraysIndirect;
+gl->multiDrawArraysIndirectCountARB					= glMultiDrawArraysIndirectCountARB;
 gl->multiDrawElements								= glMultiDrawElements;
 gl->multiDrawElementsBaseVertex						= glMultiDrawElementsBaseVertex;
 gl->multiDrawElementsIndirect						= glMultiDrawElementsIndirect;
+gl->multiDrawElementsIndirectCountARB				= glMultiDrawElementsIndirectCountARB;
 gl->multiTexBufferEXT								= glMultiTexBufferEXT;
 gl->multiTexCoordPointerEXT							= glMultiTexCoordPointerEXT;
 gl->multiTexEnvfEXT									= glMultiTexEnvfEXT;
diff --git a/scripts/opengl/src_util.py b/scripts/opengl/src_util.py
index 7c8b708..a94445b 100644
--- a/scripts/opengl/src_util.py
+++ b/scripts/opengl/src_util.py
@@ -96,6 +96,7 @@
 	'GL_ARB_draw_elements_base_vertex',
 	'GL_ARB_direct_state_access',
 	'GL_ARB_get_program_binary',
+	'GL_ARB_indirect_parameters',
 	'GL_ARB_internalformat_query',
 	'GL_ARB_instanced_arrays',
 	'GL_ARB_parallel_shader_compile',